mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-11 22:54:34 +00:00
update assimp to 5.2.3 Bugfix-Release
This commit is contained in:
parent
3f796d2a06
commit
f297476092
1150 changed files with 165834 additions and 112019 deletions
265
Engine/lib/assimp/code/PostProcessing/ArmaturePopulate.cpp
Normal file
265
Engine/lib/assimp/code/PostProcessing/ArmaturePopulate.cpp
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#include "ArmaturePopulate.h"
|
||||
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate::ArmaturePopulate() :
|
||||
BaseProcess() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/// The class destructor.
|
||||
ArmaturePopulate::~ArmaturePopulate() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_PopulateArmatureData) != 0;
|
||||
}
|
||||
|
||||
void ArmaturePopulate::SetupProperties(const Importer *) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void ArmaturePopulate::Execute(aiScene *out) {
|
||||
|
||||
// Now convert all bone positions to the correct mOffsetMatrix
|
||||
std::vector<aiBone *> bones;
|
||||
std::vector<aiNode *> nodes;
|
||||
std::map<aiBone *, aiNode *> bone_stack;
|
||||
BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
|
||||
BuildNodeList(out->mRootNode, nodes);
|
||||
|
||||
BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes);
|
||||
|
||||
ASSIMP_LOG_DEBUG("Bone stack size: ", bone_stack.size());
|
||||
|
||||
for (std::pair<aiBone *, aiNode *> kvp : bone_stack) {
|
||||
aiBone *bone = kvp.first;
|
||||
aiNode *bone_node = kvp.second;
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("active node lookup: ", bone->mName.C_Str());
|
||||
// lcl transform grab - done in generate_nodes :)
|
||||
|
||||
// bone->mOffsetMatrix = bone_node->mTransformation;
|
||||
aiNode *armature = GetArmatureRoot(bone_node, bones);
|
||||
|
||||
ai_assert(armature);
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS
|
||||
// set up bone armature id
|
||||
bone->mArmature = armature;
|
||||
|
||||
// set this bone node to be referenced properly
|
||||
ai_assert(bone_node);
|
||||
bone->mNode = bone_node;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reprocess all nodes to calculate bone transforms properly based on the REAL
|
||||
// mOffsetMatrix not the local.
|
||||
// Before this would use mesh transforms which is wrong for bone transforms
|
||||
// Before this would work for simple character skeletons but not complex meshes
|
||||
// with multiple origins
|
||||
// Source: sketch fab log cutter fbx
|
||||
void ArmaturePopulate::BuildBoneList(aiNode *current_node,
|
||||
const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
std::vector<aiBone *> &bones) {
|
||||
ai_assert(scene);
|
||||
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
|
||||
aiNode *child = current_node->mChildren[nodeId];
|
||||
ai_assert(child);
|
||||
|
||||
// check for bones
|
||||
for (unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId) {
|
||||
ai_assert(child->mMeshes);
|
||||
unsigned int mesh_index = child->mMeshes[meshId];
|
||||
aiMesh *mesh = scene->mMeshes[mesh_index];
|
||||
ai_assert(mesh);
|
||||
|
||||
for (unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId) {
|
||||
aiBone *bone = mesh->mBones[boneId];
|
||||
ai_assert(nullptr != bone);
|
||||
|
||||
// duplicate mehes exist with the same bones sometimes :)
|
||||
// so this must be detected
|
||||
if (std::find(bones.begin(), bones.end(), bone) == bones.end()) {
|
||||
// add the element once
|
||||
bones.emplace_back(bone);
|
||||
}
|
||||
}
|
||||
|
||||
// find mesh and get bones
|
||||
// then do recursive lookup for bones in root node hierarchy
|
||||
}
|
||||
|
||||
BuildBoneList(child, root_node, scene, bones);
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare flat node list which can be used for non recursive lookups later
|
||||
void ArmaturePopulate::BuildNodeList(const aiNode *current_node,
|
||||
std::vector<aiNode *> &nodes) {
|
||||
ai_assert(nullptr != current_node);
|
||||
|
||||
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
|
||||
aiNode *child = current_node->mChildren[nodeId];
|
||||
ai_assert(child);
|
||||
|
||||
if (child->mNumMeshes == 0) {
|
||||
nodes.emplace_back(child);
|
||||
}
|
||||
|
||||
BuildNodeList(child, nodes);
|
||||
}
|
||||
}
|
||||
|
||||
// A bone stack allows us to have multiple armatures, with the same bone names
|
||||
// A bone stack allows us also to retrieve bones true transform even with
|
||||
// duplicate names :)
|
||||
void ArmaturePopulate::BuildBoneStack(aiNode *,
|
||||
const aiNode *root_node,
|
||||
const aiScene*,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode *> &node_stack) {
|
||||
if (node_stack.empty()) {
|
||||
return;
|
||||
}
|
||||
ai_assert(nullptr != root_node);
|
||||
|
||||
for (aiBone *bone : bones) {
|
||||
ai_assert(bone);
|
||||
aiNode *node = GetNodeFromStack(bone->mName, node_stack);
|
||||
if (node == nullptr) {
|
||||
node_stack.clear();
|
||||
BuildNodeList(root_node, node_stack);
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Resetting bone stack: nullptr element ", bone->mName.C_Str());
|
||||
|
||||
node = GetNodeFromStack(bone->mName, node_stack);
|
||||
|
||||
if (nullptr == node) {
|
||||
ASSIMP_LOG_ERROR("serious import issue node for bone was not detected");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Successfully added bone[", bone->mName.C_Str(), "] to stack and bone node is: ", node->mName.C_Str());
|
||||
|
||||
bone_stack.insert(std::pair<aiBone *, aiNode *>(bone, node));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the armature root node
|
||||
// This is required to be detected for a bone initially, it will recurse up
|
||||
// until it cannot find another bone and return the node No known failure
|
||||
// points. (yet)
|
||||
aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list) {
|
||||
while (nullptr != bone_node) {
|
||||
if (!IsBoneNode(bone_node->mName, bone_list)) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str());
|
||||
return bone_node;
|
||||
}
|
||||
|
||||
bone_node = bone_node->mParent;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_ERROR("GetArmatureRoot() can't find armature!");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Simple IsBoneNode check if this could be a bone
|
||||
bool ArmaturePopulate::IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones) {
|
||||
for (aiBone *bone : bones) {
|
||||
if (bone->mName == bone_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pop this node by name from the stack if found
|
||||
// Used in multiple armature situations with duplicate node / bone names
|
||||
// Known flaw: cannot have nodes with bone names, will be fixed in later release
|
||||
// (serious to be fixed) Known flaw: nodes which have more than one bone could
|
||||
// be prematurely dropped from stack
|
||||
aiNode *ArmaturePopulate::GetNodeFromStack(const aiString &node_name,
|
||||
std::vector<aiNode *> &nodes) {
|
||||
std::vector<aiNode *>::iterator iter;
|
||||
aiNode *found = nullptr;
|
||||
for (iter = nodes.begin(); iter < nodes.end(); ++iter) {
|
||||
aiNode *element = *iter;
|
||||
ai_assert(nullptr != element);
|
||||
// node valid and node name matches
|
||||
if (element->mName == node_name) {
|
||||
found = element;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found != nullptr) {
|
||||
ASSIMP_LOG_INFO("Removed node from stack: ", found->mName.C_Str());
|
||||
// now pop the element from the node list
|
||||
nodes.erase(iter);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// unique names can cause this problem
|
||||
ASSIMP_LOG_ERROR("[Serious] GetNodeFromStack() can't find node from stack!");
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // Namespace Assimp
|
||||
112
Engine/lib/assimp/code/PostProcessing/ArmaturePopulate.h
Normal file
112
Engine/lib/assimp/code/PostProcessing/ArmaturePopulate.h
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef ARMATURE_POPULATE_H_
|
||||
#define ARMATURE_POPULATE_H_
|
||||
|
||||
#include "Common/BaseProcess.h"
|
||||
#include <assimp/BaseImporter.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
struct aiNode;
|
||||
struct aiBone;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** Armature Populate: This is a post process designed
|
||||
* To save you time when importing models into your game engines
|
||||
* This was originally designed only for fbx but will work with other formats
|
||||
* it is intended to auto populate aiBone data with armature and the aiNode
|
||||
* This is very useful when dealing with skinned meshes
|
||||
* or when dealing with many different skeletons
|
||||
* It's off by default but recommend that you try it and use it
|
||||
* It should reduce down any glue code you have in your
|
||||
* importers
|
||||
* You can contact RevoluPowered <gordon@gordonite.tech>
|
||||
* For more info about this
|
||||
*/
|
||||
class ASSIMP_API ArmaturePopulate : public BaseProcess {
|
||||
public:
|
||||
/// The default class constructor.
|
||||
ArmaturePopulate();
|
||||
|
||||
/// The class destructor.
|
||||
virtual ~ArmaturePopulate();
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual bool IsActive( unsigned int pFlags ) const;
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void SetupProperties( const Importer* pImp );
|
||||
|
||||
/// Overwritten, @see BaseProcess
|
||||
virtual void Execute( aiScene* pScene );
|
||||
|
||||
static aiNode *GetArmatureRoot(aiNode *bone_node,
|
||||
std::vector<aiBone *> &bone_list);
|
||||
|
||||
static bool IsBoneNode(const aiString &bone_name,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static aiNode *GetNodeFromStack(const aiString &node_name,
|
||||
std::vector<aiNode *> &nodes);
|
||||
|
||||
static void BuildNodeList(const aiNode *current_node,
|
||||
std::vector<aiNode *> &nodes);
|
||||
|
||||
static void BuildBoneList(aiNode *current_node, const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
std::vector<aiBone *> &bones);
|
||||
|
||||
static void BuildBoneStack(aiNode *current_node, const aiNode *root_node,
|
||||
const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode *> &node_stack);
|
||||
};
|
||||
|
||||
} // Namespace Assimp
|
||||
|
||||
|
||||
#endif // SCALE_PROCESS_H_
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -55,54 +55,49 @@ using namespace Assimp;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
CalcTangentsProcess::CalcTangentsProcess()
|
||||
: configMaxAngle( AI_DEG_TO_RAD(45.f) )
|
||||
, configSourceUV( 0 ) {
|
||||
CalcTangentsProcess::CalcTangentsProcess() :
|
||||
configMaxAngle(float(AI_DEG_TO_RAD(45.f))), configSourceUV(0) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
CalcTangentsProcess::~CalcTangentsProcess()
|
||||
{
|
||||
CalcTangentsProcess::~CalcTangentsProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool CalcTangentsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool CalcTangentsProcess::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_CalcTangentSpace) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void CalcTangentsProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
ai_assert( NULL != pImp );
|
||||
void CalcTangentsProcess::SetupProperties(const Importer *pImp) {
|
||||
ai_assert(nullptr != pImp);
|
||||
|
||||
// get the current value of the property
|
||||
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f);
|
||||
configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f);
|
||||
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, 45.f);
|
||||
configMaxAngle = std::max(std::min(configMaxAngle, 45.0f), 0.0f);
|
||||
configMaxAngle = AI_DEG_TO_RAD(configMaxAngle);
|
||||
|
||||
configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0);
|
||||
configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX, 0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void CalcTangentsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ai_assert( NULL != pScene );
|
||||
void CalcTangentsProcess::Execute(aiScene *pScene) {
|
||||
ai_assert(nullptr != pScene);
|
||||
|
||||
ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
|
||||
|
||||
bool bHas = false;
|
||||
for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
|
||||
if(ProcessMesh( pScene->mMeshes[a],a))bHas = true;
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if (ProcessMesh(pScene->mMeshes[a], a)) bHas = true;
|
||||
}
|
||||
|
||||
if ( bHas ) {
|
||||
if (bHas) {
|
||||
ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
|
||||
|
|
@ -111,8 +106,7 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Calculates tangents and bi-tangents for the given mesh
|
||||
bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
||||
{
|
||||
bool CalcTangentsProcess::ProcessMesh(aiMesh *pMesh, unsigned int meshIndex) {
|
||||
// we assume that the mesh is still in the verbose vertex format where each face has its own set
|
||||
// of vertices and no vertices are shared between faces. Sadly I don't know any quick test to
|
||||
// assert() it here.
|
||||
|
|
@ -124,54 +118,48 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
// If the mesh consists of lines and/or points but not of
|
||||
// triangles or higher-order polygons the normal vectors
|
||||
// are undefined.
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
|
||||
{
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
|
||||
ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
|
||||
return false;
|
||||
}
|
||||
|
||||
// what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
|
||||
if( pMesh->mNormals == NULL)
|
||||
{
|
||||
if (pMesh->mNormals == nullptr) {
|
||||
ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
|
||||
return false;
|
||||
}
|
||||
if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
|
||||
{
|
||||
ASSIMP_LOG_ERROR((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
|
||||
if (configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV]) {
|
||||
ASSIMP_LOG_ERROR("Failed to compute tangents; need UV data in channel", configSourceUV);
|
||||
return false;
|
||||
}
|
||||
|
||||
const float angleEpsilon = 0.9999f;
|
||||
|
||||
std::vector<bool> vertexDone( pMesh->mNumVertices, false);
|
||||
std::vector<bool> vertexDone(pMesh->mNumVertices, false);
|
||||
const float qnan = get_qnan();
|
||||
|
||||
// create space for the tangents and bitangents
|
||||
pMesh->mTangents = new aiVector3D[pMesh->mNumVertices];
|
||||
pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices];
|
||||
|
||||
const aiVector3D* meshPos = pMesh->mVertices;
|
||||
const aiVector3D* meshNorm = pMesh->mNormals;
|
||||
const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV];
|
||||
aiVector3D* meshTang = pMesh->mTangents;
|
||||
aiVector3D* meshBitang = pMesh->mBitangents;
|
||||
const aiVector3D *meshPos = pMesh->mVertices;
|
||||
const aiVector3D *meshNorm = pMesh->mNormals;
|
||||
const aiVector3D *meshTex = pMesh->mTextureCoords[configSourceUV];
|
||||
aiVector3D *meshTang = pMesh->mTangents;
|
||||
aiVector3D *meshBitang = pMesh->mBitangents;
|
||||
|
||||
// calculate the tangent and bitangent for every face
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3)
|
||||
{
|
||||
for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
const aiFace &face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3) {
|
||||
// There are less than three indices, thus the tangent vector
|
||||
// is not defined. We are finished with these vertices now,
|
||||
// their tangent vectors are set to qnan.
|
||||
for (unsigned int i = 0; i < face.mNumIndices;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
||||
unsigned int idx = face.mIndices[i];
|
||||
vertexDone [idx] = true;
|
||||
meshTang [idx] = aiVector3D(qnan);
|
||||
meshBitang [idx] = aiVector3D(qnan);
|
||||
vertexDone[idx] = true;
|
||||
meshTang[idx] = aiVector3D(qnan);
|
||||
meshBitang[idx] = aiVector3D(qnan);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
|
@ -190,9 +178,11 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y;
|
||||
float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f;
|
||||
// when t1, t2, t3 in same position in UV space, just use default UV direction.
|
||||
if ( sx * ty == sy * tx ) {
|
||||
sx = 0.0; sy = 1.0;
|
||||
tx = 1.0; ty = 0.0;
|
||||
if (sx * ty == sy * tx) {
|
||||
sx = 0.0;
|
||||
sy = 1.0;
|
||||
tx = 1.0;
|
||||
ty = 0.0;
|
||||
}
|
||||
|
||||
// tangent points in the direction where to positive X axis of the texture coord's would point in model space
|
||||
|
|
@ -201,18 +191,19 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
tangent.x = (w.x * sy - v.x * ty) * dirCorrection;
|
||||
tangent.y = (w.y * sy - v.y * ty) * dirCorrection;
|
||||
tangent.z = (w.z * sy - v.z * ty) * dirCorrection;
|
||||
bitangent.x = (w.x * sx - v.x * tx) * dirCorrection;
|
||||
bitangent.y = (w.y * sx - v.y * tx) * dirCorrection;
|
||||
bitangent.z = (w.z * sx - v.z * tx) * dirCorrection;
|
||||
bitangent.x = (- w.x * sx + v.x * tx) * dirCorrection;
|
||||
bitangent.y = (- w.y * sx + v.y * tx) * dirCorrection;
|
||||
bitangent.z = (- w.z * sx + v.z * tx) * dirCorrection;
|
||||
|
||||
// store for every vertex of that face
|
||||
for( unsigned int b = 0; b < face.mNumIndices; ++b ) {
|
||||
for (unsigned int b = 0; b < face.mNumIndices; ++b) {
|
||||
unsigned int p = face.mIndices[b];
|
||||
|
||||
// project tangent and bitangent into the plane formed by the vertex' normal
|
||||
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
|
||||
localTangent.NormalizeSafe(); localBitangent.NormalizeSafe();
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]) - localTangent * (bitangent * localTangent);
|
||||
localTangent.NormalizeSafe();
|
||||
localBitangent.NormalizeSafe();
|
||||
|
||||
// reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
|
||||
bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
|
||||
|
|
@ -228,31 +219,28 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
}
|
||||
|
||||
// and write it into the mesh.
|
||||
meshTang[ p ] = localTangent;
|
||||
meshBitang[ p ] = localBitangent;
|
||||
meshTang[p] = localTangent;
|
||||
meshBitang[p] = localBitangent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// create a helper to quickly find locally close vertices among the vertex array
|
||||
// FIX: check whether we can reuse the SpatialSort of a previous step
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort _vertexFinder;
|
||||
float posEpsilon;
|
||||
if (shared)
|
||||
{
|
||||
std::vector<std::pair<SpatialSort,float> >* avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
||||
if (avf)
|
||||
{
|
||||
std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex);
|
||||
SpatialSort *vertexFinder = nullptr;
|
||||
SpatialSort _vertexFinder;
|
||||
float posEpsilon = 10e-6f;
|
||||
if (shared) {
|
||||
std::vector<std::pair<SpatialSort, float>> *avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
|
||||
if (avf) {
|
||||
std::pair<SpatialSort, float> &blubb = avf->operator[](meshIndex);
|
||||
vertexFinder = &blubb.first;
|
||||
posEpsilon = blubb.second;;
|
||||
posEpsilon = blubb.second;
|
||||
;
|
||||
}
|
||||
}
|
||||
if (!vertexFinder)
|
||||
{
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
if (!vertexFinder) {
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
|
||||
vertexFinder = &_vertexFinder;
|
||||
posEpsilon = ComputePositionEpsilon(pMesh);
|
||||
}
|
||||
|
|
@ -263,56 +251,52 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
|
||||
// in the second pass we now smooth out all tangents and bitangents at the same local position
|
||||
// if they are not too far off.
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
{
|
||||
if( vertexDone[a])
|
||||
for (unsigned int a = 0; a < pMesh->mNumVertices; a++) {
|
||||
if (vertexDone[a])
|
||||
continue;
|
||||
|
||||
const aiVector3D& origPos = pMesh->mVertices[a];
|
||||
const aiVector3D& origNorm = pMesh->mNormals[a];
|
||||
const aiVector3D& origTang = pMesh->mTangents[a];
|
||||
const aiVector3D& origBitang = pMesh->mBitangents[a];
|
||||
closeVertices.resize( 0 );
|
||||
const aiVector3D &origPos = pMesh->mVertices[a];
|
||||
const aiVector3D &origNorm = pMesh->mNormals[a];
|
||||
const aiVector3D &origTang = pMesh->mTangents[a];
|
||||
const aiVector3D &origBitang = pMesh->mBitangents[a];
|
||||
closeVertices.resize(0);
|
||||
|
||||
// find all vertices close to that position
|
||||
vertexFinder->FindPositions( origPos, posEpsilon, verticesFound);
|
||||
vertexFinder->FindPositions(origPos, posEpsilon, verticesFound);
|
||||
|
||||
closeVertices.reserve (verticesFound.size()+5);
|
||||
closeVertices.push_back( a);
|
||||
closeVertices.reserve(verticesFound.size() + 5);
|
||||
closeVertices.push_back(a);
|
||||
|
||||
// look among them for other vertices sharing the same normal and a close-enough tangent/bitangent
|
||||
for( unsigned int b = 0; b < verticesFound.size(); b++)
|
||||
{
|
||||
for (unsigned int b = 0; b < verticesFound.size(); b++) {
|
||||
unsigned int idx = verticesFound[b];
|
||||
if( vertexDone[idx])
|
||||
if (vertexDone[idx])
|
||||
continue;
|
||||
if( meshNorm[idx] * origNorm < angleEpsilon)
|
||||
if (meshNorm[idx] * origNorm < angleEpsilon)
|
||||
continue;
|
||||
if( meshTang[idx] * origTang < fLimit)
|
||||
if (meshTang[idx] * origTang < fLimit)
|
||||
continue;
|
||||
if( meshBitang[idx] * origBitang < fLimit)
|
||||
if (meshBitang[idx] * origBitang < fLimit)
|
||||
continue;
|
||||
|
||||
// it's similar enough -> add it to the smoothing group
|
||||
closeVertices.push_back( idx);
|
||||
closeVertices.push_back(idx);
|
||||
vertexDone[idx] = true;
|
||||
}
|
||||
|
||||
// smooth the tangents and bitangents of all vertices that were found to be close enough
|
||||
aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0);
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
smoothTangent += meshTang[ closeVertices[b] ];
|
||||
smoothBitangent += meshBitang[ closeVertices[b] ];
|
||||
aiVector3D smoothTangent(0, 0, 0), smoothBitangent(0, 0, 0);
|
||||
for (unsigned int b = 0; b < closeVertices.size(); ++b) {
|
||||
smoothTangent += meshTang[closeVertices[b]];
|
||||
smoothBitangent += meshBitang[closeVertices[b]];
|
||||
}
|
||||
smoothTangent.Normalize();
|
||||
smoothBitangent.Normalize();
|
||||
|
||||
// and write it back into all affected tangents
|
||||
for( unsigned int b = 0; b < closeVertices.size(); ++b)
|
||||
{
|
||||
meshTang[ closeVertices[b] ] = smoothTangent;
|
||||
meshBitang[ closeVertices[b] ] = smoothBitangent;
|
||||
for (unsigned int b = 0; b < closeVertices.size(); ++b) {
|
||||
meshTang[closeVertices[b]] = smoothTangent;
|
||||
meshBitang[closeVertices[b]] = smoothBitangent;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -122,7 +122,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
|||
const aiFace& face = mesh->mFaces[fidx];
|
||||
if (face.mNumIndices < 3) continue; // triangles and polygons only, please
|
||||
|
||||
unsigned int small = face.mNumIndices, large = small;
|
||||
unsigned int smallV = face.mNumIndices, large = smallV;
|
||||
bool zero = false, one = false, round_to_zero = false;
|
||||
|
||||
// Check whether this face lies on a UV seam. We can just guess,
|
||||
|
|
@ -133,7 +133,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
|||
{
|
||||
if (out[face.mIndices[n]].x < LOWER_LIMIT)
|
||||
{
|
||||
small = n;
|
||||
smallV = n;
|
||||
|
||||
// If we have a U value very close to 0 we can't
|
||||
// round the others to 0, too.
|
||||
|
|
@ -151,7 +151,7 @@ void RemoveUVSeams (aiMesh* mesh, aiVector3D* out)
|
|||
one = true;
|
||||
}
|
||||
}
|
||||
if (small != face.mNumIndices && large != face.mNumIndices)
|
||||
if (smallV != face.mNumIndices && large != face.mNumIndices)
|
||||
{
|
||||
for (unsigned int n = 0; n < face.mNumIndices;++n)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -49,10 +49,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* better location.
|
||||
*/
|
||||
|
||||
|
||||
#include "ConvertToLHProcess.h"
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
|
@ -62,8 +61,10 @@ using namespace Assimp;
|
|||
namespace {
|
||||
|
||||
template <typename aiMeshType>
|
||||
void flipUVs(aiMeshType* pMesh) {
|
||||
if (pMesh == nullptr) { return; }
|
||||
void flipUVs(aiMeshType *pMesh) {
|
||||
if (pMesh == nullptr) {
|
||||
return;
|
||||
}
|
||||
// mirror texture y coordinate
|
||||
for (unsigned int tcIdx = 0; tcIdx < AI_MAX_NUMBER_OF_TEXTURECOORDS; tcIdx++) {
|
||||
if (!pMesh->HasTextureCoords(tcIdx)) {
|
||||
|
|
@ -80,8 +81,8 @@ void flipUVs(aiMeshType* pMesh) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
MakeLeftHandedProcess::MakeLeftHandedProcess()
|
||||
: BaseProcess() {
|
||||
MakeLeftHandedProcess::MakeLeftHandedProcess() :
|
||||
BaseProcess() {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
|
@ -93,40 +94,36 @@ MakeLeftHandedProcess::~MakeLeftHandedProcess() {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool MakeLeftHandedProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool MakeLeftHandedProcess::IsActive(unsigned int pFlags) const {
|
||||
return 0 != (pFlags & aiProcess_MakeLeftHanded);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void MakeLeftHandedProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void MakeLeftHandedProcess::Execute(aiScene *pScene) {
|
||||
// Check for an existent root node to proceed
|
||||
ai_assert(pScene->mRootNode != NULL);
|
||||
ai_assert(pScene->mRootNode != nullptr);
|
||||
ASSIMP_LOG_DEBUG("MakeLeftHandedProcess begin");
|
||||
|
||||
// recursively convert all the nodes
|
||||
ProcessNode( pScene->mRootNode, aiMatrix4x4());
|
||||
ProcessNode(pScene->mRootNode, aiMatrix4x4());
|
||||
|
||||
// process the meshes accordingly
|
||||
for ( unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
|
||||
ProcessMesh( pScene->mMeshes[ a ] );
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
||||
ProcessMesh(pScene->mMeshes[a]);
|
||||
}
|
||||
|
||||
// process the materials accordingly
|
||||
for ( unsigned int a = 0; a < pScene->mNumMaterials; ++a ) {
|
||||
ProcessMaterial( pScene->mMaterials[ a ] );
|
||||
for (unsigned int a = 0; a < pScene->mNumMaterials; ++a) {
|
||||
ProcessMaterial(pScene->mMaterials[a]);
|
||||
}
|
||||
|
||||
// transform all animation channels as well
|
||||
for( unsigned int a = 0; a < pScene->mNumAnimations; a++)
|
||||
{
|
||||
aiAnimation* anim = pScene->mAnimations[a];
|
||||
for( unsigned int b = 0; b < anim->mNumChannels; b++)
|
||||
{
|
||||
aiNodeAnim* nodeAnim = anim->mChannels[b];
|
||||
ProcessAnimation( nodeAnim);
|
||||
for (unsigned int a = 0; a < pScene->mNumAnimations; a++) {
|
||||
aiAnimation *anim = pScene->mAnimations[a];
|
||||
for (unsigned int b = 0; b < anim->mNumChannels; b++) {
|
||||
aiNodeAnim *nodeAnim = anim->mChannels[b];
|
||||
ProcessAnimation(nodeAnim);
|
||||
}
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished");
|
||||
|
|
@ -134,8 +131,7 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively converts a node, all of its children and all of its meshes
|
||||
void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pParentGlobalRotation)
|
||||
{
|
||||
void MakeLeftHandedProcess::ProcessNode(aiNode *pNode, const aiMatrix4x4 &pParentGlobalRotation) {
|
||||
// mirror all base vectors at the local Z axis
|
||||
pNode->mTransformation.c1 = -pNode->mTransformation.c1;
|
||||
pNode->mTransformation.c2 = -pNode->mTransformation.c2;
|
||||
|
|
@ -150,43 +146,38 @@ void MakeLeftHandedProcess::ProcessNode( aiNode* pNode, const aiMatrix4x4& pPare
|
|||
pNode->mTransformation.d3 = -pNode->mTransformation.d3; // useless, but anyways...
|
||||
|
||||
// continue for all children
|
||||
for( size_t a = 0; a < pNode->mNumChildren; ++a ) {
|
||||
ProcessNode( pNode->mChildren[ a ], pParentGlobalRotation * pNode->mTransformation );
|
||||
for (size_t a = 0; a < pNode->mNumChildren; ++a) {
|
||||
ProcessNode(pNode->mChildren[a], pParentGlobalRotation * pNode->mTransformation);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh to left handed coordinates.
|
||||
void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
|
||||
if ( nullptr == pMesh ) {
|
||||
ASSIMP_LOG_ERROR( "Nullptr to mesh found." );
|
||||
void MakeLeftHandedProcess::ProcessMesh(aiMesh *pMesh) {
|
||||
if (nullptr == pMesh) {
|
||||
ASSIMP_LOG_ERROR("Nullptr to mesh found.");
|
||||
return;
|
||||
}
|
||||
// mirror positions, normals and stuff along the Z axis
|
||||
for( size_t a = 0; a < pMesh->mNumVertices; ++a)
|
||||
{
|
||||
for (size_t a = 0; a < pMesh->mNumVertices; ++a) {
|
||||
pMesh->mVertices[a].z *= -1.0f;
|
||||
if (pMesh->HasNormals()) {
|
||||
pMesh->mNormals[a].z *= -1.0f;
|
||||
}
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
if (pMesh->HasTangentsAndBitangents()) {
|
||||
pMesh->mTangents[a].z *= -1.0f;
|
||||
pMesh->mBitangents[a].z *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// mirror anim meshes positions, normals and stuff along the Z axis
|
||||
for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m)
|
||||
{
|
||||
for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a)
|
||||
{
|
||||
for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m) {
|
||||
for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a) {
|
||||
pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f;
|
||||
if (pMesh->mAnimMeshes[m]->HasNormals()) {
|
||||
pMesh->mAnimMeshes[m]->mNormals[a].z *= -1.0f;
|
||||
}
|
||||
if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents())
|
||||
{
|
||||
if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents()) {
|
||||
pMesh->mAnimMeshes[m]->mTangents[a].z *= -1.0f;
|
||||
pMesh->mAnimMeshes[m]->mBitangents[a].z *= -1.0f;
|
||||
}
|
||||
|
|
@ -194,9 +185,8 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
|
|||
}
|
||||
|
||||
// mirror offset matrices of all bones
|
||||
for( size_t a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
aiBone* bone = pMesh->mBones[a];
|
||||
for (size_t a = 0; a < pMesh->mNumBones; ++a) {
|
||||
aiBone *bone = pMesh->mBones[a];
|
||||
bone->mOffsetMatrix.a3 = -bone->mOffsetMatrix.a3;
|
||||
bone->mOffsetMatrix.b3 = -bone->mOffsetMatrix.b3;
|
||||
bone->mOffsetMatrix.d3 = -bone->mOffsetMatrix.d3;
|
||||
|
|
@ -206,29 +196,28 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) {
|
|||
}
|
||||
|
||||
// mirror bitangents as well as they're derived from the texture coords
|
||||
if( pMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
for( unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
if (pMesh->HasTangentsAndBitangents()) {
|
||||
for (unsigned int a = 0; a < pMesh->mNumVertices; a++)
|
||||
pMesh->mBitangents[a] *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single material to left handed coordinates.
|
||||
void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) {
|
||||
if ( nullptr == _mat ) {
|
||||
ASSIMP_LOG_ERROR( "Nullptr to aiMaterial found." );
|
||||
void MakeLeftHandedProcess::ProcessMaterial(aiMaterial *_mat) {
|
||||
if (nullptr == _mat) {
|
||||
ASSIMP_LOG_ERROR("Nullptr to aiMaterial found.");
|
||||
return;
|
||||
}
|
||||
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
aiMaterial *mat = (aiMaterial *)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
|
||||
aiMaterialProperty *prop = mat->mProperties[a];
|
||||
|
||||
// Mapping axis for UV mappings?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.mapaxis")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiVector3D)); /* something is wrong with the validation if we end up here */
|
||||
aiVector3D* pff = (aiVector3D*)prop->mData;
|
||||
if (!::strcmp(prop->mKey.data, "$tex.mapaxis")) {
|
||||
ai_assert(prop->mDataLength >= sizeof(aiVector3D)); // something is wrong with the validation if we end up here
|
||||
aiVector3D *pff = (aiVector3D *)prop->mData;
|
||||
pff->z *= -1.f;
|
||||
}
|
||||
}
|
||||
|
|
@ -236,15 +225,13 @@ void MakeLeftHandedProcess::ProcessMaterial( aiMaterial* _mat) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts the given animation to LH coordinates.
|
||||
void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim)
|
||||
{
|
||||
void MakeLeftHandedProcess::ProcessAnimation(aiNodeAnim *pAnim) {
|
||||
// position keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
|
||||
for (unsigned int a = 0; a < pAnim->mNumPositionKeys; a++)
|
||||
pAnim->mPositionKeys[a].mValue.z *= -1.0f;
|
||||
|
||||
// rotation keys
|
||||
for( unsigned int a = 0; a < pAnim->mNumRotationKeys; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < pAnim->mNumRotationKeys; a++) {
|
||||
/* That's the safe version, but the float errors add up. So we try the short version instead
|
||||
aiMatrix3x3 rotmat = pAnim->mRotationKeys[a].mValue.GetMatrix();
|
||||
rotmat.a3 = -rotmat.a3; rotmat.b3 = -rotmat.b3;
|
||||
|
|
@ -258,55 +245,50 @@ void MakeLeftHandedProcess::ProcessAnimation( aiNodeAnim* pAnim)
|
|||
}
|
||||
|
||||
#endif // !! ASSIMP_BUILD_NO_MAKELEFTHANDED_PROCESS
|
||||
#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS
|
||||
#ifndef ASSIMP_BUILD_NO_FLIPUVS_PROCESS
|
||||
// # FlipUVsProcess
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FlipUVsProcess::FlipUVsProcess()
|
||||
{}
|
||||
FlipUVsProcess::FlipUVsProcess() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FlipUVsProcess::~FlipUVsProcess()
|
||||
{}
|
||||
FlipUVsProcess::~FlipUVsProcess() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FlipUVsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool FlipUVsProcess::IsActive(unsigned int pFlags) const {
|
||||
return 0 != (pFlags & aiProcess_FlipUVs);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FlipUVsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void FlipUVsProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("FlipUVsProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
|
||||
for (unsigned int i = 0; i < pScene->mNumMaterials; ++i)
|
||||
ProcessMaterial(pScene->mMaterials[i]);
|
||||
ASSIMP_LOG_DEBUG("FlipUVsProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single material
|
||||
void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
|
||||
{
|
||||
aiMaterial* mat = (aiMaterial*)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties;++a) {
|
||||
aiMaterialProperty* prop = mat->mProperties[a];
|
||||
if( !prop ) {
|
||||
ASSIMP_LOG_DEBUG( "Property is null" );
|
||||
void FlipUVsProcess::ProcessMaterial(aiMaterial *_mat) {
|
||||
aiMaterial *mat = (aiMaterial *)_mat;
|
||||
for (unsigned int a = 0; a < mat->mNumProperties; ++a) {
|
||||
aiMaterialProperty *prop = mat->mProperties[a];
|
||||
if (!prop) {
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Property is null");
|
||||
continue;
|
||||
}
|
||||
|
||||
// UV transformation key?
|
||||
if (!::strcmp( prop->mKey.data, "$tex.uvtrafo")) {
|
||||
ai_assert( prop->mDataLength >= sizeof(aiUVTransform)); /* something is wrong with the validation if we end up here */
|
||||
aiUVTransform* uv = (aiUVTransform*)prop->mData;
|
||||
if (!::strcmp(prop->mKey.data, "$tex.uvtrafo")) {
|
||||
ai_assert(prop->mDataLength >= sizeof(aiUVTransform)); // something is wrong with the validation if we end up here
|
||||
aiUVTransform *uv = (aiUVTransform *)prop->mData;
|
||||
|
||||
// just flip it, that's everything
|
||||
uv->mTranslation.y *= -1.f;
|
||||
|
|
@ -317,8 +299,7 @@ void FlipUVsProcess::ProcessMaterial (aiMaterial* _mat)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh
|
||||
void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
void FlipUVsProcess::ProcessMesh(aiMesh *pMesh) {
|
||||
flipUVs(pMesh);
|
||||
for (unsigned int idx = 0; idx < pMesh->mNumAnimMeshes; idx++) {
|
||||
flipUVs(pMesh->mAnimMeshes[idx]);
|
||||
|
|
@ -326,44 +307,38 @@ void FlipUVsProcess::ProcessMesh( aiMesh* pMesh)
|
|||
}
|
||||
|
||||
#endif // !ASSIMP_BUILD_NO_FLIPUVS_PROCESS
|
||||
#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
|
||||
#ifndef ASSIMP_BUILD_NO_FLIPWINDING_PROCESS
|
||||
// # FlipWindingOrderProcess
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FlipWindingOrderProcess::FlipWindingOrderProcess()
|
||||
{}
|
||||
FlipWindingOrderProcess::FlipWindingOrderProcess() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FlipWindingOrderProcess::~FlipWindingOrderProcess()
|
||||
{}
|
||||
FlipWindingOrderProcess::~FlipWindingOrderProcess() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool FlipWindingOrderProcess::IsActive(unsigned int pFlags) const {
|
||||
return 0 != (pFlags & aiProcess_FlipWindingOrder);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FlipWindingOrderProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void FlipWindingOrderProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("FlipWindingOrderProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i)
|
||||
ProcessMesh(pScene->mMeshes[i]);
|
||||
ASSIMP_LOG_DEBUG("FlipWindingOrderProcess finished");
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Converts a single mesh
|
||||
void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
|
||||
{
|
||||
void FlipWindingOrderProcess::ProcessMesh(aiMesh *pMesh) {
|
||||
// invert the order of all faces in this mesh
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
aiFace& face = pMesh->mFaces[a];
|
||||
for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
aiFace &face = pMesh->mFaces[a];
|
||||
for (unsigned int b = 0; b < face.mNumIndices / 2; b++) {
|
||||
std::swap(face.mIndices[b], face.mIndices[face.mNumIndices - 1 - b]);
|
||||
}
|
||||
|
|
@ -371,39 +346,34 @@ void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh)
|
|||
|
||||
// invert the order of all components in this mesh anim meshes
|
||||
for (unsigned int m = 0; m < pMesh->mNumAnimMeshes; m++) {
|
||||
aiAnimMesh* animMesh = pMesh->mAnimMeshes[m];
|
||||
aiAnimMesh *animMesh = pMesh->mAnimMeshes[m];
|
||||
unsigned int numVertices = animMesh->mNumVertices;
|
||||
if (animMesh->HasPositions()) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numVertices; a++) {
|
||||
std::swap(animMesh->mVertices[a], animMesh->mVertices[numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
if (animMesh->HasNormals()) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numVertices; a++) {
|
||||
std::swap(animMesh->mNormals[a], animMesh->mNormals[numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) {
|
||||
if (animMesh->HasTextureCoords(i)) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numVertices; a++) {
|
||||
std::swap(animMesh->mTextureCoords[i][a], animMesh->mTextureCoords[i][numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (animMesh->HasTangentsAndBitangents()) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numVertices; a++) {
|
||||
std::swap(animMesh->mTangents[a], animMesh->mTangents[numVertices - 1 - a]);
|
||||
std::swap(animMesh->mBitangents[a], animMesh->mBitangents[numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
for (unsigned int v = 0; v < AI_MAX_NUMBER_OF_COLOR_SETS; v++) {
|
||||
if (animMesh->HasVertexColors(v)) {
|
||||
for (unsigned int a = 0; a < numVertices; a++)
|
||||
{
|
||||
for (unsigned int a = 0; a < numVertices; a++) {
|
||||
std::swap(animMesh->mColors[v][a], animMesh->mColors[v][numVertices - 1 - a]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -148,7 +148,7 @@ void DeboneProcess::Execute( aiScene* pScene)
|
|||
}
|
||||
|
||||
if(!DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_INFO_F("Removed %u bones. Input bones:", in - out, ". Output bones: ", out);
|
||||
ASSIMP_LOG_INFO("Removed %u bones. Input bones:", in - out, ". Output bones: ", out);
|
||||
}
|
||||
|
||||
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||
|
|
@ -414,7 +414,8 @@ void DeboneProcess::UpdateNode(aiNode* pNode) const
|
|||
}
|
||||
|
||||
if( pNode->mNumMeshes > 0 ) {
|
||||
delete [] pNode->mMeshes; pNode->mMeshes = NULL;
|
||||
delete[] pNode->mMeshes;
|
||||
pNode->mMeshes = nullptr;
|
||||
}
|
||||
|
||||
pNode->mNumMeshes = static_cast<unsigned int>(newMeshList.size());
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -98,12 +98,14 @@ void DropFaceNormalsProcess::Execute( aiScene* pScene) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* pMesh) {
|
||||
if (NULL == pMesh->mNormals) {
|
||||
bool DropFaceNormalsProcess::DropMeshFaceNormals (aiMesh* mesh) {
|
||||
ai_assert(nullptr != mesh);
|
||||
|
||||
if (nullptr == mesh->mNormals) {
|
||||
return false;
|
||||
}
|
||||
|
||||
delete[] pMesh->mNormals;
|
||||
pMesh->mNormals = nullptr;
|
||||
|
||||
delete[] mesh->mNormals;
|
||||
mesh->mNormals = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -41,6 +40,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
*/
|
||||
|
||||
#include "EmbedTexturesProcess.h"
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include "ProcessHelper.h"
|
||||
|
||||
|
|
@ -48,11 +49,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
EmbedTexturesProcess::EmbedTexturesProcess()
|
||||
: BaseProcess() {
|
||||
EmbedTexturesProcess::EmbedTexturesProcess() :
|
||||
BaseProcess() {
|
||||
// empty
|
||||
}
|
||||
|
||||
EmbedTexturesProcess::~EmbedTexturesProcess() {
|
||||
// empty
|
||||
}
|
||||
|
||||
bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
|
||||
|
|
@ -62,15 +65,16 @@ bool EmbedTexturesProcess::IsActive(unsigned int pFlags) const {
|
|||
void EmbedTexturesProcess::SetupProperties(const Importer* pImp) {
|
||||
mRootPath = pImp->GetPropertyString("sourceFilePath");
|
||||
mRootPath = mRootPath.substr(0, mRootPath.find_last_of("\\/") + 1u);
|
||||
mIOHandler = pImp->GetIOHandler();
|
||||
}
|
||||
|
||||
void EmbedTexturesProcess::Execute(aiScene* pScene) {
|
||||
if (pScene == nullptr || pScene->mRootNode == nullptr) return;
|
||||
if (pScene == nullptr || pScene->mRootNode == nullptr || mIOHandler == nullptr){
|
||||
return;
|
||||
}
|
||||
|
||||
aiString path;
|
||||
|
||||
uint32_t embeddedTexturesCount = 0u;
|
||||
|
||||
for (auto matId = 0u; matId < pScene->mNumMaterials; ++matId) {
|
||||
auto material = pScene->mMaterials[matId];
|
||||
|
||||
|
|
@ -85,7 +89,7 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) {
|
|||
// Indeed embed
|
||||
if (addTexture(pScene, path.data)) {
|
||||
auto embeddedTextureId = pScene->mNumTextures - 1u;
|
||||
::ai_snprintf(path.data, 1024, "*%u", embeddedTextureId);
|
||||
path.length = ::ai_snprintf(path.data, 1024, "*%u", embeddedTextureId);
|
||||
material->AddProperty(&path, AI_MATKEY_TEXTURE(tt, texId));
|
||||
embeddedTexturesCount++;
|
||||
}
|
||||
|
|
@ -93,41 +97,46 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) {
|
|||
}
|
||||
}
|
||||
|
||||
ASSIMP_LOG_INFO_F("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." );
|
||||
ASSIMP_LOG_INFO("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." );
|
||||
}
|
||||
|
||||
bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
|
||||
bool EmbedTexturesProcess::addTexture(aiScene *pScene, const std::string &path) const {
|
||||
std::streampos imageSize = 0;
|
||||
std::string imagePath = path;
|
||||
|
||||
// Test path directly
|
||||
std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
|
||||
if ((imageSize = file.tellg()) == std::streampos(-1)) {
|
||||
ASSIMP_LOG_WARN_F("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder.");
|
||||
if (!mIOHandler->Exists(imagePath)) {
|
||||
ASSIMP_LOG_WARN("EmbedTexturesProcess: Cannot find image: ", imagePath, ". Will try to find it in root folder.");
|
||||
|
||||
// Test path in root path
|
||||
imagePath = mRootPath + path;
|
||||
file.open(imagePath, std::ios::binary | std::ios::ate);
|
||||
if ((imageSize = file.tellg()) == std::streampos(-1)) {
|
||||
if (!mIOHandler->Exists(imagePath)) {
|
||||
// Test path basename in root path
|
||||
imagePath = mRootPath + path.substr(path.find_last_of("\\/") + 1u);
|
||||
file.open(imagePath, std::ios::binary | std::ios::ate);
|
||||
if ((imageSize = file.tellg()) == std::streampos(-1)) {
|
||||
ASSIMP_LOG_ERROR_F("EmbedTexturesProcess: Unable to embed texture: ", path, ".");
|
||||
if (!mIOHandler->Exists(imagePath)) {
|
||||
ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", path, ".");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
IOStream* pFile = mIOHandler->Open(imagePath);
|
||||
if (pFile == nullptr) {
|
||||
ASSIMP_LOG_ERROR("EmbedTexturesProcess: Unable to embed texture: ", path, ".");
|
||||
return false;
|
||||
}
|
||||
imageSize = pFile->FileSize();
|
||||
|
||||
aiTexel* imageContent = new aiTexel[ 1ul + static_cast<unsigned long>( imageSize ) / sizeof(aiTexel)];
|
||||
file.seekg(0, std::ios::beg);
|
||||
file.read(reinterpret_cast<char*>(imageContent), imageSize);
|
||||
pFile->Seek(0, aiOrigin_SET);
|
||||
pFile->Read(reinterpret_cast<char*>(imageContent), imageSize, 1);
|
||||
mIOHandler->Close(pFile);
|
||||
|
||||
// Enlarging the textures table
|
||||
unsigned int textureId = pScene->mNumTextures++;
|
||||
auto oldTextures = pScene->mTextures;
|
||||
pScene->mTextures = new aiTexture*[pScene->mNumTextures];
|
||||
::memmove(pScene->mTextures, oldTextures, sizeof(aiTexture*) * (pScene->mNumTextures - 1u));
|
||||
delete [] oldTextures;
|
||||
|
||||
// Add the new texture
|
||||
auto pTexture = new aiTexture;
|
||||
|
|
@ -136,7 +145,7 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const {
|
|||
pTexture->pcData = imageContent;
|
||||
|
||||
auto extension = path.substr(path.find_last_of('.') + 1u);
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
extension = ai_tolower(extension);
|
||||
if (extension == "jpeg") {
|
||||
extension = "jpg";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -48,6 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
struct aiNode;
|
||||
|
||||
class IOSystem;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
/**
|
||||
|
|
@ -76,10 +78,11 @@ public:
|
|||
|
||||
private:
|
||||
// Resolve the path and add the file content to the scene as a texture.
|
||||
bool addTexture(aiScene* pScene, std::string path) const;
|
||||
bool addTexture(aiScene *pScene, const std::string &path) const;
|
||||
|
||||
private:
|
||||
std::string mRootPath;
|
||||
IOSystem* mIOHandler = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -45,25 +43,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* @brief Implementation of the FindDegenerates post-process step.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// internal headers
|
||||
#include "ProcessHelper.h"
|
||||
#include "FindDegenerates.h"
|
||||
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
//remove mesh at position 'index' from the scene
|
||||
static void removeMesh(aiScene* pScene, unsigned const index);
|
||||
//correct node indices to meshes and remove references to deleted mesh
|
||||
static void updateSceneGraph(aiNode* pNode, unsigned const index);
|
||||
// Correct node indices to meshes and remove references to deleted mesh
|
||||
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FindDegeneratesProcess::FindDegeneratesProcess()
|
||||
: mConfigRemoveDegenerates( false )
|
||||
, mConfigCheckAreaOfTriangle( false ){
|
||||
FindDegeneratesProcess::FindDegeneratesProcess() :
|
||||
mConfigRemoveDegenerates( false ),
|
||||
mConfigCheckAreaOfTriangle( false ){
|
||||
// empty
|
||||
}
|
||||
|
||||
|
|
@ -91,50 +87,50 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
|
|||
// Executes the post processing step on the given imported data.
|
||||
void FindDegeneratesProcess::Execute( aiScene* pScene) {
|
||||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
||||
{
|
||||
//Do not process point cloud, ExecuteOnMesh works only with faces data
|
||||
if ( nullptr == pScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unordered_map<unsigned int, unsigned int> meshMap;
|
||||
meshMap.reserve(pScene->mNumMeshes);
|
||||
|
||||
const unsigned int originalNumMeshes = pScene->mNumMeshes;
|
||||
unsigned int targetIndex = 0;
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
// Do not process point cloud, ExecuteOnMesh works only with faces data
|
||||
if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
|
||||
removeMesh(pScene, i);
|
||||
--i; //the current i is removed, do not skip the next one
|
||||
delete pScene->mMeshes[i];
|
||||
// Not strictly required, but clean:
|
||||
pScene->mMeshes[i] = nullptr;
|
||||
} else {
|
||||
meshMap[i] = targetIndex;
|
||||
pScene->mMeshes[targetIndex] = pScene->mMeshes[i];
|
||||
++targetIndex;
|
||||
}
|
||||
}
|
||||
pScene->mNumMeshes = targetIndex;
|
||||
|
||||
if (meshMap.size() < originalNumMeshes) {
|
||||
updateSceneGraph(pScene->mRootNode, meshMap);
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
|
||||
}
|
||||
|
||||
static void removeMesh(aiScene* pScene, unsigned const index) {
|
||||
//we start at index and copy the pointers one position forward
|
||||
//save the mesh pointer to delete it later
|
||||
auto delete_me = pScene->mMeshes[index];
|
||||
for (unsigned i = index; i < pScene->mNumMeshes - 1; ++i) {
|
||||
pScene->mMeshes[i] = pScene->mMeshes[i+1];
|
||||
}
|
||||
pScene->mMeshes[pScene->mNumMeshes - 1] = nullptr;
|
||||
--(pScene->mNumMeshes);
|
||||
delete delete_me;
|
||||
|
||||
//removing a mesh also requires updating all references to it in the scene graph
|
||||
updateSceneGraph(pScene->mRootNode, index);
|
||||
}
|
||||
|
||||
static void updateSceneGraph(aiNode* pNode, unsigned const index) {
|
||||
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap) {
|
||||
unsigned int targetIndex = 0;
|
||||
for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
|
||||
if (pNode->mMeshes[i] > index) {
|
||||
--(pNode->mMeshes[i]);
|
||||
continue;
|
||||
}
|
||||
if (pNode->mMeshes[i] == index) {
|
||||
for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) {
|
||||
pNode->mMeshes[j] = pNode->mMeshes[j+1];
|
||||
}
|
||||
--(pNode->mNumMeshes);
|
||||
--i;
|
||||
continue;
|
||||
const unsigned int sourceMeshIndex = pNode->mMeshes[i];
|
||||
auto it = meshMap.find(sourceMeshIndex);
|
||||
if (it != meshMap.end()) {
|
||||
pNode->mMeshes[targetIndex] = it->second;
|
||||
++targetIndex;
|
||||
}
|
||||
}
|
||||
pNode->mNumMeshes = targetIndex;
|
||||
//recurse to all children
|
||||
for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
|
||||
updateSceneGraph(pNode->mChildren[i], index);
|
||||
updateSceneGraph(pNode->mChildren[i], meshMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +221,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
|
|||
if ( mConfigCheckAreaOfTriangle ) {
|
||||
if ( face.mNumIndices == 3 ) {
|
||||
ai_real area = calculateAreaOfTriangle( face, mesh );
|
||||
if ( area < 1e-6 ) {
|
||||
if (area < ai_epsilon) {
|
||||
if ( mConfigRemoveDegenerates ) {
|
||||
remove_me[ a ] = true;
|
||||
++deg;
|
||||
|
|
@ -289,13 +285,13 @@ evil_jump_outside:
|
|||
if (!mesh->mNumFaces) {
|
||||
//The whole mesh consists of degenerated faces
|
||||
//signal upward, that this mesh should be deleted.
|
||||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (deg && !DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_WARN_F( "Found ", deg, " degenerated primitives");
|
||||
ASSIMP_LOG_WARN( "Found ", deg, " degenerated primitives");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -137,7 +137,7 @@ void FindInstancesProcess::Execute( aiScene* pScene)
|
|||
aiMesh* inst = pScene->mMeshes[i];
|
||||
hashes[i] = GetMeshHash(inst);
|
||||
|
||||
// Find an appropriate epsilon
|
||||
// Find an appropriate epsilon
|
||||
// to compare position differences against
|
||||
float epsilon = ComputePositionEpsilon(inst);
|
||||
epsilon *= epsilon;
|
||||
|
|
@ -243,7 +243,7 @@ void FindInstancesProcess::Execute( aiScene* pScene)
|
|||
|
||||
// Delete the instanced mesh, we don't need it anymore
|
||||
delete inst;
|
||||
pScene->mMeshes[i] = NULL;
|
||||
pScene->mMeshes[i] = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ void FindInstancesProcess::Execute( aiScene* pScene)
|
|||
ai_assert(0 != numMeshesOut);
|
||||
if (numMeshesOut != pScene->mNumMeshes) {
|
||||
|
||||
// Collapse the meshes array by removing all NULL entries
|
||||
// Collapse the meshes array by removing all nullptr entries
|
||||
for (unsigned int real = 0, i = 0; real < numMeshesOut; ++i) {
|
||||
if (pScene->mMeshes[i])
|
||||
pScene->mMeshes[real++] = pScene->mMeshes[i];
|
||||
|
|
@ -267,7 +267,7 @@ void FindInstancesProcess::Execute( aiScene* pScene)
|
|||
|
||||
// write to log
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_INFO_F( "FindInstancesProcess finished. Found ", (pScene->mNumMeshes - numMeshesOut), " instances" );
|
||||
ASSIMP_LOG_INFO( "FindInstancesProcess finished. Found ", (pScene->mNumMeshes - numMeshesOut), " instances" );
|
||||
}
|
||||
pScene->mNumMeshes = numMeshesOut;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -44,15 +42,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
/** @file Defines a post processing step to search an importer's output
|
||||
for data that is obviously invalid */
|
||||
|
||||
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS
|
||||
|
||||
// internal headers
|
||||
#include "FindInvalidDataProcess.h"
|
||||
#include "ProcessHelper.h"
|
||||
|
||||
#include <assimp/Macros.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/qnan.h>
|
||||
|
||||
|
|
@ -60,9 +55,8 @@ using namespace Assimp;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
FindInvalidDataProcess::FindInvalidDataProcess()
|
||||
: configEpsilon(0.0)
|
||||
, mIgnoreTexCoods( false ){
|
||||
FindInvalidDataProcess::FindInvalidDataProcess() :
|
||||
configEpsilon(0.0), mIgnoreTexCoods(false) {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
|
|
@ -74,47 +68,47 @@ FindInvalidDataProcess::~FindInvalidDataProcess() {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const {
|
||||
bool FindInvalidDataProcess::IsActive(unsigned int pFlags) const {
|
||||
return 0 != (pFlags & aiProcess_FindInvalidData);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup import configuration
|
||||
void FindInvalidDataProcess::SetupProperties(const Importer* pImp) {
|
||||
void FindInvalidDataProcess::SetupProperties(const Importer *pImp) {
|
||||
// Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY
|
||||
configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY,0.f));
|
||||
configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY, 0.f));
|
||||
mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Update mesh references in the node graph
|
||||
void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMapping) {
|
||||
if (node->mNumMeshes) {
|
||||
void UpdateMeshReferences(aiNode *node, const std::vector<unsigned int> &meshMapping) {
|
||||
if (node->mNumMeshes) {
|
||||
unsigned int out = 0;
|
||||
for (unsigned int a = 0; a < node->mNumMeshes;++a) {
|
||||
for (unsigned int a = 0; a < node->mNumMeshes; ++a) {
|
||||
|
||||
unsigned int ref = node->mMeshes[a];
|
||||
if (UINT_MAX != (ref = meshMapping[ref])) {
|
||||
if (UINT_MAX != (ref = meshMapping[ref])) {
|
||||
node->mMeshes[out++] = ref;
|
||||
}
|
||||
}
|
||||
// just let the members that are unused, that's much cheaper
|
||||
// than a full array realloc'n'copy party ...
|
||||
if(!(node->mNumMeshes = out)) {
|
||||
|
||||
node->mNumMeshes = out;
|
||||
if (0 == out) {
|
||||
delete[] node->mMeshes;
|
||||
node->mMeshes = NULL;
|
||||
node->mMeshes = nullptr;
|
||||
}
|
||||
}
|
||||
// recursively update all children
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i) {
|
||||
UpdateMeshReferences(node->mChildren[i],meshMapping);
|
||||
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
|
||||
UpdateMeshReferences(node->mChildren[i], meshMapping);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void FindInvalidDataProcess::Execute( aiScene* pScene) {
|
||||
void FindInvalidDataProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
|
||||
|
||||
bool out = false;
|
||||
|
|
@ -122,33 +116,32 @@ void FindInvalidDataProcess::Execute( aiScene* pScene) {
|
|||
unsigned int real = 0;
|
||||
|
||||
// Process meshes
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
|
||||
int result;
|
||||
if ((result = ProcessMesh( pScene->mMeshes[a]))) {
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
int result = ProcessMesh(pScene->mMeshes[a]);
|
||||
if (0 == result) {
|
||||
out = true;
|
||||
|
||||
if (2 == result) {
|
||||
// remove this mesh
|
||||
delete pScene->mMeshes[a];
|
||||
AI_DEBUG_INVALIDATE_PTR(pScene->mMeshes[a]);
|
||||
|
||||
meshMapping[a] = UINT_MAX;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (2 == result) {
|
||||
// remove this mesh
|
||||
delete pScene->mMeshes[a];
|
||||
pScene->mMeshes[a] = nullptr;
|
||||
|
||||
meshMapping[a] = UINT_MAX;
|
||||
out = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
pScene->mMeshes[real] = pScene->mMeshes[a];
|
||||
meshMapping[a] = real++;
|
||||
}
|
||||
|
||||
// Process animations
|
||||
for (unsigned int a = 0; a < pScene->mNumAnimations;++a) {
|
||||
ProcessAnimation( pScene->mAnimations[a]);
|
||||
for (unsigned int animIdx = 0; animIdx < pScene->mNumAnimations; ++animIdx) {
|
||||
ProcessAnimation(pScene->mAnimations[animIdx]);
|
||||
}
|
||||
|
||||
|
||||
if (out) {
|
||||
if ( real != pScene->mNumMeshes) {
|
||||
if (out) {
|
||||
if (real != pScene->mNumMeshes) {
|
||||
if (!real) {
|
||||
throw DeadlyImportError("No meshes remaining");
|
||||
}
|
||||
|
|
@ -156,7 +149,7 @@ void FindInvalidDataProcess::Execute( aiScene* pScene) {
|
|||
// we need to remove some meshes.
|
||||
// therefore we'll also need to remove all references
|
||||
// to them from the scenegraph
|
||||
UpdateMeshReferences(pScene->mRootNode,meshMapping);
|
||||
UpdateMeshReferences(pScene->mRootNode, meshMapping);
|
||||
pScene->mNumMeshes = real;
|
||||
}
|
||||
|
||||
|
|
@ -168,35 +161,32 @@ void FindInvalidDataProcess::Execute( aiScene* pScene) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline
|
||||
const char* ValidateArrayContents(const T* /*arr*/, unsigned int /*size*/,
|
||||
const std::vector<bool>& /*dirtyMask*/, bool /*mayBeIdentical = false*/, bool /*mayBeZero = true*/)
|
||||
{
|
||||
inline const char *ValidateArrayContents(const T * /*arr*/, unsigned int /*size*/,
|
||||
const std::vector<bool> & /*dirtyMask*/, bool /*mayBeIdentical = false*/, bool /*mayBeZero = true*/) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <>
|
||||
inline
|
||||
const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsigned int size,
|
||||
const std::vector<bool>& dirtyMask, bool mayBeIdentical , bool mayBeZero ) {
|
||||
inline const char *ValidateArrayContents<aiVector3D>(const aiVector3D *arr, unsigned int size,
|
||||
const std::vector<bool> &dirtyMask, bool mayBeIdentical, bool mayBeZero) {
|
||||
bool b = false;
|
||||
unsigned int cnt = 0;
|
||||
for (unsigned int i = 0; i < size;++i) {
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
|
||||
if (dirtyMask.size() && dirtyMask[i]) {
|
||||
continue;
|
||||
}
|
||||
++cnt;
|
||||
|
||||
const aiVector3D& v = arr[i];
|
||||
if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
|
||||
const aiVector3D &v = arr[i];
|
||||
if (is_special_float(v.x) || is_special_float(v.y) || is_special_float(v.z)) {
|
||||
return "INF/NAN was found in a vector component";
|
||||
}
|
||||
if (!mayBeZero && !v.x && !v.y && !v.z ) {
|
||||
if (!mayBeZero && !v.x && !v.y && !v.z) {
|
||||
return "Found zero-length vector";
|
||||
}
|
||||
if (i && v != arr[i-1])b = true;
|
||||
if (i && v != arr[i - 1]) b = true;
|
||||
}
|
||||
if (cnt > 1 && !b && !mayBeIdentical) {
|
||||
return "All vectors are identical";
|
||||
|
|
@ -206,14 +196,13 @@ const char* ValidateArrayContents<aiVector3D>(const aiVector3D* arr, unsigned in
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline
|
||||
bool ProcessArray(T*& in, unsigned int num,const char* name,
|
||||
const std::vector<bool>& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
|
||||
const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero);
|
||||
if (err) {
|
||||
ASSIMP_LOG_ERROR_F( "FindInvalidDataProcess fails on mesh ", name, ": ", err);
|
||||
inline bool ProcessArray(T *&in, unsigned int num, const char *name,
|
||||
const std::vector<bool> &dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) {
|
||||
const char *err = ValidateArrayContents(in, num, dirtyMask, mayBeIdentical, mayBeZero);
|
||||
if (err) {
|
||||
ASSIMP_LOG_ERROR("FindInvalidDataProcess fails on mesh ", name, ": ", err);
|
||||
delete[] in;
|
||||
in = NULL;
|
||||
in = nullptr;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -221,49 +210,46 @@ bool ProcessArray(T*& in, unsigned int num,const char* name,
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
AI_FORCE_INLINE bool EpsilonCompare(const T& n, const T& s, ai_real epsilon);
|
||||
AI_FORCE_INLINE bool EpsilonCompare(const T &n, const T &s, ai_real epsilon);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE bool EpsilonCompare(ai_real n, ai_real s, ai_real epsilon) {
|
||||
return std::fabs(n-s)>epsilon;
|
||||
return std::fabs(n - s) > epsilon;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <>
|
||||
bool EpsilonCompare<aiVectorKey>(const aiVectorKey& n, const aiVectorKey& s, ai_real epsilon) {
|
||||
return
|
||||
EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) &&
|
||||
EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) &&
|
||||
EpsilonCompare(n.mValue.z,s.mValue.z,epsilon);
|
||||
bool EpsilonCompare<aiVectorKey>(const aiVectorKey &n, const aiVectorKey &s, ai_real epsilon) {
|
||||
return EpsilonCompare(n.mValue.x, s.mValue.x, epsilon) &&
|
||||
EpsilonCompare(n.mValue.y, s.mValue.y, epsilon) &&
|
||||
EpsilonCompare(n.mValue.z, s.mValue.z, epsilon);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <>
|
||||
bool EpsilonCompare<aiQuatKey>(const aiQuatKey& n, const aiQuatKey& s, ai_real epsilon) {
|
||||
return
|
||||
EpsilonCompare(n.mValue.x,s.mValue.x,epsilon) &&
|
||||
EpsilonCompare(n.mValue.y,s.mValue.y,epsilon) &&
|
||||
EpsilonCompare(n.mValue.z,s.mValue.z,epsilon) &&
|
||||
EpsilonCompare(n.mValue.w,s.mValue.w,epsilon);
|
||||
bool EpsilonCompare<aiQuatKey>(const aiQuatKey &n, const aiQuatKey &s, ai_real epsilon) {
|
||||
return EpsilonCompare(n.mValue.x, s.mValue.x, epsilon) &&
|
||||
EpsilonCompare(n.mValue.y, s.mValue.y, epsilon) &&
|
||||
EpsilonCompare(n.mValue.z, s.mValue.z, epsilon) &&
|
||||
EpsilonCompare(n.mValue.w, s.mValue.w, epsilon);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline
|
||||
bool AllIdentical(T* in, unsigned int num, ai_real epsilon) {
|
||||
inline bool AllIdentical(T *in, unsigned int num, ai_real epsilon) {
|
||||
if (num <= 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fabs(epsilon) > 0.f) {
|
||||
for (unsigned int i = 0; i < num-1;++i) {
|
||||
if (!EpsilonCompare(in[i],in[i+1],epsilon)) {
|
||||
for (unsigned int i = 0; i < num - 1; ++i) {
|
||||
if (!EpsilonCompare(in[i], in[i + 1], epsilon)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = 0; i < num-1;++i) {
|
||||
if (in[i] != in[i+1]) {
|
||||
for (unsigned int i = 0; i < num - 1; ++i) {
|
||||
if (in[i] != in[i + 1]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -273,16 +259,16 @@ bool AllIdentical(T* in, unsigned int num, ai_real epsilon) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Search an animation for invalid content
|
||||
void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim) {
|
||||
void FindInvalidDataProcess::ProcessAnimation(aiAnimation *anim) {
|
||||
// Process all animation channels
|
||||
for ( unsigned int a = 0; a < anim->mNumChannels; ++a ) {
|
||||
ProcessAnimationChannel( anim->mChannels[a]);
|
||||
for (unsigned int a = 0; a < anim->mNumChannels; ++a) {
|
||||
ProcessAnimationChannel(anim->mChannels[a]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) {
|
||||
ai_assert( nullptr != anim );
|
||||
void FindInvalidDataProcess::ProcessAnimationChannel(aiNodeAnim *anim) {
|
||||
ai_assert(nullptr != anim);
|
||||
if (anim->mNumPositionKeys == 0 && anim->mNumRotationKeys == 0 && anim->mNumScalingKeys == 0) {
|
||||
ai_assert_entry();
|
||||
return;
|
||||
|
|
@ -292,7 +278,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) {
|
|||
// we can remove al keys except one.
|
||||
// POSITIONS
|
||||
int i = 0;
|
||||
if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon)) {
|
||||
if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys, anim->mNumPositionKeys, configEpsilon)) {
|
||||
aiVectorKey v = anim->mPositionKeys[0];
|
||||
|
||||
// Reallocate ... we need just ONE element, it makes no sense to reuse the array
|
||||
|
|
@ -303,7 +289,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) {
|
|||
}
|
||||
|
||||
// ROTATIONS
|
||||
if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon)) {
|
||||
if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys, anim->mNumRotationKeys, configEpsilon)) {
|
||||
aiQuatKey v = anim->mRotationKeys[0];
|
||||
|
||||
// Reallocate ... we need just ONE element, it makes no sense to reuse the array
|
||||
|
|
@ -314,7 +300,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) {
|
|||
}
|
||||
|
||||
// SCALINGS
|
||||
if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon)) {
|
||||
if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys, anim->mNumScalingKeys, configEpsilon)) {
|
||||
aiVectorKey v = anim->mScalingKeys[0];
|
||||
|
||||
// Reallocate ... we need just ONE element, it makes no sense to reuse the array
|
||||
|
|
@ -323,22 +309,21 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) {
|
|||
anim->mScalingKeys[0] = v;
|
||||
i = 1;
|
||||
}
|
||||
if ( 1 == i ) {
|
||||
if (1 == i) {
|
||||
ASSIMP_LOG_WARN("Simplified dummy tracks with just one key");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Search a mesh for invalid contents
|
||||
int FindInvalidDataProcess::ProcessMesh(aiMesh* pMesh)
|
||||
{
|
||||
int FindInvalidDataProcess::ProcessMesh(aiMesh *pMesh) {
|
||||
bool ret = false;
|
||||
std::vector<bool> dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0);
|
||||
|
||||
// Ignore elements that are not referenced by vertices.
|
||||
// (they are, for example, caused by the FindDegenerates step)
|
||||
for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
|
||||
const aiFace& f = pMesh->mFaces[m];
|
||||
const aiFace &f = pMesh->mFaces[m];
|
||||
|
||||
for (unsigned int i = 0; i < f.mNumIndices; ++i) {
|
||||
dirtyMask[f.mIndices[i]] = false;
|
||||
|
|
@ -361,7 +346,7 @@ int FindInvalidDataProcess::ProcessMesh(aiMesh* pMesh)
|
|||
// delete all subsequent texture coordinate sets.
|
||||
for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) {
|
||||
delete[] pMesh->mTextureCoords[a];
|
||||
pMesh->mTextureCoords[a] = NULL;
|
||||
pMesh->mTextureCoords[a] = nullptr;
|
||||
pMesh->mNumUVComponents[a] = 0;
|
||||
}
|
||||
|
||||
|
|
@ -374,19 +359,17 @@ int FindInvalidDataProcess::ProcessMesh(aiMesh* pMesh)
|
|||
// they are invalid or not.
|
||||
|
||||
// Normals and tangents are undefined for point and line faces.
|
||||
if (pMesh->mNormals || pMesh->mTangents) {
|
||||
if (pMesh->mNormals || pMesh->mTangents) {
|
||||
|
||||
if (aiPrimitiveType_POINT & pMesh->mPrimitiveTypes ||
|
||||
aiPrimitiveType_LINE & pMesh->mPrimitiveTypes)
|
||||
{
|
||||
aiPrimitiveType_LINE & pMesh->mPrimitiveTypes) {
|
||||
if (aiPrimitiveType_TRIANGLE & pMesh->mPrimitiveTypes ||
|
||||
aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes)
|
||||
{
|
||||
aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) {
|
||||
// We need to update the lookup-table
|
||||
for (unsigned int m = 0; m < pMesh->mNumFaces;++m) {
|
||||
const aiFace& f = pMesh->mFaces[ m ];
|
||||
for (unsigned int m = 0; m < pMesh->mNumFaces; ++m) {
|
||||
const aiFace &f = pMesh->mFaces[m];
|
||||
|
||||
if (f.mNumIndices < 3) {
|
||||
if (f.mNumIndices < 3) {
|
||||
dirtyMask[f.mIndices[0]] = true;
|
||||
if (f.mNumIndices == 2) {
|
||||
dirtyMask[f.mIndices[1]] = true;
|
||||
|
|
@ -402,19 +385,21 @@ int FindInvalidDataProcess::ProcessMesh(aiMesh* pMesh)
|
|||
}
|
||||
|
||||
// Process mesh normals
|
||||
if (pMesh->mNormals && ProcessArray(pMesh->mNormals,pMesh->mNumVertices,
|
||||
"normals",dirtyMask,true,false))
|
||||
if (pMesh->mNormals && ProcessArray(pMesh->mNormals, pMesh->mNumVertices,
|
||||
"normals", dirtyMask, true, false))
|
||||
ret = true;
|
||||
|
||||
// Process mesh tangents
|
||||
if (pMesh->mTangents && ProcessArray(pMesh->mTangents,pMesh->mNumVertices,"tangents",dirtyMask)) {
|
||||
delete[] pMesh->mBitangents; pMesh->mBitangents = NULL;
|
||||
if (pMesh->mTangents && ProcessArray(pMesh->mTangents, pMesh->mNumVertices, "tangents", dirtyMask)) {
|
||||
delete[] pMesh->mBitangents;
|
||||
pMesh->mBitangents = nullptr;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// Process mesh bitangents
|
||||
if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents,pMesh->mNumVertices,"bitangents",dirtyMask)) {
|
||||
delete[] pMesh->mTangents; pMesh->mTangents = NULL;
|
||||
if (pMesh->mBitangents && ProcessArray(pMesh->mBitangents, pMesh->mNumVertices, "bitangents", dirtyMask)) {
|
||||
delete[] pMesh->mTangents;
|
||||
pMesh->mTangents = nullptr;
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -48,14 +47,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "Common/BaseProcess.h"
|
||||
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/types.h>
|
||||
|
||||
struct aiMesh;
|
||||
|
||||
class FindInvalidDataProcessTest;
|
||||
|
||||
namespace Assimp {
|
||||
namespace Assimp {
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
/** The FindInvalidData post-processing step. It searches the mesh data
|
||||
|
|
@ -70,31 +69,31 @@ public:
|
|||
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
bool IsActive(unsigned int pFlags) const;
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Setup import settings
|
||||
void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer *pImp);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Run the step
|
||||
void Execute( aiScene* pScene);
|
||||
void Execute(aiScene *pScene);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post-processing step on the given mesh
|
||||
* @param pMesh The mesh to process.
|
||||
* @return 0 - nothing, 1 - removed sth, 2 - please delete me */
|
||||
int ProcessMesh( aiMesh* pMesh);
|
||||
int ProcessMesh(aiMesh *pMesh);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post-processing step on the given animation
|
||||
* @param anim The animation to process. */
|
||||
void ProcessAnimation (aiAnimation* anim);
|
||||
void ProcessAnimation(aiAnimation *anim);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Executes the post-processing step on the given anim channel
|
||||
* @param anim The animation channel to process.*/
|
||||
void ProcessAnimationChannel (aiNodeAnim* anim);
|
||||
void ProcessAnimationChannel(aiNodeAnim *anim);
|
||||
|
||||
private:
|
||||
ai_real configEpsilon;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -164,7 +164,7 @@ bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index)
|
|||
// now compare the volumes of the bounding boxes
|
||||
if (std::fabs(fDelta0_x * fDelta0_y * fDelta0_z) < std::fabs(fDelta1_x * fDelta1_yz)) {
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_INFO_F("Mesh ", index, ": Normals are facing inwards (or the mesh is planar)", index);
|
||||
ASSIMP_LOG_INFO("Mesh ", index, ": Normals are facing inwards (or the mesh is planar)", index);
|
||||
}
|
||||
|
||||
// Invert normals
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -45,41 +45,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* normals for all imported faces.
|
||||
*/
|
||||
|
||||
|
||||
#include "GenFaceNormalsProcess.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/qnan.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/qnan.h>
|
||||
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
GenFaceNormalsProcess::GenFaceNormalsProcess()
|
||||
{
|
||||
GenFaceNormalsProcess::GenFaceNormalsProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
GenFaceNormalsProcess::~GenFaceNormalsProcess()
|
||||
{
|
||||
GenFaceNormalsProcess::~GenFaceNormalsProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool GenFaceNormalsProcess::IsActive( unsigned int pFlags) const {
|
||||
bool GenFaceNormalsProcess::IsActive(unsigned int pFlags) const {
|
||||
force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
|
||||
return (pFlags & aiProcess_GenNormals) != 0;
|
||||
flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
|
||||
return (pFlags & aiProcess_GenNormals) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void GenFaceNormalsProcess::Execute( aiScene* pScene) {
|
||||
void GenFaceNormalsProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("GenFaceNormalsProcess begin");
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
|
||||
|
|
@ -87,33 +84,35 @@ void GenFaceNormalsProcess::Execute( aiScene* pScene) {
|
|||
}
|
||||
|
||||
bool bHas = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if(this->GenMeshFaceNormals( pScene->mMeshes[a])) {
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if (this->GenMeshFaceNormals(pScene->mMeshes[a])) {
|
||||
bHas = true;
|
||||
}
|
||||
}
|
||||
if (bHas) {
|
||||
if (bHas) {
|
||||
ASSIMP_LOG_INFO("GenFaceNormalsProcess finished. "
|
||||
"Face normals have been calculated");
|
||||
"Face normals have been calculated");
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG("GenFaceNormalsProcess finished. "
|
||||
"Normals are already there");
|
||||
"Normals are already there");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
|
||||
{
|
||||
if (NULL != pMesh->mNormals) {
|
||||
if (force_) delete[] pMesh->mNormals;
|
||||
else return false;
|
||||
bool GenFaceNormalsProcess::GenMeshFaceNormals(aiMesh *pMesh) {
|
||||
if (nullptr != pMesh->mNormals) {
|
||||
if (force_) {
|
||||
delete[] pMesh->mNormals;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the mesh consists of lines and/or points but not of
|
||||
// triangles or higher-order polygons the normal vectors
|
||||
// are undefined.
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
|
||||
ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -123,22 +122,24 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
|
|||
const float qnan = get_qnan();
|
||||
|
||||
// iterate through all faces and compute per-face normals but store them per-vertex.
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3) {
|
||||
for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
const aiFace &face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3) {
|
||||
// either a point or a line -> no well-defined normal vector
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i) {
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
||||
pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
|
||||
const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
|
||||
const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
|
||||
const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]];
|
||||
const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]];
|
||||
const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]];
|
||||
if (flippedWindingOrder_)
|
||||
std::swap( pV2, pV3 );
|
||||
const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
|
||||
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i) {
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
||||
pMesh->mNormals[face.mIndices[i]] = vNor;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -80,6 +80,7 @@ public:
|
|||
private:
|
||||
bool GenMeshFaceNormals(aiMesh* pcMesh);
|
||||
mutable bool force_ = false;
|
||||
mutable bool flippedWindingOrder_ = false;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -45,8 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* normals for all imported faces.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// internal headers
|
||||
#include "GenVertexNormalsProcess.h"
|
||||
#include "ProcessHelper.h"
|
||||
|
|
@ -57,8 +55,8 @@ using namespace Assimp;
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
GenVertexNormalsProcess::GenVertexNormalsProcess()
|
||||
: configMaxAngle( AI_DEG_TO_RAD( 175.f ) ) {
|
||||
GenVertexNormalsProcess::GenVertexNormalsProcess() :
|
||||
configMaxAngle(AI_DEG_TO_RAD(175.f)) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
|
@ -70,25 +68,23 @@ GenVertexNormalsProcess::~GenVertexNormalsProcess() {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool GenVertexNormalsProcess::IsActive(unsigned int pFlags) const {
|
||||
force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
|
||||
flippedWindingOrder_ = (pFlags & aiProcess_FlipWindingOrder) != 0;
|
||||
return (pFlags & aiProcess_GenSmoothNormals) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void GenVertexNormalsProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
void GenVertexNormalsProcess::SetupProperties(const Importer *pImp) {
|
||||
// Get the current value of the AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE property
|
||||
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE,(ai_real)175.0);
|
||||
configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle,(ai_real)175.0),(ai_real)0.0));
|
||||
configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, (ai_real)175.0);
|
||||
configMaxAngle = AI_DEG_TO_RAD(std::max(std::min(configMaxAngle, (ai_real)175.0), (ai_real)0.0));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void GenVertexNormalsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void GenVertexNormalsProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("GenVertexNormalsProcess begin");
|
||||
|
||||
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
|
||||
|
|
@ -96,34 +92,34 @@ void GenVertexNormalsProcess::Execute( aiScene* pScene)
|
|||
}
|
||||
|
||||
bool bHas = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
||||
if(GenMeshVertexNormals( pScene->mMeshes[a],a))
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
|
||||
if (GenMeshVertexNormals(pScene->mMeshes[a], a))
|
||||
bHas = true;
|
||||
}
|
||||
|
||||
if (bHas) {
|
||||
if (bHas) {
|
||||
ASSIMP_LOG_INFO("GenVertexNormalsProcess finished. "
|
||||
"Vertex normals have been calculated");
|
||||
"Vertex normals have been calculated");
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG("GenVertexNormalsProcess finished. "
|
||||
"Normals are already there");
|
||||
"Normals are already there");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex)
|
||||
{
|
||||
if (NULL != pMesh->mNormals) {
|
||||
if (force_) delete[] pMesh->mNormals;
|
||||
else return false;
|
||||
bool GenVertexNormalsProcess::GenMeshVertexNormals(aiMesh *pMesh, unsigned int meshIndex) {
|
||||
if (nullptr != pMesh->mNormals) {
|
||||
if (force_)
|
||||
delete[] pMesh->mNormals;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the mesh consists of lines and/or points but not of
|
||||
// triangles or higher-order polygons the normal vectors
|
||||
// are undefined.
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
|
||||
{
|
||||
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
|
||||
ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes");
|
||||
return false;
|
||||
}
|
||||
|
|
@ -133,75 +129,73 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
|
|||
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
|
||||
|
||||
// Compute per-face normals but store them per-vertex
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++)
|
||||
{
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3)
|
||||
{
|
||||
for (unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
const aiFace &face = pMesh->mFaces[a];
|
||||
if (face.mNumIndices < 3) {
|
||||
// either a point or a line -> no normal vector
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i) {
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
||||
pMesh->mNormals[face.mIndices[i]] = aiVector3D(qnan);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
|
||||
const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
|
||||
const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
|
||||
const aiVector3D *pV1 = &pMesh->mVertices[face.mIndices[0]];
|
||||
const aiVector3D *pV2 = &pMesh->mVertices[face.mIndices[1]];
|
||||
const aiVector3D *pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices - 1]];
|
||||
if (flippedWindingOrder_)
|
||||
std::swap( pV2, pV3 );
|
||||
const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
|
||||
|
||||
for (unsigned int i = 0;i < face.mNumIndices;++i) {
|
||||
for (unsigned int i = 0; i < face.mNumIndices; ++i) {
|
||||
pMesh->mNormals[face.mIndices[i]] = vNor;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up a SpatialSort to quickly find all vertices close to a given position
|
||||
// check whether we can reuse the SpatialSort of a previous step.
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort _vertexFinder;
|
||||
ai_real posEpsilon = ai_real( 1e-5 );
|
||||
SpatialSort *vertexFinder = nullptr;
|
||||
SpatialSort _vertexFinder;
|
||||
ai_real posEpsilon = ai_real(1e-5);
|
||||
if (shared) {
|
||||
std::vector<std::pair<SpatialSort,ai_real> >* avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT,avf);
|
||||
if (avf)
|
||||
{
|
||||
std::pair<SpatialSort,ai_real>& blubb = avf->operator [] (meshIndex);
|
||||
std::vector<std::pair<SpatialSort, ai_real>> *avf;
|
||||
shared->GetProperty(AI_SPP_SPATIAL_SORT, avf);
|
||||
if (avf) {
|
||||
std::pair<SpatialSort, ai_real> &blubb = avf->operator[](meshIndex);
|
||||
vertexFinder = &blubb.first;
|
||||
posEpsilon = blubb.second;
|
||||
}
|
||||
}
|
||||
if (!vertexFinder) {
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D));
|
||||
if (!vertexFinder) {
|
||||
_vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof(aiVector3D));
|
||||
vertexFinder = &_vertexFinder;
|
||||
posEpsilon = ComputePositionEpsilon(pMesh);
|
||||
}
|
||||
std::vector<unsigned int> verticesFound;
|
||||
aiVector3D* pcNew = new aiVector3D[pMesh->mNumVertices];
|
||||
aiVector3D *pcNew = new aiVector3D[pMesh->mNumVertices];
|
||||
|
||||
if (configMaxAngle >= AI_DEG_TO_RAD( 175.f )) {
|
||||
if (configMaxAngle >= AI_DEG_TO_RAD(175.f)) {
|
||||
// There is no angle limit. Thus all vertices with positions close
|
||||
// to each other will receive the same vertex normal. This allows us
|
||||
// to optimize the whole algorithm a little bit ...
|
||||
std::vector<bool> abHad(pMesh->mNumVertices,false);
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices;++i) {
|
||||
std::vector<bool> abHad(pMesh->mNumVertices, false);
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
|
||||
if (abHad[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get all vertices that share this one ...
|
||||
vertexFinder->FindPositions( pMesh->mVertices[i], posEpsilon, verticesFound);
|
||||
vertexFinder->FindPositions(pMesh->mVertices[i], posEpsilon, verticesFound);
|
||||
|
||||
aiVector3D pcNor;
|
||||
for (unsigned int a = 0; a < verticesFound.size(); ++a) {
|
||||
const aiVector3D& v = pMesh->mNormals[verticesFound[a]];
|
||||
if (is_not_qnan(v.x))pcNor += v;
|
||||
const aiVector3D &v = pMesh->mNormals[verticesFound[a]];
|
||||
if (is_not_qnan(v.x)) pcNor += v;
|
||||
}
|
||||
pcNor.NormalizeSafe();
|
||||
|
||||
// Write the smoothed normal back to all affected normals
|
||||
for (unsigned int a = 0; a < verticesFound.size(); ++a)
|
||||
{
|
||||
for (unsigned int a = 0; a < verticesFound.size(); ++a) {
|
||||
unsigned int vidx = verticesFound[a];
|
||||
pcNew[vidx] = pcNor;
|
||||
abHad[vidx] = true;
|
||||
|
|
@ -210,11 +204,11 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
|
|||
}
|
||||
// Slower code path if a smooth angle is set. There are many ways to achieve
|
||||
// the effect, this one is the most straightforward one.
|
||||
else {
|
||||
else {
|
||||
const ai_real fLimit = std::cos(configMaxAngle);
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices;++i) {
|
||||
for (unsigned int i = 0; i < pMesh->mNumVertices; ++i) {
|
||||
// Get all vertices that share this one ...
|
||||
vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);
|
||||
vertexFinder->FindPositions(pMesh->mVertices[i], posEpsilon, verticesFound);
|
||||
|
||||
aiVector3D vr = pMesh->mNormals[i];
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -104,6 +104,7 @@ private:
|
|||
/** Configuration option: maximum smoothing angle, in radians*/
|
||||
ai_real configMaxAngle;
|
||||
mutable bool force_ = false;
|
||||
mutable bool flippedWindingOrder_ = false;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -109,7 +109,7 @@ void ImproveCacheLocalityProcess::Execute( aiScene* pScene) {
|
|||
}
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
if (numf > 0) {
|
||||
ASSIMP_LOG_INFO_F("Cache relevant are ", numm, " meshes (", numf, " faces). Average output ACMR is ", out / numf);
|
||||
ASSIMP_LOG_INFO("Cache relevant are ", numm, " meshes (", numf, " faces). Average output ACMR is ", out / numf);
|
||||
}
|
||||
ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess finished. ");
|
||||
}
|
||||
|
|
@ -355,7 +355,7 @@ ai_real ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int me
|
|||
|
||||
// very intense verbose logging ... prepare for much text if there are many meshes
|
||||
if ( DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) {
|
||||
ASSIMP_LOG_DEBUG_F("Mesh %u | ACMR in: ", meshNum, " out: ", fACMR, " | ~", fACMR2, ((fACMR - fACMR2) / fACMR) * 100.f);
|
||||
ASSIMP_LOG_VERBOSE_DEBUG("Mesh %u | ACMR in: ", meshNum, " out: ", fACMR, " | ~", fACMR2, ((fACMR - fACMR2) / fACMR) * 100.f);
|
||||
}
|
||||
|
||||
fACMR2 *= pMesh->mNumFaces;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ void JoinVerticesProcess::Execute( aiScene* pScene)
|
|||
if (iNumOldVertices == iNumVertices) {
|
||||
ASSIMP_LOG_DEBUG("JoinVerticesProcess finished ");
|
||||
} else {
|
||||
ASSIMP_LOG_INFO_F("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
|
||||
ASSIMP_LOG_INFO("JoinVerticesProcess finished | Verts in: ", iNumOldVertices,
|
||||
" out: ", iNumVertices, " | ~",
|
||||
((iNumOldVertices - iNumVertices) / (float)iNumOldVertices) * 100.f );
|
||||
}
|
||||
|
|
@ -266,7 +266,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
std::vector<unsigned int> replaceIndex( pMesh->mNumVertices, 0xffffffff);
|
||||
|
||||
// float posEpsilonSqr;
|
||||
SpatialSort* vertexFinder = NULL;
|
||||
SpatialSort *vertexFinder = nullptr;
|
||||
SpatialSort _vertexFinder;
|
||||
|
||||
typedef std::pair<SpatialSort,float> SpatPair;
|
||||
|
|
@ -373,7 +373,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
}
|
||||
|
||||
if (!DefaultLogger::isNullLogger() && DefaultLogger::get()->getLogSeverity() == Logger::VERBOSE) {
|
||||
ASSIMP_LOG_DEBUG_F(
|
||||
ASSIMP_LOG_VERBOSE_DEBUG(
|
||||
"Mesh ",meshIndex,
|
||||
" (",
|
||||
(pMesh->mName.length ? pMesh->mName.data : "unnamed"),
|
||||
|
|
@ -408,7 +408,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
std::vector<aiVertexWeight> newWeights;
|
||||
newWeights.reserve( bone->mNumWeights);
|
||||
|
||||
if ( NULL != bone->mWeights ) {
|
||||
if (nullptr != bone->mWeights) {
|
||||
for ( unsigned int b = 0; b < bone->mNumWeights; b++ ) {
|
||||
const aiVertexWeight& ow = bone->mWeights[ b ];
|
||||
// if the vertex is a unique one, translate it
|
||||
|
|
@ -420,7 +420,7 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
ASSIMP_LOG_ERROR( "X-Export: aiBone shall contain weights, but pointer to them is NULL." );
|
||||
ASSIMP_LOG_ERROR( "X-Export: aiBone shall contain weights, but pointer to them is nullptr." );
|
||||
}
|
||||
|
||||
if (newWeights.size() > 0) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -44,6 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
|
||||
#include "LimitBoneWeightsProcess.h"
|
||||
#include <assimp/SmallVector.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
|
@ -52,7 +53,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
LimitBoneWeightsProcess::LimitBoneWeightsProcess()
|
||||
|
|
@ -76,10 +76,12 @@ bool LimitBoneWeightsProcess::IsActive( unsigned int pFlags) const
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
|
||||
void LimitBoneWeightsProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess begin");
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; ++a ) {
|
||||
ProcessMesh(pScene->mMeshes[a]);
|
||||
|
||||
for (unsigned int m = 0; m < pScene->mNumMeshes; ++m) {
|
||||
ProcessMesh(pScene->mMeshes[m]);
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG("LimitBoneWeightsProcess end");
|
||||
|
|
@ -95,107 +97,100 @@ void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Unites identical vertices in the given mesh
|
||||
void LimitBoneWeightsProcess::ProcessMesh( aiMesh* pMesh)
|
||||
void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh)
|
||||
{
|
||||
if( !pMesh->HasBones())
|
||||
if (!pMesh->HasBones())
|
||||
return;
|
||||
|
||||
// collect all bone weights per vertex
|
||||
typedef std::vector< std::vector< Weight > > WeightsPerVertex;
|
||||
WeightsPerVertex vertexWeights( pMesh->mNumVertices);
|
||||
typedef SmallVector<Weight,8> VertexWeightArray;
|
||||
typedef std::vector<VertexWeightArray> WeightsPerVertex;
|
||||
WeightsPerVertex vertexWeights(pMesh->mNumVertices);
|
||||
size_t maxVertexWeights = 0;
|
||||
|
||||
// collect all weights per vertex
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
||||
for (unsigned int b = 0; b < pMesh->mNumBones; ++b)
|
||||
{
|
||||
const aiBone* bone = pMesh->mBones[a];
|
||||
for( unsigned int b = 0; b < bone->mNumWeights; b++)
|
||||
const aiBone* bone = pMesh->mBones[b];
|
||||
for (unsigned int w = 0; w < bone->mNumWeights; ++w)
|
||||
{
|
||||
const aiVertexWeight& w = bone->mWeights[b];
|
||||
vertexWeights[w.mVertexId].push_back( Weight( a, w.mWeight));
|
||||
const aiVertexWeight& vw = bone->mWeights[w];
|
||||
|
||||
if (vertexWeights.size() <= vw.mVertexId)
|
||||
continue;
|
||||
|
||||
vertexWeights[vw.mVertexId].push_back(Weight(b, vw.mWeight));
|
||||
maxVertexWeights = std::max(maxVertexWeights, vertexWeights[vw.mVertexId].size());
|
||||
}
|
||||
}
|
||||
|
||||
if (maxVertexWeights <= mMaxWeights)
|
||||
return;
|
||||
|
||||
unsigned int removed = 0, old_bones = pMesh->mNumBones;
|
||||
|
||||
// now cut the weight count if it exceeds the maximum
|
||||
bool bChanged = false;
|
||||
for( WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit)
|
||||
for (WeightsPerVertex::iterator vit = vertexWeights.begin(); vit != vertexWeights.end(); ++vit)
|
||||
{
|
||||
if( vit->size() <= mMaxWeights)
|
||||
if (vit->size() <= mMaxWeights)
|
||||
continue;
|
||||
|
||||
bChanged = true;
|
||||
|
||||
// more than the defined maximum -> first sort by weight in descending order. That's
|
||||
// why we defined the < operator in such a weird way.
|
||||
std::sort( vit->begin(), vit->end());
|
||||
std::sort(vit->begin(), vit->end());
|
||||
|
||||
// now kill everything beyond the maximum count
|
||||
unsigned int m = static_cast<unsigned int>(vit->size());
|
||||
vit->erase( vit->begin() + mMaxWeights, vit->end());
|
||||
removed += static_cast<unsigned int>(m-vit->size());
|
||||
vit->resize(mMaxWeights);
|
||||
removed += static_cast<unsigned int>(m - vit->size());
|
||||
|
||||
// and renormalize the weights
|
||||
float sum = 0.0f;
|
||||
for( std::vector<Weight>::const_iterator it = vit->begin(); it != vit->end(); ++it ) {
|
||||
for(const Weight* it = vit->begin(); it != vit->end(); ++it) {
|
||||
sum += it->mWeight;
|
||||
}
|
||||
if( 0.0f != sum ) {
|
||||
if (0.0f != sum) {
|
||||
const float invSum = 1.0f / sum;
|
||||
for( std::vector<Weight>::iterator it = vit->begin(); it != vit->end(); ++it ) {
|
||||
for(Weight* it = vit->begin(); it != vit->end(); ++it) {
|
||||
it->mWeight *= invSum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bChanged) {
|
||||
// rebuild the vertex weight array for all bones
|
||||
typedef std::vector< std::vector< aiVertexWeight > > WeightsPerBone;
|
||||
WeightsPerBone boneWeights( pMesh->mNumBones);
|
||||
for( unsigned int a = 0; a < vertexWeights.size(); a++)
|
||||
// clear weight count for all bone
|
||||
for (unsigned int a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
pMesh->mBones[a]->mNumWeights = 0;
|
||||
}
|
||||
|
||||
// rebuild the vertex weight array for all bones
|
||||
for (unsigned int a = 0; a < vertexWeights.size(); ++a)
|
||||
{
|
||||
const VertexWeightArray& vw = vertexWeights[a];
|
||||
for (const Weight* it = vw.begin(); it != vw.end(); ++it)
|
||||
{
|
||||
const std::vector<Weight>& vw = vertexWeights[a];
|
||||
for( std::vector<Weight>::const_iterator it = vw.begin(); it != vw.end(); ++it)
|
||||
boneWeights[it->mBone].push_back( aiVertexWeight( a, it->mWeight));
|
||||
}
|
||||
|
||||
// and finally copy the vertex weight list over to the mesh's bones
|
||||
std::vector<bool> abNoNeed(pMesh->mNumBones,false);
|
||||
bChanged = false;
|
||||
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; a++)
|
||||
{
|
||||
const std::vector<aiVertexWeight>& bw = boneWeights[a];
|
||||
aiBone* bone = pMesh->mBones[a];
|
||||
|
||||
if ( bw.empty() )
|
||||
{
|
||||
abNoNeed[a] = bChanged = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// copy the weight list. should always be less weights than before, so we don't need a new allocation
|
||||
ai_assert( bw.size() <= bone->mNumWeights);
|
||||
bone->mNumWeights = static_cast<unsigned int>( bw.size() );
|
||||
::memcpy( bone->mWeights, &bw[0], bw.size() * sizeof( aiVertexWeight));
|
||||
}
|
||||
|
||||
if (bChanged) {
|
||||
// the number of new bones is smaller than before, so we can reuse the old array
|
||||
aiBone** ppcCur = pMesh->mBones;aiBone** ppcSrc = ppcCur;
|
||||
|
||||
for (std::vector<bool>::const_iterator iter = abNoNeed.begin();iter != abNoNeed.end() ;++iter) {
|
||||
if (*iter) {
|
||||
delete *ppcSrc;
|
||||
--pMesh->mNumBones;
|
||||
}
|
||||
else *ppcCur++ = *ppcSrc;
|
||||
++ppcSrc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_INFO_F("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones );
|
||||
aiBone* bone = pMesh->mBones[it->mBone];
|
||||
bone->mWeights[bone->mNumWeights++] = aiVertexWeight(a, it->mWeight);
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty bones
|
||||
unsigned int writeBone = 0;
|
||||
|
||||
for (unsigned int readBone = 0; readBone< pMesh->mNumBones; ++readBone)
|
||||
{
|
||||
aiBone* bone = pMesh->mBones[readBone];
|
||||
if (bone->mNumWeights > 0)
|
||||
{
|
||||
pMesh->mBones[writeBone++] = bone;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete bone;
|
||||
}
|
||||
}
|
||||
pMesh->mNumBones = writeBone;
|
||||
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
/** @file Implementation of the post processing step "MakeVerboseFormat"
|
||||
*/
|
||||
|
||||
|
||||
#include "MakeVerboseFormat.h"
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
|
@ -51,26 +50,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MakeVerboseFormatProcess::MakeVerboseFormatProcess()
|
||||
{
|
||||
MakeVerboseFormatProcess::MakeVerboseFormatProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
MakeVerboseFormatProcess::~MakeVerboseFormatProcess()
|
||||
{
|
||||
MakeVerboseFormatProcess::~MakeVerboseFormatProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void MakeVerboseFormatProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ai_assert(NULL != pScene);
|
||||
void MakeVerboseFormatProcess::Execute(aiScene *pScene) {
|
||||
ai_assert(nullptr != pScene);
|
||||
ASSIMP_LOG_DEBUG("MakeVerboseFormatProcess begin");
|
||||
|
||||
bool bHas = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
if( MakeVerboseFormat( pScene->mMeshes[a]))
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if (MakeVerboseFormat(pScene->mMeshes[a]))
|
||||
bHas = true;
|
||||
}
|
||||
if (bHas) {
|
||||
|
|
@ -84,29 +79,26 @@ void MakeVerboseFormatProcess::Execute( aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh)
|
||||
{
|
||||
ai_assert(NULL != pcMesh);
|
||||
bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh *pcMesh) {
|
||||
ai_assert(nullptr != pcMesh);
|
||||
|
||||
unsigned int iOldNumVertices = pcMesh->mNumVertices;
|
||||
const unsigned int iNumVerts = pcMesh->mNumFaces*3;
|
||||
const unsigned int iNumVerts = pcMesh->mNumFaces * 3;
|
||||
|
||||
aiVector3D* pvPositions = new aiVector3D[ iNumVerts ];
|
||||
aiVector3D *pvPositions = new aiVector3D[iNumVerts];
|
||||
|
||||
aiVector3D* pvNormals = NULL;
|
||||
if (pcMesh->HasNormals())
|
||||
{
|
||||
aiVector3D *pvNormals = nullptr;
|
||||
if (pcMesh->HasNormals()) {
|
||||
pvNormals = new aiVector3D[iNumVerts];
|
||||
}
|
||||
aiVector3D* pvTangents = NULL, *pvBitangents = NULL;
|
||||
if (pcMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
aiVector3D *pvTangents = nullptr, *pvBitangents = nullptr;
|
||||
if (pcMesh->HasTangentsAndBitangents()) {
|
||||
pvTangents = new aiVector3D[iNumVerts];
|
||||
pvBitangents = new aiVector3D[iNumVerts];
|
||||
}
|
||||
|
||||
aiVector3D* apvTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS] = {0};
|
||||
aiColor4D* apvColorSets[AI_MAX_NUMBER_OF_COLOR_SETS] = {0};
|
||||
aiVector3D *apvTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS] = { 0 };
|
||||
aiColor4D *apvColorSets[AI_MAX_NUMBER_OF_COLOR_SETS] = { 0 };
|
||||
|
||||
unsigned int p = 0;
|
||||
while (pcMesh->HasTextureCoords(p))
|
||||
|
|
@ -117,26 +109,21 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh)
|
|||
apvColorSets[p++] = new aiColor4D[iNumVerts];
|
||||
|
||||
// allocate enough memory to hold output bones and vertex weights ...
|
||||
std::vector<aiVertexWeight>* newWeights = new std::vector<aiVertexWeight>[pcMesh->mNumBones];
|
||||
for (unsigned int i = 0;i < pcMesh->mNumBones;++i) {
|
||||
newWeights[i].reserve(pcMesh->mBones[i]->mNumWeights*3);
|
||||
std::vector<aiVertexWeight> *newWeights = new std::vector<aiVertexWeight>[pcMesh->mNumBones];
|
||||
for (unsigned int i = 0; i < pcMesh->mNumBones; ++i) {
|
||||
newWeights[i].reserve(pcMesh->mBones[i]->mNumWeights * 3);
|
||||
}
|
||||
|
||||
// iterate through all faces and build a clean list
|
||||
unsigned int iIndex = 0;
|
||||
for (unsigned int a = 0; a< pcMesh->mNumFaces;++a)
|
||||
{
|
||||
aiFace* pcFace = &pcMesh->mFaces[a];
|
||||
for (unsigned int q = 0; q < pcFace->mNumIndices;++q,++iIndex)
|
||||
{
|
||||
for (unsigned int a = 0; a < pcMesh->mNumFaces; ++a) {
|
||||
aiFace *pcFace = &pcMesh->mFaces[a];
|
||||
for (unsigned int q = 0; q < pcFace->mNumIndices; ++q, ++iIndex) {
|
||||
// need to build a clean list of bones, too
|
||||
for (unsigned int i = 0;i < pcMesh->mNumBones;++i)
|
||||
{
|
||||
for (unsigned int a = 0; a < pcMesh->mBones[i]->mNumWeights;a++)
|
||||
{
|
||||
const aiVertexWeight& w = pcMesh->mBones[i]->mWeights[a];
|
||||
if(pcFace->mIndices[q] == w.mVertexId)
|
||||
{
|
||||
for (unsigned int i = 0; i < pcMesh->mNumBones; ++i) {
|
||||
for (unsigned int boneIdx = 0; boneIdx < pcMesh->mBones[i]->mNumWeights; ++boneIdx) {
|
||||
const aiVertexWeight &w = pcMesh->mBones[i]->mWeights[boneIdx];
|
||||
if (pcFace->mIndices[q] == w.mVertexId) {
|
||||
aiVertexWeight wNew;
|
||||
wNew.mVertexId = iIndex;
|
||||
wNew.mWeight = w.mWeight;
|
||||
|
|
@ -147,45 +134,39 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh)
|
|||
|
||||
pvPositions[iIndex] = pcMesh->mVertices[pcFace->mIndices[q]];
|
||||
|
||||
if (pcMesh->HasNormals())
|
||||
{
|
||||
if (pcMesh->HasNormals()) {
|
||||
pvNormals[iIndex] = pcMesh->mNormals[pcFace->mIndices[q]];
|
||||
}
|
||||
if (pcMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
if (pcMesh->HasTangentsAndBitangents()) {
|
||||
pvTangents[iIndex] = pcMesh->mTangents[pcFace->mIndices[q]];
|
||||
pvBitangents[iIndex] = pcMesh->mBitangents[pcFace->mIndices[q]];
|
||||
}
|
||||
|
||||
unsigned int p = 0;
|
||||
while (pcMesh->HasTextureCoords(p))
|
||||
{
|
||||
apvTextureCoords[p][iIndex] = pcMesh->mTextureCoords[p][pcFace->mIndices[q]];
|
||||
++p;
|
||||
unsigned int pp = 0;
|
||||
while (pcMesh->HasTextureCoords(pp)) {
|
||||
apvTextureCoords[pp][iIndex] = pcMesh->mTextureCoords[pp][pcFace->mIndices[q]];
|
||||
++pp;
|
||||
}
|
||||
p = 0;
|
||||
while (pcMesh->HasVertexColors(p))
|
||||
{
|
||||
apvColorSets[p][iIndex] = pcMesh->mColors[p][pcFace->mIndices[q]];
|
||||
++p;
|
||||
pp = 0;
|
||||
while (pcMesh->HasVertexColors(pp)) {
|
||||
apvColorSets[pp][iIndex] = pcMesh->mColors[pp][pcFace->mIndices[q]];
|
||||
++pp;
|
||||
}
|
||||
pcFace->mIndices[q] = iIndex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// build output vertex weights
|
||||
for (unsigned int i = 0;i < pcMesh->mNumBones;++i)
|
||||
{
|
||||
delete [] pcMesh->mBones[i]->mWeights;
|
||||
for (unsigned int i = 0; i < pcMesh->mNumBones; ++i) {
|
||||
delete[] pcMesh->mBones[i]->mWeights;
|
||||
if (!newWeights[i].empty()) {
|
||||
pcMesh->mBones[i]->mWeights = new aiVertexWeight[newWeights[i].size()];
|
||||
aiVertexWeight *weightToCopy = &( newWeights[i][0] );
|
||||
pcMesh->mBones[i]->mNumWeights = static_cast<unsigned int>(newWeights[i].size());
|
||||
aiVertexWeight *weightToCopy = &(newWeights[i][0]);
|
||||
memcpy(pcMesh->mBones[i]->mWeights, weightToCopy,
|
||||
sizeof(aiVertexWeight) * newWeights[i].size());
|
||||
sizeof(aiVertexWeight) * newWeights[i].size());
|
||||
} else {
|
||||
pcMesh->mBones[i]->mWeights = NULL;
|
||||
pcMesh->mBones[i]->mWeights = nullptr;
|
||||
}
|
||||
}
|
||||
delete[] newWeights;
|
||||
|
|
@ -195,28 +176,24 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh)
|
|||
pcMesh->mVertices = pvPositions;
|
||||
|
||||
p = 0;
|
||||
while (pcMesh->HasTextureCoords(p))
|
||||
{
|
||||
while (pcMesh->HasTextureCoords(p)) {
|
||||
delete[] pcMesh->mTextureCoords[p];
|
||||
pcMesh->mTextureCoords[p] = apvTextureCoords[p];
|
||||
++p;
|
||||
}
|
||||
p = 0;
|
||||
while (pcMesh->HasVertexColors(p))
|
||||
{
|
||||
while (pcMesh->HasVertexColors(p)) {
|
||||
delete[] pcMesh->mColors[p];
|
||||
pcMesh->mColors[p] = apvColorSets[p];
|
||||
++p;
|
||||
}
|
||||
pcMesh->mNumVertices = iNumVerts;
|
||||
|
||||
if (pcMesh->HasNormals())
|
||||
{
|
||||
if (pcMesh->HasNormals()) {
|
||||
delete[] pcMesh->mNormals;
|
||||
pcMesh->mNormals = pvNormals;
|
||||
}
|
||||
if (pcMesh->HasTangentsAndBitangents())
|
||||
{
|
||||
if (pcMesh->HasTangentsAndBitangents()) {
|
||||
delete[] pcMesh->mTangents;
|
||||
pcMesh->mTangents = pvTangents;
|
||||
delete[] pcMesh->mBitangents;
|
||||
|
|
@ -225,15 +202,14 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh)
|
|||
return (pcMesh->mNumVertices != iOldNumVertices);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IsMeshInVerboseFormat(const aiMesh* mesh) {
|
||||
bool IsMeshInVerboseFormat(const aiMesh *mesh) {
|
||||
// avoid slow vector<bool> specialization
|
||||
std::vector<unsigned int> seen(mesh->mNumVertices,0);
|
||||
for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||
const aiFace& f = mesh->mFaces[i];
|
||||
for(unsigned int j = 0; j < f.mNumIndices; ++j) {
|
||||
if(++seen[f.mIndices[j]] == 2) {
|
||||
std::vector<unsigned int> seen(mesh->mNumVertices, 0);
|
||||
for (unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||
const aiFace &f = mesh->mFaces[i];
|
||||
for (unsigned int j = 0; j < f.mNumIndices; ++j) {
|
||||
if (++seen[f.mIndices[j]] == 2) {
|
||||
// found a duplicate index
|
||||
return false;
|
||||
}
|
||||
|
|
@ -244,9 +220,9 @@ bool IsMeshInVerboseFormat(const aiMesh* mesh) {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene* pScene) {
|
||||
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
if(!IsMeshInVerboseFormat(pScene->mMeshes[i])) {
|
||||
bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene *pScene) {
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
if (!IsMeshInVerboseFormat(pScene->mMeshes[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -98,7 +98,7 @@ public:
|
|||
|
||||
// -------------------------------------------------------------------
|
||||
/** Checks whether the scene is already in verbose format.
|
||||
* @param pScene The data to check.
|
||||
* @param pScene The data to check.
|
||||
* @return true if the scene is already in verbose format. */
|
||||
static bool IsVerboseFormat(const aiScene* pScene);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -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 <assimp/SceneCombiner.h>
|
||||
#include "ConvertToLHProcess.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <stdio.h>
|
||||
|
||||
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<aiNode*>& nodes) {
|
||||
nodes_in += nd->mNumChildren;
|
||||
void OptimizeGraphProcess::CollectNewChildren(aiNode *nd, std::list<aiNode *> &nodes) {
|
||||
nodes_in += nd->mNumChildren;
|
||||
|
||||
// Process children
|
||||
std::list<aiNode*> 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<aiNode *> 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<aiNode*>::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<aiNode *>::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<aiNode*> join;
|
||||
for (std::list<aiNode*>::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<aiNode *> join;
|
||||
for (std::list<aiNode *>::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_%u", count_merged++);
|
||||
|
||||
unsigned int out_meshes = 0;
|
||||
for (std::list<aiNode*>::iterator it = join.begin(); it != join.end(); ++it) {
|
||||
out_meshes += (*it)->mNumMeshes;
|
||||
}
|
||||
unsigned int out_meshes = 0;
|
||||
for (std::list<aiNode *>::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 *meshIdxs = new unsigned int[out_meshes + join_master->mNumMeshes], *tmp = meshIdxs;
|
||||
for (unsigned int n = 0; n < join_master->mNumMeshes; ++n) {
|
||||
*tmp++ = join_master->mMeshes[n];
|
||||
}
|
||||
|
||||
for (std::list<aiNode*>::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 = meshIdxs;
|
||||
join_master->mNumMeshes += out_meshes;
|
||||
}
|
||||
}
|
||||
}
|
||||
// reassign children if something changed
|
||||
if (child_nodes.empty() || child_nodes.size() > nd->mNumChildren) {
|
||||
|
||||
nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
|
||||
delete[] nd->mChildren;
|
||||
|
||||
if (nd->mChildren) {
|
||||
aiNode** tmp = nd->mChildren;
|
||||
for (std::list<aiNode*>::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<unsigned int>(child_nodes.size());
|
||||
nd->mNumChildren = static_cast<unsigned int>(child_nodes.size());
|
||||
|
||||
if (nd->mChildren) {
|
||||
aiNode **tmp = nd->mChildren;
|
||||
for (std::list<aiNode *>::iterator it = child_nodes.begin(); it != child_nodes.end(); ++it) {
|
||||
aiNode *node = *tmp++ = *it;
|
||||
node->mParent = nd;
|
||||
}
|
||||
}
|
||||
|
||||
nodes_out += static_cast<unsigned int>(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<std::string>::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<std::string>::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<aiNode*> 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<aiNode *> 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("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
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -151,7 +151,7 @@ void OptimizeMeshesProcess::Execute( aiScene* pScene)
|
|||
std::copy(output.begin(),output.end(),mScene->mMeshes);
|
||||
|
||||
if (output.size() != num_old) {
|
||||
ASSIMP_LOG_DEBUG_F("OptimizeMeshesProcess finished. Input meshes: ", num_old, ", Output meshes: ", pScene->mNumMeshes);
|
||||
ASSIMP_LOG_DEBUG("OptimizeMeshesProcess finished. Input meshes: ", num_old, ", Output meshes: ", pScene->mNumMeshes);
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG( "OptimizeMeshesProcess finished" );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -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<unsigned int>& 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<unsigned int> &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<aiMesh*>& out, aiMesh** in,
|
||||
unsigned int numIn, aiNode* node);
|
||||
// -------------------------------------------------------------------
|
||||
// Simple routine to build meshes in worldspace, no further optimization
|
||||
void BuildWCSMeshes(std::vector<aiMesh *> &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
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -43,22 +43,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
/// @file ProcessHelper.cpp
|
||||
/** Implement shared utility functions for postprocessing steps */
|
||||
|
||||
|
||||
#include "ProcessHelper.h"
|
||||
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
|
||||
{
|
||||
const char* s = in.c_str();
|
||||
void ConvertListToStrings(const std::string &in, std::list<std::string> &out) {
|
||||
const char *s = in.c_str();
|
||||
while (*s) {
|
||||
SkipSpacesAndLineEnd(&s);
|
||||
if (*s == '\'') {
|
||||
const char* base = ++s;
|
||||
const char *base = ++s;
|
||||
while (*s != '\'') {
|
||||
++s;
|
||||
if (*s == '\0') {
|
||||
|
|
@ -66,43 +63,39 @@ void ConvertListToStrings(const std::string& in, std::list<std::string>& out)
|
|||
return;
|
||||
}
|
||||
}
|
||||
out.push_back(std::string(base,(size_t)(s-base)));
|
||||
out.push_back(std::string(base, (size_t)(s - base)));
|
||||
++s;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
out.push_back(GetNextToken(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max,
|
||||
const aiMatrix4x4& m)
|
||||
{
|
||||
min = aiVector3D ( ai_real( 10e10 ), ai_real( 10e10 ), ai_real( 10e10 ) );
|
||||
max = aiVector3D ( ai_real( -10e10 ), ai_real( -10e10 ), ai_real( -10e10 ) );
|
||||
for (unsigned int i = 0;i < mesh->mNumVertices;++i)
|
||||
{
|
||||
void FindAABBTransformed(const aiMesh *mesh, aiVector3D &min, aiVector3D &max,
|
||||
const aiMatrix4x4 &m) {
|
||||
min = aiVector3D(ai_real(10e10), ai_real(10e10), ai_real(10e10));
|
||||
max = aiVector3D(ai_real(-10e10), ai_real(-10e10), ai_real(-10e10));
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
const aiVector3D v = m * mesh->mVertices[i];
|
||||
min = std::min(v,min);
|
||||
max = std::max(v,max);
|
||||
min = std::min(v, min);
|
||||
max = std::max(v, max);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max)
|
||||
{
|
||||
ArrayBounds(mesh->mVertices,mesh->mNumVertices, min,max);
|
||||
out = min + (max-min)*(ai_real)0.5;
|
||||
void FindMeshCenter(aiMesh *mesh, aiVector3D &out, aiVector3D &min, aiVector3D &max) {
|
||||
ArrayBounds(mesh->mVertices, mesh->mNumVertices, min, max);
|
||||
out = min + (max - min) * (ai_real)0.5;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max) {
|
||||
if ( NULL == scene ) {
|
||||
void FindSceneCenter(aiScene *scene, aiVector3D &out, aiVector3D &min, aiVector3D &max) {
|
||||
if (nullptr == scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 0 == scene->mNumMeshes ) {
|
||||
if (0 == scene->mNumMeshes) {
|
||||
return;
|
||||
}
|
||||
FindMeshCenter(scene->mMeshes[0], out, min, max);
|
||||
|
|
@ -116,79 +109,71 @@ void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector
|
|||
if (max[1] < tmax[1]) max[1] = tmax[1];
|
||||
if (max[2] < tmax[2]) max[2] = tmax[2];
|
||||
}
|
||||
out = min + (max-min)*(ai_real)0.5;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,
|
||||
aiVector3D& max, const aiMatrix4x4& m)
|
||||
{
|
||||
FindAABBTransformed(mesh,min,max,m);
|
||||
out = min + (max-min)*(ai_real)0.5;
|
||||
out = min + (max - min) * (ai_real)0.5;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
void FindMeshCenter (aiMesh* mesh, aiVector3D& out)
|
||||
{
|
||||
aiVector3D min,max;
|
||||
FindMeshCenter(mesh,out,min,max);
|
||||
void FindMeshCenterTransformed(aiMesh *mesh, aiVector3D &out, aiVector3D &min,
|
||||
aiVector3D &max, const aiMatrix4x4 &m) {
|
||||
FindAABBTransformed(mesh, min, max, m);
|
||||
out = min + (max - min) * (ai_real)0.5;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,
|
||||
const aiMatrix4x4& m)
|
||||
{
|
||||
aiVector3D min,max;
|
||||
FindMeshCenterTransformed(mesh,out,min,max,m);
|
||||
void FindMeshCenter(aiMesh *mesh, aiVector3D &out) {
|
||||
aiVector3D min, max;
|
||||
FindMeshCenter(mesh, out, min, max);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
ai_real ComputePositionEpsilon(const aiMesh* pMesh)
|
||||
{
|
||||
const ai_real epsilon = ai_real( 1e-4 );
|
||||
void FindMeshCenterTransformed(aiMesh *mesh, aiVector3D &out,
|
||||
const aiMatrix4x4 &m) {
|
||||
aiVector3D min, max;
|
||||
FindMeshCenterTransformed(mesh, out, min, max, m);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
ai_real ComputePositionEpsilon(const aiMesh *pMesh) {
|
||||
const ai_real epsilon = ai_real(1e-4);
|
||||
|
||||
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
||||
aiVector3D minVec, maxVec;
|
||||
ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,minVec,maxVec);
|
||||
ArrayBounds(pMesh->mVertices, pMesh->mNumVertices, minVec, maxVec);
|
||||
return (maxVec - minVec).Length() * epsilon;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num)
|
||||
{
|
||||
ai_assert( NULL != pMeshes );
|
||||
ai_real ComputePositionEpsilon(const aiMesh *const *pMeshes, size_t num) {
|
||||
ai_assert(nullptr != pMeshes);
|
||||
|
||||
const ai_real epsilon = ai_real( 1e-4 );
|
||||
const ai_real epsilon = ai_real(1e-4);
|
||||
|
||||
// calculate the position bounds so we have a reliable epsilon to check position differences against
|
||||
aiVector3D minVec, maxVec, mi, ma;
|
||||
MinMaxChooser<aiVector3D>()(minVec,maxVec);
|
||||
MinMaxChooser<aiVector3D>()(minVec, maxVec);
|
||||
|
||||
for (size_t a = 0; a < num; ++a) {
|
||||
const aiMesh* pMesh = pMeshes[a];
|
||||
ArrayBounds(pMesh->mVertices,pMesh->mNumVertices,mi,ma);
|
||||
const aiMesh *pMesh = pMeshes[a];
|
||||
ArrayBounds(pMesh->mVertices, pMesh->mNumVertices, mi, ma);
|
||||
|
||||
minVec = std::min(minVec,mi);
|
||||
maxVec = std::max(maxVec,ma);
|
||||
minVec = std::min(minVec, mi);
|
||||
maxVec = std::max(maxVec, ma);
|
||||
}
|
||||
return (maxVec - minVec).Length() * epsilon;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh)
|
||||
{
|
||||
ai_assert(NULL != pcMesh);
|
||||
unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh) {
|
||||
ai_assert(nullptr != pcMesh);
|
||||
|
||||
// FIX: the hash may never be 0. Otherwise a comparison against
|
||||
// nullptr could be successful
|
||||
unsigned int iRet = 1;
|
||||
|
||||
// normals
|
||||
if (pcMesh->HasNormals())iRet |= 0x2;
|
||||
if (pcMesh->HasNormals()) iRet |= 0x2;
|
||||
// tangents and bitangents
|
||||
if (pcMesh->HasTangentsAndBitangents())iRet |= 0x4;
|
||||
if (pcMesh->HasTangentsAndBitangents()) iRet |= 0x4;
|
||||
|
||||
#ifdef BOOST_STATIC_ASSERT
|
||||
BOOST_STATIC_ASSERT(8 >= AI_MAX_NUMBER_OF_COLOR_SETS);
|
||||
|
|
@ -197,8 +182,7 @@ unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh)
|
|||
|
||||
// texture coordinates
|
||||
unsigned int p = 0;
|
||||
while (pcMesh->HasTextureCoords(p))
|
||||
{
|
||||
while (pcMesh->HasTextureCoords(p)) {
|
||||
iRet |= (0x100 << p);
|
||||
if (3 == pcMesh->mNumUVComponents[p])
|
||||
iRet |= (0x10000 << p);
|
||||
|
|
@ -207,74 +191,32 @@ unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh)
|
|||
}
|
||||
// vertex colors
|
||||
p = 0;
|
||||
while (pcMesh->HasVertexColors(p))iRet |= (0x1000000 << p++);
|
||||
while (pcMesh->HasVertexColors(p))
|
||||
iRet |= (0x1000000 << p++);
|
||||
return iRet;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh)
|
||||
{
|
||||
VertexWeightTable *ComputeVertexBoneWeightTable(const aiMesh *pMesh) {
|
||||
if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VertexWeightTable* avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
|
||||
for (unsigned int i = 0; i < pMesh->mNumBones;++i) {
|
||||
VertexWeightTable *avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices];
|
||||
for (unsigned int i = 0; i < pMesh->mNumBones; ++i) {
|
||||
|
||||
aiBone* bone = pMesh->mBones[i];
|
||||
for (unsigned int a = 0; a < bone->mNumWeights;++a) {
|
||||
const aiVertexWeight& weight = bone->mWeights[a];
|
||||
avPerVertexWeights[weight.mVertexId].push_back( std::pair<unsigned int,float>(i,weight.mWeight) );
|
||||
aiBone *bone = pMesh->mBones[i];
|
||||
for (unsigned int a = 0; a < bone->mNumWeights; ++a) {
|
||||
const aiVertexWeight &weight = bone->mWeights[a];
|
||||
avPerVertexWeights[weight.mVertexId].push_back(std::pair<unsigned int, float>(i, weight.mWeight));
|
||||
}
|
||||
}
|
||||
return avPerVertexWeights;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
const char* TextureTypeToString(aiTextureType in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
case aiTextureType_NONE:
|
||||
return "n/a";
|
||||
case aiTextureType_DIFFUSE:
|
||||
return "Diffuse";
|
||||
case aiTextureType_SPECULAR:
|
||||
return "Specular";
|
||||
case aiTextureType_AMBIENT:
|
||||
return "Ambient";
|
||||
case aiTextureType_EMISSIVE:
|
||||
return "Emissive";
|
||||
case aiTextureType_OPACITY:
|
||||
return "Opacity";
|
||||
case aiTextureType_NORMALS:
|
||||
return "Normals";
|
||||
case aiTextureType_HEIGHT:
|
||||
return "Height";
|
||||
case aiTextureType_SHININESS:
|
||||
return "Shininess";
|
||||
case aiTextureType_DISPLACEMENT:
|
||||
return "Displacement";
|
||||
case aiTextureType_LIGHTMAP:
|
||||
return "Lightmap";
|
||||
case aiTextureType_REFLECTION:
|
||||
return "Reflection";
|
||||
case aiTextureType_UNKNOWN:
|
||||
return "Unknown";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ai_assert(false);
|
||||
return "BUG";
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
const char* MappingTypeToString(aiTextureMapping in)
|
||||
{
|
||||
switch (in)
|
||||
{
|
||||
const char *MappingTypeToString(aiTextureMapping in) {
|
||||
switch (in) {
|
||||
case aiTextureMapping_UV:
|
||||
return "UV";
|
||||
case aiTextureMapping_BOX:
|
||||
|
|
@ -292,24 +234,22 @@ const char* MappingTypeToString(aiTextureMapping in)
|
|||
}
|
||||
|
||||
ai_assert(false);
|
||||
return "BUG";
|
||||
return "BUG";
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags)
|
||||
{
|
||||
aiMesh *MakeSubmesh(const aiMesh *pMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags) {
|
||||
aiMesh *oMesh = new aiMesh();
|
||||
std::vector<unsigned int> vMap(pMesh->mNumVertices,UINT_MAX);
|
||||
std::vector<unsigned int> vMap(pMesh->mNumVertices, UINT_MAX);
|
||||
|
||||
size_t numSubVerts = 0;
|
||||
size_t numSubFaces = subMeshFaces.size();
|
||||
|
||||
for(unsigned int i=0;i<numSubFaces;i++) {
|
||||
for (unsigned int i = 0; i < numSubFaces; i++) {
|
||||
const aiFace &f = pMesh->mFaces[subMeshFaces[i]];
|
||||
|
||||
for(unsigned int j=0;j<f.mNumIndices;j++) {
|
||||
if(vMap[f.mIndices[j]]==UINT_MAX) {
|
||||
for (unsigned int j = 0; j < f.mNumIndices; j++) {
|
||||
if (vMap[f.mIndices[j]] == UINT_MAX) {
|
||||
vMap[f.mIndices[j]] = static_cast<unsigned int>(numSubVerts++);
|
||||
}
|
||||
}
|
||||
|
|
@ -325,114 +265,114 @@ aiMesh* MakeSubmesh(const aiMesh *pMesh, const std::vector<unsigned int> &subMes
|
|||
oMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
|
||||
oMesh->mNumVertices = static_cast<unsigned int>(numSubVerts);
|
||||
oMesh->mVertices = new aiVector3D[numSubVerts];
|
||||
if( pMesh->HasNormals() ) {
|
||||
if (pMesh->HasNormals()) {
|
||||
oMesh->mNormals = new aiVector3D[numSubVerts];
|
||||
}
|
||||
|
||||
if( pMesh->HasTangentsAndBitangents() ) {
|
||||
if (pMesh->HasTangentsAndBitangents()) {
|
||||
oMesh->mTangents = new aiVector3D[numSubVerts];
|
||||
oMesh->mBitangents = new aiVector3D[numSubVerts];
|
||||
}
|
||||
|
||||
for( size_t a = 0; pMesh->HasTextureCoords(static_cast<unsigned int>(a)) ; ++a ) {
|
||||
for (size_t a = 0; pMesh->HasTextureCoords(static_cast<unsigned int>(a)); ++a) {
|
||||
oMesh->mTextureCoords[a] = new aiVector3D[numSubVerts];
|
||||
oMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
|
||||
}
|
||||
|
||||
for( size_t a = 0; pMesh->HasVertexColors( static_cast<unsigned int>(a)); ++a ) {
|
||||
for (size_t a = 0; pMesh->HasVertexColors(static_cast<unsigned int>(a)); ++a) {
|
||||
oMesh->mColors[a] = new aiColor4D[numSubVerts];
|
||||
}
|
||||
|
||||
// and copy over the data, generating faces with linear indices along the way
|
||||
oMesh->mFaces = new aiFace[numSubFaces];
|
||||
|
||||
for(unsigned int a = 0; a < numSubFaces; ++a ) {
|
||||
for (unsigned int a = 0; a < numSubFaces; ++a) {
|
||||
|
||||
const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
|
||||
aiFace& dstFace = oMesh->mFaces[a];
|
||||
const aiFace &srcFace = pMesh->mFaces[subMeshFaces[a]];
|
||||
aiFace &dstFace = oMesh->mFaces[a];
|
||||
dstFace.mNumIndices = srcFace.mNumIndices;
|
||||
dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
|
||||
|
||||
// accumulate linearly all the vertices of the source face
|
||||
for( size_t b = 0; b < dstFace.mNumIndices; ++b ) {
|
||||
for (size_t b = 0; b < dstFace.mNumIndices; ++b) {
|
||||
dstFace.mIndices[b] = vMap[srcFace.mIndices[b]];
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex ) {
|
||||
for (unsigned int srcIndex = 0; srcIndex < pMesh->mNumVertices; ++srcIndex) {
|
||||
unsigned int nvi = vMap[srcIndex];
|
||||
if(nvi==UINT_MAX) {
|
||||
if (nvi == UINT_MAX) {
|
||||
continue;
|
||||
}
|
||||
|
||||
oMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
|
||||
if( pMesh->HasNormals() ) {
|
||||
if (pMesh->HasNormals()) {
|
||||
oMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
|
||||
}
|
||||
|
||||
if( pMesh->HasTangentsAndBitangents() ) {
|
||||
if (pMesh->HasTangentsAndBitangents()) {
|
||||
oMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
|
||||
oMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
|
||||
}
|
||||
for( size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c ) {
|
||||
oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
|
||||
for (size_t c = 0, cc = pMesh->GetNumUVChannels(); c < cc; ++c) {
|
||||
oMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
|
||||
}
|
||||
for( size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c ) {
|
||||
for (size_t c = 0, cc = pMesh->GetNumColorChannels(); c < cc; ++c) {
|
||||
oMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
|
||||
}
|
||||
}
|
||||
|
||||
if(~subFlags&AI_SUBMESH_FLAGS_SANS_BONES) {
|
||||
std::vector<unsigned int> subBones(pMesh->mNumBones,0);
|
||||
if (~subFlags & AI_SUBMESH_FLAGS_SANS_BONES) {
|
||||
std::vector<unsigned int> subBones(pMesh->mNumBones, 0);
|
||||
|
||||
for(unsigned int a=0;a<pMesh->mNumBones;++a) {
|
||||
const aiBone* bone = pMesh->mBones[a];
|
||||
for (unsigned int a = 0; a < pMesh->mNumBones; ++a) {
|
||||
const aiBone *bone = pMesh->mBones[a];
|
||||
|
||||
for(unsigned int b=0;b<bone->mNumWeights;b++) {
|
||||
for (unsigned int b = 0; b < bone->mNumWeights; b++) {
|
||||
unsigned int v = vMap[bone->mWeights[b].mVertexId];
|
||||
|
||||
if(v!=UINT_MAX) {
|
||||
if (v != UINT_MAX) {
|
||||
subBones[a]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(unsigned int a=0;a<pMesh->mNumBones;++a) {
|
||||
if(subBones[a]>0) {
|
||||
for (unsigned int a = 0; a < pMesh->mNumBones; ++a) {
|
||||
if (subBones[a] > 0) {
|
||||
oMesh->mNumBones++;
|
||||
}
|
||||
}
|
||||
|
||||
if(oMesh->mNumBones) {
|
||||
oMesh->mBones = new aiBone*[oMesh->mNumBones]();
|
||||
if (oMesh->mNumBones) {
|
||||
oMesh->mBones = new aiBone *[oMesh->mNumBones]();
|
||||
unsigned int nbParanoia = oMesh->mNumBones;
|
||||
|
||||
oMesh->mNumBones = 0; //rewind
|
||||
|
||||
for(unsigned int a=0;a<pMesh->mNumBones;++a) {
|
||||
if(subBones[a]==0) {
|
||||
for (unsigned int a = 0; a < pMesh->mNumBones; ++a) {
|
||||
if (subBones[a] == 0) {
|
||||
continue;
|
||||
}
|
||||
aiBone *newBone = new aiBone;
|
||||
oMesh->mBones[oMesh->mNumBones++] = newBone;
|
||||
|
||||
const aiBone* bone = pMesh->mBones[a];
|
||||
const aiBone *bone = pMesh->mBones[a];
|
||||
|
||||
newBone->mName = bone->mName;
|
||||
newBone->mOffsetMatrix = bone->mOffsetMatrix;
|
||||
newBone->mWeights = new aiVertexWeight[subBones[a]];
|
||||
|
||||
for(unsigned int b=0;b<bone->mNumWeights;b++) {
|
||||
for (unsigned int b = 0; b < bone->mNumWeights; b++) {
|
||||
const unsigned int v = vMap[bone->mWeights[b].mVertexId];
|
||||
|
||||
if(v!=UINT_MAX) {
|
||||
aiVertexWeight w(v,bone->mWeights[b].mWeight);
|
||||
if (v != UINT_MAX) {
|
||||
aiVertexWeight w(v, bone->mWeights[b].mWeight);
|
||||
newBone->mWeights[newBone->mNumWeights++] = w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ai_assert(nbParanoia==oMesh->mNumBones);
|
||||
ai_assert(nbParanoia == oMesh->mNumBones);
|
||||
(void)nbParanoia; // remove compiler warning on release build
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -43,16 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef AI_PROCESS_HELPER_H_INCLUDED
|
||||
#define AI_PROCESS_HELPER_H_INCLUDED
|
||||
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/anim.h>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include <assimp/SpatialSort.h>
|
||||
#include "Common/BaseProcess.h"
|
||||
#include <assimp/ParsingUtils.h>
|
||||
#include <assimp/SpatialSort.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
|
|
@ -63,86 +63,83 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifdef __cplusplus
|
||||
namespace std {
|
||||
|
||||
// std::min for aiVector3D
|
||||
template <typename TReal>
|
||||
inline ::aiVector3t<TReal> min (const ::aiVector3t<TReal>& a, const ::aiVector3t<TReal>& b) {
|
||||
return ::aiVector3t<TReal> (min(a.x,b.x),min(a.y,b.y),min(a.z,b.z));
|
||||
}
|
||||
// std::min for aiVector3D
|
||||
template <typename TReal>
|
||||
inline ::aiVector3t<TReal> min(const ::aiVector3t<TReal> &a, const ::aiVector3t<TReal> &b) {
|
||||
return ::aiVector3t<TReal>(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
|
||||
}
|
||||
|
||||
// std::max for aiVector3t<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiVector3t<TReal> max (const ::aiVector3t<TReal>& a, const ::aiVector3t<TReal>& b) {
|
||||
return ::aiVector3t<TReal> (max(a.x,b.x),max(a.y,b.y),max(a.z,b.z));
|
||||
}
|
||||
// std::max for aiVector3t<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiVector3t<TReal> max(const ::aiVector3t<TReal> &a, const ::aiVector3t<TReal> &b) {
|
||||
return ::aiVector3t<TReal>(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
|
||||
}
|
||||
|
||||
// std::min for aiVector2t<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiVector2t<TReal> min (const ::aiVector2t<TReal>& a, const ::aiVector2t<TReal>& b) {
|
||||
return ::aiVector2t<TReal> (min(a.x,b.x),min(a.y,b.y));
|
||||
}
|
||||
// std::min for aiVector2t<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiVector2t<TReal> min(const ::aiVector2t<TReal> &a, const ::aiVector2t<TReal> &b) {
|
||||
return ::aiVector2t<TReal>(min(a.x, b.x), min(a.y, b.y));
|
||||
}
|
||||
|
||||
// std::max for aiVector2t<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiVector2t<TReal> max (const ::aiVector2t<TReal>& a, const ::aiVector2t<TReal>& b) {
|
||||
return ::aiVector2t<TReal> (max(a.x,b.x),max(a.y,b.y));
|
||||
}
|
||||
// std::max for aiVector2t<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiVector2t<TReal> max(const ::aiVector2t<TReal> &a, const ::aiVector2t<TReal> &b) {
|
||||
return ::aiVector2t<TReal>(max(a.x, b.x), max(a.y, b.y));
|
||||
}
|
||||
|
||||
// std::min for aiColor4D
|
||||
template <typename TReal>
|
||||
inline ::aiColor4t<TReal> min (const ::aiColor4t<TReal>& a, const ::aiColor4t<TReal>& b) {
|
||||
return ::aiColor4t<TReal> (min(a.r,b.r),min(a.g,b.g),min(a.b,b.b),min(a.a,b.a));
|
||||
}
|
||||
// std::min for aiColor4D
|
||||
template <typename TReal>
|
||||
inline ::aiColor4t<TReal> min(const ::aiColor4t<TReal> &a, const ::aiColor4t<TReal> &b) {
|
||||
return ::aiColor4t<TReal>(min(a.r, b.r), min(a.g, b.g), min(a.b, b.b), min(a.a, b.a));
|
||||
}
|
||||
|
||||
// std::max for aiColor4D
|
||||
template <typename TReal>
|
||||
inline ::aiColor4t<TReal> max (const ::aiColor4t<TReal>& a, const ::aiColor4t<TReal>& b) {
|
||||
return ::aiColor4t<TReal> (max(a.r,b.r),max(a.g,b.g),max(a.b,b.b),max(a.a,b.a));
|
||||
}
|
||||
// std::max for aiColor4D
|
||||
template <typename TReal>
|
||||
inline ::aiColor4t<TReal> max(const ::aiColor4t<TReal> &a, const ::aiColor4t<TReal> &b) {
|
||||
return ::aiColor4t<TReal>(max(a.r, b.r), max(a.g, b.g), max(a.b, b.b), max(a.a, b.a));
|
||||
}
|
||||
|
||||
// std::min for aiQuaterniont<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiQuaterniont<TReal> min(const ::aiQuaterniont<TReal> &a, const ::aiQuaterniont<TReal> &b) {
|
||||
return ::aiQuaterniont<TReal>(min(a.w, b.w), min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
|
||||
}
|
||||
|
||||
// std::min for aiQuaterniont<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiQuaterniont<TReal> min (const ::aiQuaterniont<TReal>& a, const ::aiQuaterniont<TReal>& b) {
|
||||
return ::aiQuaterniont<TReal> (min(a.w,b.w),min(a.x,b.x),min(a.y,b.y),min(a.z,b.z));
|
||||
}
|
||||
// std::max for aiQuaterniont<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiQuaterniont<TReal> max(const ::aiQuaterniont<TReal> &a, const ::aiQuaterniont<TReal> &b) {
|
||||
return ::aiQuaterniont<TReal>(max(a.w, b.w), max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
|
||||
}
|
||||
|
||||
// std::max for aiQuaterniont<TReal>
|
||||
template <typename TReal>
|
||||
inline ::aiQuaterniont<TReal> max (const ::aiQuaterniont<TReal>& a, const ::aiQuaterniont<TReal>& b) {
|
||||
return ::aiQuaterniont<TReal> (max(a.w,b.w),max(a.x,b.x),max(a.y,b.y),max(a.z,b.z));
|
||||
}
|
||||
// std::min for aiVectorKey
|
||||
inline ::aiVectorKey min(const ::aiVectorKey &a, const ::aiVectorKey &b) {
|
||||
return ::aiVectorKey(min(a.mTime, b.mTime), min(a.mValue, b.mValue));
|
||||
}
|
||||
|
||||
// std::max for aiVectorKey
|
||||
inline ::aiVectorKey max(const ::aiVectorKey &a, const ::aiVectorKey &b) {
|
||||
return ::aiVectorKey(max(a.mTime, b.mTime), max(a.mValue, b.mValue));
|
||||
}
|
||||
|
||||
// std::min for aiQuatKey
|
||||
inline ::aiQuatKey min(const ::aiQuatKey &a, const ::aiQuatKey &b) {
|
||||
return ::aiQuatKey(min(a.mTime, b.mTime), min(a.mValue, b.mValue));
|
||||
}
|
||||
|
||||
// std::min for aiVectorKey
|
||||
inline ::aiVectorKey min (const ::aiVectorKey& a, const ::aiVectorKey& b) {
|
||||
return ::aiVectorKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue));
|
||||
}
|
||||
// std::max for aiQuatKey
|
||||
inline ::aiQuatKey max(const ::aiQuatKey &a, const ::aiQuatKey &b) {
|
||||
return ::aiQuatKey(max(a.mTime, b.mTime), max(a.mValue, b.mValue));
|
||||
}
|
||||
|
||||
// std::max for aiVectorKey
|
||||
inline ::aiVectorKey max (const ::aiVectorKey& a, const ::aiVectorKey& b) {
|
||||
return ::aiVectorKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue));
|
||||
}
|
||||
// std::min for aiVertexWeight
|
||||
inline ::aiVertexWeight min(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
|
||||
return ::aiVertexWeight(min(a.mVertexId, b.mVertexId),static_cast<ai_real>(min(a.mWeight, b.mWeight)));
|
||||
}
|
||||
|
||||
// std::min for aiQuatKey
|
||||
inline ::aiQuatKey min (const ::aiQuatKey& a, const ::aiQuatKey& b) {
|
||||
return ::aiQuatKey (min(a.mTime,b.mTime),min(a.mValue,b.mValue));
|
||||
}
|
||||
|
||||
// std::max for aiQuatKey
|
||||
inline ::aiQuatKey max (const ::aiQuatKey& a, const ::aiQuatKey& b) {
|
||||
return ::aiQuatKey (max(a.mTime,b.mTime),max(a.mValue,b.mValue));
|
||||
}
|
||||
|
||||
// std::min for aiVertexWeight
|
||||
inline ::aiVertexWeight min (const ::aiVertexWeight& a, const ::aiVertexWeight& b) {
|
||||
return ::aiVertexWeight (min(a.mVertexId,b.mVertexId),min(a.mWeight,b.mWeight));
|
||||
}
|
||||
|
||||
// std::max for aiVertexWeight
|
||||
inline ::aiVertexWeight max (const ::aiVertexWeight& a, const ::aiVertexWeight& b) {
|
||||
return ::aiVertexWeight (max(a.mVertexId,b.mVertexId),max(a.mWeight,b.mWeight));
|
||||
}
|
||||
// std::max for aiVertexWeight
|
||||
inline ::aiVertexWeight max(const ::aiVertexWeight &a, const ::aiVertexWeight &b) {
|
||||
return ::aiVertexWeight(max(a.mVertexId, b.mVertexId), static_cast<ai_real>(max(a.mWeight, b.mWeight)));
|
||||
}
|
||||
|
||||
} // end namespace std
|
||||
#endif // !! C++
|
||||
|
|
@ -154,60 +151,80 @@ namespace Assimp {
|
|||
template <typename T>
|
||||
struct MinMaxChooser;
|
||||
|
||||
template <> struct MinMaxChooser<float> {
|
||||
void operator ()(float& min,float& max) {
|
||||
template <>
|
||||
struct MinMaxChooser<float> {
|
||||
void operator()(float &min, float &max) {
|
||||
max = -1e10f;
|
||||
min = 1e10f;
|
||||
}};
|
||||
template <> struct MinMaxChooser<double> {
|
||||
void operator ()(double& min,double& max) {
|
||||
min = 1e10f;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct MinMaxChooser<double> {
|
||||
void operator()(double &min, double &max) {
|
||||
max = -1e10;
|
||||
min = 1e10;
|
||||
}};
|
||||
template <> struct MinMaxChooser<unsigned int> {
|
||||
void operator ()(unsigned int& min,unsigned int& max) {
|
||||
min = 1e10;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct MinMaxChooser<unsigned int> {
|
||||
void operator()(unsigned int &min, unsigned int &max) {
|
||||
max = 0;
|
||||
min = (1u<<(sizeof(unsigned int)*8-1));
|
||||
}};
|
||||
min = (1u << (sizeof(unsigned int) * 8 - 1));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct MinMaxChooser< aiVector3t<T> > {
|
||||
void operator ()(aiVector3t<T>& min,aiVector3t<T>& max) {
|
||||
max = aiVector3t<T>(-1e10f,-1e10f,-1e10f);
|
||||
min = aiVector3t<T>( 1e10f, 1e10f, 1e10f);
|
||||
}};
|
||||
template <typename T> struct MinMaxChooser< aiVector2t<T> > {
|
||||
void operator ()(aiVector2t<T>& min,aiVector2t<T>& max) {
|
||||
max = aiVector2t<T>(-1e10f,-1e10f);
|
||||
min = aiVector2t<T>( 1e10f, 1e10f);
|
||||
}};
|
||||
template <typename T> struct MinMaxChooser< aiColor4t<T> > {
|
||||
void operator ()(aiColor4t<T>& min,aiColor4t<T>& max) {
|
||||
max = aiColor4t<T>(-1e10f,-1e10f,-1e10f,-1e10f);
|
||||
min = aiColor4t<T>( 1e10f, 1e10f, 1e10f, 1e10f);
|
||||
}};
|
||||
template <typename T>
|
||||
struct MinMaxChooser<aiVector3t<T>> {
|
||||
void operator()(aiVector3t<T> &min, aiVector3t<T> &max) {
|
||||
max = aiVector3t<T>(-1e10f, -1e10f, -1e10f);
|
||||
min = aiVector3t<T>(1e10f, 1e10f, 1e10f);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct MinMaxChooser<aiVector2t<T>> {
|
||||
void operator()(aiVector2t<T> &min, aiVector2t<T> &max) {
|
||||
max = aiVector2t<T>(-1e10f, -1e10f);
|
||||
min = aiVector2t<T>(1e10f, 1e10f);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct MinMaxChooser<aiColor4t<T>> {
|
||||
void operator()(aiColor4t<T> &min, aiColor4t<T> &max) {
|
||||
max = aiColor4t<T>(-1e10f, -1e10f, -1e10f, -1e10f);
|
||||
min = aiColor4t<T>(1e10f, 1e10f, 1e10f, 1e10f);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct MinMaxChooser< aiQuaterniont<T> > {
|
||||
void operator ()(aiQuaterniont<T>& min,aiQuaterniont<T>& max) {
|
||||
max = aiQuaterniont<T>(-1e10f,-1e10f,-1e10f,-1e10f);
|
||||
min = aiQuaterniont<T>( 1e10f, 1e10f, 1e10f, 1e10f);
|
||||
}};
|
||||
template <typename T>
|
||||
struct MinMaxChooser<aiQuaterniont<T>> {
|
||||
void operator()(aiQuaterniont<T> &min, aiQuaterniont<T> &max) {
|
||||
max = aiQuaterniont<T>(-1e10f, -1e10f, -1e10f, -1e10f);
|
||||
min = aiQuaterniont<T>(1e10f, 1e10f, 1e10f, 1e10f);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MinMaxChooser<aiVectorKey> {
|
||||
void operator ()(aiVectorKey& min,aiVectorKey& max) {
|
||||
MinMaxChooser<double>()(min.mTime,max.mTime);
|
||||
MinMaxChooser<aiVector3D>()(min.mValue,max.mValue);
|
||||
}};
|
||||
template <> struct MinMaxChooser<aiQuatKey> {
|
||||
void operator ()(aiQuatKey& min,aiQuatKey& max) {
|
||||
MinMaxChooser<double>()(min.mTime,max.mTime);
|
||||
MinMaxChooser<aiQuaternion>()(min.mValue,max.mValue);
|
||||
}};
|
||||
template <>
|
||||
struct MinMaxChooser<aiVectorKey> {
|
||||
void operator()(aiVectorKey &min, aiVectorKey &max) {
|
||||
MinMaxChooser<double>()(min.mTime, max.mTime);
|
||||
MinMaxChooser<aiVector3D>()(min.mValue, max.mValue);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct MinMaxChooser<aiQuatKey> {
|
||||
void operator()(aiQuatKey &min, aiQuatKey &max) {
|
||||
MinMaxChooser<double>()(min.mTime, max.mTime);
|
||||
MinMaxChooser<aiQuaternion>()(min.mValue, max.mValue);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MinMaxChooser<aiVertexWeight> {
|
||||
void operator ()(aiVertexWeight& min,aiVertexWeight& max) {
|
||||
MinMaxChooser<unsigned int>()(min.mVertexId,max.mVertexId);
|
||||
MinMaxChooser<float>()(min.mWeight,max.mWeight);
|
||||
}};
|
||||
template <>
|
||||
struct MinMaxChooser<aiVertexWeight> {
|
||||
void operator()(aiVertexWeight &min, aiVertexWeight &max) {
|
||||
MinMaxChooser<unsigned int>()(min.mVertexId, max.mVertexId);
|
||||
MinMaxChooser<ai_real>()(min.mWeight, max.mWeight);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** @brief Find the min/max values of an array of Ts
|
||||
|
|
@ -217,36 +234,31 @@ template <> struct MinMaxChooser<aiVertexWeight> {
|
|||
* @param[out] max maximum value
|
||||
*/
|
||||
template <typename T>
|
||||
inline void ArrayBounds(const T* in, unsigned int size, T& min, T& max)
|
||||
{
|
||||
MinMaxChooser<T> ()(min,max);
|
||||
for (unsigned int i = 0; i < size;++i) {
|
||||
min = std::min(in[i],min);
|
||||
max = std::max(in[i],max);
|
||||
inline void ArrayBounds(const T *in, unsigned int size, T &min, T &max) {
|
||||
MinMaxChooser<T>()(min, max);
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
min = std::min(in[i], min);
|
||||
max = std::max(in[i], max);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** Little helper function to calculate the quadratic difference
|
||||
* of two colours.
|
||||
* of two colors.
|
||||
* @param pColor1 First color
|
||||
* @param pColor2 second color
|
||||
* @return Quadratic color difference */
|
||||
inline ai_real GetColorDifference( const aiColor4D& pColor1, const aiColor4D& pColor2)
|
||||
{
|
||||
const aiColor4D c (pColor1.r - pColor2.r, pColor1.g - pColor2.g, pColor1.b - pColor2.b, pColor1.a - pColor2.a);
|
||||
return c.r*c.r + c.g*c.g + c.b*c.b + c.a*c.a;
|
||||
inline ai_real GetColorDifference(const aiColor4D &pColor1, const aiColor4D &pColor2) {
|
||||
const aiColor4D c(pColor1.r - pColor2.r, pColor1.g - pColor2.g, pColor1.b - pColor2.b, pColor1.a - pColor2.a);
|
||||
return c.r * c.r + c.g * c.g + c.b * c.b + c.a * c.a;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** @brief Extract single strings from a list of identifiers
|
||||
* @param in Input string list.
|
||||
* @param out Receives a list of clean output strings
|
||||
* @sdee #AI_CONFIG_PP_OG_EXCLUDE_LIST */
|
||||
void ConvertListToStrings(const std::string& in, std::list<std::string>& out);
|
||||
|
||||
void ConvertListToStrings(const std::string &in, std::list<std::string> &out);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** @brief Compute the AABB of a mesh after applying a given transform
|
||||
|
|
@ -254,8 +266,7 @@ void ConvertListToStrings(const std::string& in, std::list<std::string>& out);
|
|||
* @param[out] min Receives minimum transformed vertex
|
||||
* @param[out] max Receives maximum transformed vertex
|
||||
* @param m Transformation matrix to be applied */
|
||||
void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max, const aiMatrix4x4& m);
|
||||
|
||||
void FindAABBTransformed(const aiMesh *mesh, aiVector3D &min, aiVector3D &max, const aiMatrix4x4 &m);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** @brief Helper function to determine the 'real' center of a mesh
|
||||
|
|
@ -265,7 +276,7 @@ void FindAABBTransformed (const aiMesh* mesh, aiVector3D& min, aiVector3D& max,
|
|||
* @param[out] min Minimum vertex of the mesh
|
||||
* @param[out] max maximum vertex of the mesh
|
||||
* @param[out] out Center point */
|
||||
void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D& max);
|
||||
void FindMeshCenter(aiMesh *mesh, aiVector3D &out, aiVector3D &min, aiVector3D &max);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/** @brief Helper function to determine the 'real' center of a scene
|
||||
|
|
@ -275,112 +286,91 @@ void FindMeshCenter (aiMesh* mesh, aiVector3D& out, aiVector3D& min, aiVector3D&
|
|||
* @param[out] min Minimum vertex of the scene
|
||||
* @param[out] max maximum vertex of the scene
|
||||
* @param[out] out Center point */
|
||||
void FindSceneCenter (aiScene* scene, aiVector3D& out, aiVector3D& min, aiVector3D& max);
|
||||
|
||||
void FindSceneCenter(aiScene *scene, aiVector3D &out, aiVector3D &min, aiVector3D &max);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Helper function to determine the 'real' center of a mesh after applying a given transform
|
||||
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out, aiVector3D& min,aiVector3D& max, const aiMatrix4x4& m);
|
||||
|
||||
void FindMeshCenterTransformed(aiMesh *mesh, aiVector3D &out, aiVector3D &min, aiVector3D &max, const aiMatrix4x4 &m);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Helper function to determine the 'real' center of a mesh
|
||||
void FindMeshCenter (aiMesh* mesh, aiVector3D& out);
|
||||
|
||||
void FindMeshCenter(aiMesh *mesh, aiVector3D &out);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Helper function to determine the 'real' center of a mesh after applying a given transform
|
||||
void FindMeshCenterTransformed (aiMesh* mesh, aiVector3D& out,const aiMatrix4x4& m);
|
||||
|
||||
void FindMeshCenterTransformed(aiMesh *mesh, aiVector3D &out, const aiMatrix4x4 &m);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Compute a good epsilon value for position comparisons on a mesh
|
||||
ai_real ComputePositionEpsilon(const aiMesh* pMesh);
|
||||
|
||||
ai_real ComputePositionEpsilon(const aiMesh *pMesh);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Compute a good epsilon value for position comparisons on a array of meshes
|
||||
ai_real ComputePositionEpsilon(const aiMesh* const* pMeshes, size_t num);
|
||||
|
||||
ai_real ComputePositionEpsilon(const aiMesh *const *pMeshes, size_t num);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Compute an unique value for the vertex format of a mesh
|
||||
unsigned int GetMeshVFormatUnique(const aiMesh* pcMesh);
|
||||
|
||||
unsigned int GetMeshVFormatUnique(const aiMesh *pcMesh);
|
||||
|
||||
// defs for ComputeVertexBoneWeightTable()
|
||||
typedef std::pair <unsigned int,float> PerVertexWeight;
|
||||
typedef std::vector <PerVertexWeight> VertexWeightTable;
|
||||
using PerVertexWeight = std::pair<unsigned int, float>;
|
||||
using VertexWeightTable = std::vector<PerVertexWeight>;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Compute a per-vertex bone weight table
|
||||
VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Get a string for a given aiTextureType
|
||||
const char* TextureTypeToString(aiTextureType in);
|
||||
|
||||
VertexWeightTable *ComputeVertexBoneWeightTable(const aiMesh *pMesh);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Get a string for a given aiTextureMapping
|
||||
const char* MappingTypeToString(aiTextureMapping in);
|
||||
|
||||
const char *MappingTypeToString(aiTextureMapping in);
|
||||
|
||||
// flags for MakeSubmesh()
|
||||
#define AI_SUBMESH_FLAGS_SANS_BONES 0x1
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Split a mesh given a list of faces to be contained in the sub mesh
|
||||
aiMesh* MakeSubmesh(const aiMesh *superMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags);
|
||||
aiMesh *MakeSubmesh(const aiMesh *superMesh, const std::vector<unsigned int> &subMeshFaces, unsigned int subFlags);
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// Utility postprocess step to share the spatial sort tree between
|
||||
// Utility post-process step to share the spatial sort tree between
|
||||
// all steps which use it to speedup its computations.
|
||||
class ComputeSpatialSortProcess : public BaseProcess
|
||||
{
|
||||
bool IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return NULL != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
|
||||
aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
|
||||
class ComputeSpatialSortProcess : public BaseProcess {
|
||||
bool IsActive(unsigned int pFlags) const {
|
||||
return nullptr != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
|
||||
aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
|
||||
}
|
||||
|
||||
void Execute( aiScene* pScene)
|
||||
{
|
||||
void Execute(aiScene *pScene) {
|
||||
typedef std::pair<SpatialSort, ai_real> _Type;
|
||||
ASSIMP_LOG_DEBUG("Generate spatially-sorted vertex cache");
|
||||
|
||||
std::vector<_Type>* p = new std::vector<_Type>(pScene->mNumMeshes);
|
||||
std::vector<_Type> *p = new std::vector<_Type>(pScene->mNumMeshes);
|
||||
std::vector<_Type>::iterator it = p->begin();
|
||||
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i, ++it) {
|
||||
aiMesh* mesh = pScene->mMeshes[i];
|
||||
_Type& blubb = *it;
|
||||
blubb.first.Fill(mesh->mVertices,mesh->mNumVertices,sizeof(aiVector3D));
|
||||
aiMesh *mesh = pScene->mMeshes[i];
|
||||
_Type &blubb = *it;
|
||||
blubb.first.Fill(mesh->mVertices, mesh->mNumVertices, sizeof(aiVector3D));
|
||||
blubb.second = ComputePositionEpsilon(mesh);
|
||||
}
|
||||
|
||||
shared->AddProperty(AI_SPP_SPATIAL_SORT,p);
|
||||
shared->AddProperty(AI_SPP_SPATIAL_SORT, p);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
// ... and the same again to cleanup the whole stuff
|
||||
class DestroySpatialSortProcess : public BaseProcess
|
||||
{
|
||||
bool IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return NULL != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
|
||||
aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
|
||||
class DestroySpatialSortProcess : public BaseProcess {
|
||||
bool IsActive(unsigned int pFlags) const {
|
||||
return nullptr != shared && 0 != (pFlags & (aiProcess_CalcTangentSpace |
|
||||
aiProcess_GenNormals | aiProcess_JoinIdenticalVertices));
|
||||
}
|
||||
|
||||
void Execute( aiScene* /*pScene*/)
|
||||
{
|
||||
void Execute(aiScene * /*pScene*/) {
|
||||
shared->RemoveProperty(AI_SPP_SPATIAL_SORT);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Assimp
|
||||
|
||||
|
||||
} // ! namespace Assimp
|
||||
#endif // !! AI_PROCESS_HELPER_H_INCLUDED
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/ParsingUtils.h>
|
||||
#include "ProcessHelper.h"
|
||||
#include "Material/MaterialSystem.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
|
@ -122,7 +123,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
|
|||
|
||||
// Keep this material even if no mesh references it
|
||||
abReferenced[i] = true;
|
||||
ASSIMP_LOG_DEBUG_F( "Found positive match in exclusion list: \'", name.data, "\'");
|
||||
ASSIMP_LOG_VERBOSE_DEBUG( "Found positive match in exclusion list: \'", name.data, "\'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -171,6 +172,8 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
|
|||
}
|
||||
// If the new material count differs from the original,
|
||||
// we need to rebuild the material list and remap mesh material indexes.
|
||||
if(iNewNum < 1)
|
||||
throw DeadlyImportError("No materials remaining");
|
||||
if (iNewNum != pScene->mNumMaterials) {
|
||||
ai_assert(iNewNum > 0);
|
||||
aiMaterial** ppcMaterials = new aiMaterial*[iNewNum];
|
||||
|
|
@ -197,7 +200,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
|
|||
// update all material indices
|
||||
for (unsigned int p = 0; p < pScene->mNumMeshes;++p) {
|
||||
aiMesh* mesh = pScene->mMeshes[p];
|
||||
ai_assert( NULL!=mesh );
|
||||
ai_assert(nullptr != mesh);
|
||||
mesh->mMaterialIndex = aiMappingTable[mesh->mMaterialIndex];
|
||||
}
|
||||
// delete the old material list
|
||||
|
|
@ -215,7 +218,7 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene)
|
|||
}
|
||||
else
|
||||
{
|
||||
ASSIMP_LOG_INFO_F("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
|
||||
ASSIMP_LOG_INFO("RemoveRedundantMatsProcess finished. Removed ", redundantRemoved, " redundant and ",
|
||||
unreferencedRemoved, " unused materials.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -81,7 +81,7 @@ public:
|
|||
/** @brief Set list of fixed (inmutable) materials
|
||||
* @param fixed See #AI_CONFIG_PP_RRM_EXCLUDE_LIST
|
||||
*/
|
||||
void SetFixedMaterialsString(const std::string& fixed = "") {
|
||||
void SetFixedMaterialsString(const std::string& fixed = std::string()) {
|
||||
mConfigFixedMaterials = fixed;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -44,43 +44,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* any parts of the mesh structure from the imported data.
|
||||
*/
|
||||
|
||||
|
||||
#include "RemoveVCProcess.h"
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
RemoveVCProcess::RemoveVCProcess() :
|
||||
configDeleteFlags()
|
||||
, mScene()
|
||||
{}
|
||||
configDeleteFlags(), mScene() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
RemoveVCProcess::~RemoveVCProcess()
|
||||
{}
|
||||
RemoveVCProcess::~RemoveVCProcess() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool RemoveVCProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
bool RemoveVCProcess::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_RemoveComponent) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Small helper function to delete all elements in a T** aray using delete
|
||||
// Small helper function to delete all elements in a T** array using delete
|
||||
template <typename T>
|
||||
inline void ArrayDelete(T**& in, unsigned int& num)
|
||||
{
|
||||
inline void ArrayDelete(T **&in, unsigned int &num) {
|
||||
for (unsigned int i = 0; i < num; ++i)
|
||||
delete in[i];
|
||||
|
||||
delete[] in;
|
||||
in = NULL;
|
||||
in = nullptr;
|
||||
num = 0;
|
||||
}
|
||||
|
||||
|
|
@ -108,9 +102,9 @@ bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root)
|
|||
{
|
||||
childsOfParent.insert(childsOfParent.end(),mine.begin(),mine.end());
|
||||
|
||||
// set all children to NULL to make sure they are not deleted when we delete ourself
|
||||
// set all children to nullptr to make sure they are not deleted when we delete ourself
|
||||
for (unsigned int i = 0; i < node->mNumChildren;++i)
|
||||
node->mChildren[i] = NULL;
|
||||
node->mChildren[i] = nullptr;
|
||||
}
|
||||
b = true;
|
||||
delete node;
|
||||
|
|
@ -143,86 +137,74 @@ bool UpdateNodeGraph(aiNode* node,std::list<aiNode*>& childsOfParent,bool root)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void RemoveVCProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
void RemoveVCProcess::Execute(aiScene *pScene) {
|
||||
ASSIMP_LOG_DEBUG("RemoveVCProcess begin");
|
||||
bool bHas = false; //,bMasked = false;
|
||||
|
||||
mScene = pScene;
|
||||
|
||||
// handle animations
|
||||
if ( configDeleteFlags & aiComponent_ANIMATIONS)
|
||||
{
|
||||
if (configDeleteFlags & aiComponent_ANIMATIONS) {
|
||||
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mAnimations,pScene->mNumAnimations);
|
||||
ArrayDelete(pScene->mAnimations, pScene->mNumAnimations);
|
||||
}
|
||||
|
||||
// handle textures
|
||||
if ( configDeleteFlags & aiComponent_TEXTURES)
|
||||
{
|
||||
if (configDeleteFlags & aiComponent_TEXTURES) {
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mTextures,pScene->mNumTextures);
|
||||
ArrayDelete(pScene->mTextures, pScene->mNumTextures);
|
||||
}
|
||||
|
||||
// handle materials
|
||||
if ( configDeleteFlags & aiComponent_MATERIALS && pScene->mNumMaterials)
|
||||
{
|
||||
if (configDeleteFlags & aiComponent_MATERIALS && pScene->mNumMaterials) {
|
||||
bHas = true;
|
||||
for (unsigned int i = 1;i < pScene->mNumMaterials;++i)
|
||||
for (unsigned int i = 1; i < pScene->mNumMaterials; ++i)
|
||||
delete pScene->mMaterials[i];
|
||||
|
||||
pScene->mNumMaterials = 1;
|
||||
aiMaterial* helper = (aiMaterial*) pScene->mMaterials[0];
|
||||
ai_assert(NULL != helper);
|
||||
aiMaterial *helper = (aiMaterial *)pScene->mMaterials[0];
|
||||
ai_assert(nullptr != helper);
|
||||
helper->Clear();
|
||||
|
||||
// gray
|
||||
aiColor3D clr(0.6f,0.6f,0.6f);
|
||||
helper->AddProperty(&clr,1,AI_MATKEY_COLOR_DIFFUSE);
|
||||
aiColor3D clr(0.6f, 0.6f, 0.6f);
|
||||
helper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
|
||||
// add a small ambient color value
|
||||
clr = aiColor3D(0.05f,0.05f,0.05f);
|
||||
helper->AddProperty(&clr,1,AI_MATKEY_COLOR_AMBIENT);
|
||||
clr = aiColor3D(0.05f, 0.05f, 0.05f);
|
||||
helper->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT);
|
||||
|
||||
aiString s;
|
||||
s.Set("Dummy_MaterialsRemoved");
|
||||
helper->AddProperty(&s,AI_MATKEY_NAME);
|
||||
helper->AddProperty(&s, AI_MATKEY_NAME);
|
||||
}
|
||||
|
||||
// handle light sources
|
||||
if ( configDeleteFlags & aiComponent_LIGHTS)
|
||||
{
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mLights,pScene->mNumLights);
|
||||
if (configDeleteFlags & aiComponent_LIGHTS) {
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mLights, pScene->mNumLights);
|
||||
}
|
||||
|
||||
// handle camneras
|
||||
if ( configDeleteFlags & aiComponent_CAMERAS)
|
||||
{
|
||||
if (configDeleteFlags & aiComponent_CAMERAS) {
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mCameras,pScene->mNumCameras);
|
||||
ArrayDelete(pScene->mCameras, pScene->mNumCameras);
|
||||
}
|
||||
|
||||
// handle meshes
|
||||
if (configDeleteFlags & aiComponent_MESHES)
|
||||
{
|
||||
if (configDeleteFlags & aiComponent_MESHES) {
|
||||
bHas = true;
|
||||
ArrayDelete(pScene->mMeshes,pScene->mNumMeshes);
|
||||
}
|
||||
else
|
||||
{
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; a++)
|
||||
{
|
||||
if( ProcessMesh( pScene->mMeshes[a]))
|
||||
ArrayDelete(pScene->mMeshes, pScene->mNumMeshes);
|
||||
} else {
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if (ProcessMesh(pScene->mMeshes[a]))
|
||||
bHas = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// now check whether the result is still a full scene
|
||||
if (!pScene->mNumMeshes || !pScene->mNumMaterials)
|
||||
{
|
||||
if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
|
||||
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
||||
ASSIMP_LOG_DEBUG("Setting AI_SCENE_FLAGS_INCOMPLETE flag");
|
||||
|
||||
|
|
@ -240,63 +222,55 @@ void RemoveVCProcess::Execute( aiScene* pScene)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setup configuration properties for the step
|
||||
void RemoveVCProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
configDeleteFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,0x0);
|
||||
if (!configDeleteFlags)
|
||||
{
|
||||
void RemoveVCProcess::SetupProperties(const Importer *pImp) {
|
||||
configDeleteFlags = pImp->GetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS, 0x0);
|
||||
if (!configDeleteFlags) {
|
||||
ASSIMP_LOG_WARN("RemoveVCProcess: AI_CONFIG_PP_RVC_FLAGS is zero.");
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh)
|
||||
{
|
||||
bool RemoveVCProcess::ProcessMesh(aiMesh *pMesh) {
|
||||
bool ret = false;
|
||||
|
||||
// if all materials have been deleted let the material
|
||||
// index of the mesh point to the created default material
|
||||
if ( configDeleteFlags & aiComponent_MATERIALS)
|
||||
if (configDeleteFlags & aiComponent_MATERIALS)
|
||||
pMesh->mMaterialIndex = 0;
|
||||
|
||||
// handle normals
|
||||
if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals)
|
||||
{
|
||||
if (configDeleteFlags & aiComponent_NORMALS && pMesh->mNormals) {
|
||||
delete[] pMesh->mNormals;
|
||||
pMesh->mNormals = NULL;
|
||||
pMesh->mNormals = nullptr;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// handle tangents and bitangents
|
||||
if (configDeleteFlags & aiComponent_TANGENTS_AND_BITANGENTS && pMesh->mTangents)
|
||||
{
|
||||
if (configDeleteFlags & aiComponent_TANGENTS_AND_BITANGENTS && pMesh->mTangents) {
|
||||
delete[] pMesh->mTangents;
|
||||
pMesh->mTangents = NULL;
|
||||
pMesh->mTangents = nullptr;
|
||||
|
||||
delete[] pMesh->mBitangents;
|
||||
pMesh->mBitangents = NULL;
|
||||
pMesh->mBitangents = nullptr;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
// handle texture coordinates
|
||||
bool b = (0 != (configDeleteFlags & aiComponent_TEXCOORDS));
|
||||
for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++real)
|
||||
{
|
||||
if (!pMesh->mTextureCoords[i])break;
|
||||
if (configDeleteFlags & aiComponent_TEXCOORDSn(real) || b)
|
||||
{
|
||||
delete [] pMesh->mTextureCoords[i];
|
||||
pMesh->mTextureCoords[i] = NULL;
|
||||
for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++real) {
|
||||
if (!pMesh->mTextureCoords[i]) break;
|
||||
if (configDeleteFlags & aiComponent_TEXCOORDSn(real) || b) {
|
||||
delete[] pMesh->mTextureCoords[i];
|
||||
pMesh->mTextureCoords[i] = nullptr;
|
||||
ret = true;
|
||||
|
||||
if (!b)
|
||||
{
|
||||
if (!b) {
|
||||
// collapse the rest of the array
|
||||
for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a)
|
||||
pMesh->mTextureCoords[a-1] = pMesh->mTextureCoords[a];
|
||||
for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a)
|
||||
pMesh->mTextureCoords[a - 1] = pMesh->mTextureCoords[a];
|
||||
|
||||
pMesh->mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS-1] = NULL;
|
||||
pMesh->mTextureCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS - 1] = nullptr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -305,22 +279,19 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh)
|
|||
|
||||
// handle vertex colors
|
||||
b = (0 != (configDeleteFlags & aiComponent_COLORS));
|
||||
for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_COLOR_SETS; ++real)
|
||||
{
|
||||
if (!pMesh->mColors[i])break;
|
||||
if (configDeleteFlags & aiComponent_COLORSn(i) || b)
|
||||
{
|
||||
delete [] pMesh->mColors[i];
|
||||
pMesh->mColors[i] = NULL;
|
||||
for (unsigned int i = 0, real = 0; real < AI_MAX_NUMBER_OF_COLOR_SETS; ++real) {
|
||||
if (!pMesh->mColors[i]) break;
|
||||
if (configDeleteFlags & aiComponent_COLORSn(i) || b) {
|
||||
delete[] pMesh->mColors[i];
|
||||
pMesh->mColors[i] = nullptr;
|
||||
ret = true;
|
||||
|
||||
if (!b)
|
||||
{
|
||||
if (!b) {
|
||||
// collapse the rest of the array
|
||||
for (unsigned int a = i+1; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a)
|
||||
pMesh->mColors[a-1] = pMesh->mColors[a];
|
||||
for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a)
|
||||
pMesh->mColors[a - 1] = pMesh->mColors[a];
|
||||
|
||||
pMesh->mColors[AI_MAX_NUMBER_OF_COLOR_SETS-1] = NULL;
|
||||
pMesh->mColors[AI_MAX_NUMBER_OF_COLOR_SETS - 1] = nullptr;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -328,9 +299,8 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh)
|
|||
}
|
||||
|
||||
// handle bones
|
||||
if (configDeleteFlags & aiComponent_BONEWEIGHTS && pMesh->mBones)
|
||||
{
|
||||
ArrayDelete(pMesh->mBones,pMesh->mNumBones);
|
||||
if (configDeleteFlags & aiComponent_BONEWEIGHTS && pMesh->mBones) {
|
||||
ArrayDelete(pMesh->mBones, pMesh->mNumBones);
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -75,7 +75,7 @@ void ScaleProcess::SetupProperties( const Importer* pImp ) {
|
|||
// File scaling * Application Scaling
|
||||
float importerScale = pImp->GetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, 1.0f );
|
||||
|
||||
// apply scale to the scale
|
||||
// apply scale to the scale
|
||||
// helps prevent bugs with backward compatibility for anyone using normal scaling.
|
||||
mScale *= importerScale;
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
if(mScale == 1.0f) {
|
||||
return; // nothing to scale
|
||||
}
|
||||
|
||||
|
||||
ai_assert( mScale != 0 );
|
||||
ai_assert( nullptr != pScene );
|
||||
ai_assert( nullptr != pScene->mRootNode );
|
||||
|
|
@ -96,7 +96,7 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
if ( nullptr == pScene->mRootNode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Process animations and update position transform to new unit system
|
||||
for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ )
|
||||
{
|
||||
|
|
@ -105,7 +105,7 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++)
|
||||
{
|
||||
aiNodeAnim* anim = animation->mChannels[animationChannel];
|
||||
|
||||
|
||||
for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++)
|
||||
{
|
||||
aiVectorKey& vectorKey = anim->mPositionKeys[posKey];
|
||||
|
|
@ -116,9 +116,9 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
|
||||
for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++)
|
||||
{
|
||||
aiMesh *mesh = pScene->mMeshes[meshID];
|
||||
|
||||
// Reconstruct mesh vertexes to the new unit system
|
||||
aiMesh *mesh = pScene->mMeshes[meshID];
|
||||
|
||||
// Reconstruct mesh vertices to the new unit system
|
||||
for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++)
|
||||
{
|
||||
aiVector3D& vertex = mesh->mVertices[vertexID];
|
||||
|
|
@ -129,9 +129,9 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
// bone placement / scaling
|
||||
for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++)
|
||||
{
|
||||
// Reconstruct matrix by transform rather than by scale
|
||||
// Reconstruct matrix by transform rather than by scale
|
||||
// This prevent scale values being changed which can
|
||||
// be meaningful in some cases
|
||||
// be meaningful in some cases
|
||||
// like when you want the modeller to see 1:1 compatibility.
|
||||
aiBone* bone = mesh->mBones[boneID];
|
||||
|
||||
|
|
@ -139,10 +139,10 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
aiQuaternion rotation;
|
||||
|
||||
bone->mOffsetMatrix.Decompose( scale, rotation, pos);
|
||||
|
||||
|
||||
aiMatrix4x4 translation;
|
||||
aiMatrix4x4::Translation( pos * mScale, translation );
|
||||
|
||||
|
||||
aiMatrix4x4 scaling;
|
||||
aiMatrix4x4::Scaling( aiVector3D(scale), scaling );
|
||||
|
||||
|
|
@ -157,7 +157,7 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++)
|
||||
{
|
||||
aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID];
|
||||
|
||||
|
||||
for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++)
|
||||
{
|
||||
aiVector3D& vertex = animMesh->mVertices[vertexID];
|
||||
|
|
@ -169,31 +169,31 @@ void ScaleProcess::Execute( aiScene* pScene ) {
|
|||
traverseNodes( pScene->mRootNode );
|
||||
}
|
||||
|
||||
void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) {
|
||||
void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) {
|
||||
applyScaling( node );
|
||||
|
||||
for( size_t i = 0; i < node->mNumChildren; i++)
|
||||
{
|
||||
// recurse into the tree until we are done!
|
||||
traverseNodes( node->mChildren[i], nested_node_id+1 );
|
||||
traverseNodes( node->mChildren[i], nested_node_id+1 );
|
||||
}
|
||||
}
|
||||
|
||||
void ScaleProcess::applyScaling( aiNode *currentNode ) {
|
||||
if ( nullptr != currentNode ) {
|
||||
// Reconstruct matrix by transform rather than by scale
|
||||
// Reconstruct matrix by transform rather than by scale
|
||||
// This prevent scale values being changed which can
|
||||
// be meaningful in some cases
|
||||
// like when you want the modeller to
|
||||
// be meaningful in some cases
|
||||
// like when you want the modeller to
|
||||
// see 1:1 compatibility.
|
||||
|
||||
|
||||
aiVector3D pos, scale;
|
||||
aiQuaternion rotation;
|
||||
currentNode->mTransformation.Decompose( scale, rotation, pos);
|
||||
|
||||
|
||||
aiMatrix4x4 translation;
|
||||
aiMatrix4x4::Translation( pos * mScale, translation );
|
||||
|
||||
|
||||
aiMatrix4x4 scaling;
|
||||
|
||||
// note: we do not use mScale here, this is on purpose.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -55,8 +55,8 @@ namespace Assimp {
|
|||
// ---------------------------------------------------------------------------
|
||||
/** ScaleProcess: Class to rescale the whole model.
|
||||
* Now rescales animations, bones, and blend shapes properly.
|
||||
* Please note this will not write to 'scale' transform it will rewrite mesh
|
||||
* and matrixes so that your scale values
|
||||
* Please note this will not write to 'scale' transform it will rewrite mesh
|
||||
* and matrixes so that your scale values
|
||||
* from your model package are preserved, so this is completely intentional
|
||||
* bugs should be reported as soon as they are found.
|
||||
*/
|
||||
|
|
@ -94,4 +94,4 @@ private:
|
|||
} // Namespace Assimp
|
||||
|
||||
|
||||
#endif // SCALE_PROCESS_H_
|
||||
#endif // SCALE_PROCESS_H_
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
|
||||
|
|
@ -45,112 +45,99 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
* SortByPTypeProcess post-process steps.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// internal headers
|
||||
#include "ProcessHelper.h"
|
||||
#include "SortByPTypeProcess.h"
|
||||
#include "ProcessHelper.h"
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
SortByPTypeProcess::SortByPTypeProcess()
|
||||
: mConfigRemoveMeshes( 0 ) {
|
||||
SortByPTypeProcess::SortByPTypeProcess() :
|
||||
mConfigRemoveMeshes(0) {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
SortByPTypeProcess::~SortByPTypeProcess()
|
||||
{
|
||||
SortByPTypeProcess::~SortByPTypeProcess() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag field.
|
||||
bool SortByPTypeProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return (pFlags & aiProcess_SortByPType) != 0;
|
||||
bool SortByPTypeProcess::IsActive(unsigned int pFlags) const {
|
||||
return (pFlags & aiProcess_SortByPType) != 0;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SortByPTypeProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,0);
|
||||
void SortByPTypeProcess::SetupProperties(const Importer *pImp) {
|
||||
mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE, 0);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Update changed meshes in all nodes
|
||||
void UpdateNodes(const std::vector<unsigned int>& replaceMeshIndex, aiNode* node)
|
||||
{
|
||||
if (node->mNumMeshes)
|
||||
{
|
||||
void UpdateNodes(const std::vector<unsigned int> &replaceMeshIndex, aiNode *node) {
|
||||
if (node->mNumMeshes) {
|
||||
unsigned int newSize = 0;
|
||||
for (unsigned int m = 0; m< node->mNumMeshes; ++m)
|
||||
{
|
||||
unsigned int add = node->mMeshes[m]<<2;
|
||||
for (unsigned int i = 0; i < 4;++i)
|
||||
{
|
||||
if (UINT_MAX != replaceMeshIndex[add+i])++newSize;
|
||||
for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
|
||||
unsigned int add = node->mMeshes[m] << 2;
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
if (UINT_MAX != replaceMeshIndex[add + i]) ++newSize;
|
||||
}
|
||||
}
|
||||
if (!newSize)
|
||||
{
|
||||
if (!newSize) {
|
||||
delete[] node->mMeshes;
|
||||
node->mNumMeshes = 0;
|
||||
node->mMeshes = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->mMeshes = nullptr;
|
||||
} else {
|
||||
// Try to reuse the old array if possible
|
||||
unsigned int* newMeshes = (newSize > node->mNumMeshes
|
||||
? new unsigned int[newSize] : node->mMeshes);
|
||||
unsigned int *newMeshes = (newSize > node->mNumMeshes ? new unsigned int[newSize] : node->mMeshes);
|
||||
|
||||
for (unsigned int m = 0; m< node->mNumMeshes; ++m)
|
||||
{
|
||||
unsigned int add = node->mMeshes[m]<<2;
|
||||
for (unsigned int i = 0; i < 4;++i)
|
||||
{
|
||||
if (UINT_MAX != replaceMeshIndex[add+i])
|
||||
*newMeshes++ = replaceMeshIndex[add+i];
|
||||
for (unsigned int m = 0; m < node->mNumMeshes; ++m) {
|
||||
unsigned int add = node->mMeshes[m] << 2;
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
if (UINT_MAX != replaceMeshIndex[add + i])
|
||||
*newMeshes++ = replaceMeshIndex[add + i];
|
||||
}
|
||||
}
|
||||
if (newSize > node->mNumMeshes)
|
||||
delete[] node->mMeshes;
|
||||
|
||||
node->mMeshes = newMeshes-(node->mNumMeshes = newSize);
|
||||
node->mMeshes = newMeshes - (node->mNumMeshes = newSize);
|
||||
}
|
||||
}
|
||||
|
||||
// call all subnodes recursively
|
||||
for (unsigned int m = 0; m < node->mNumChildren; ++m)
|
||||
UpdateNodes(replaceMeshIndex,node->mChildren[m]);
|
||||
UpdateNodes(replaceMeshIndex, node->mChildren[m]);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void SortByPTypeProcess::Execute( aiScene* pScene) {
|
||||
if ( 0 == pScene->mNumMeshes) {
|
||||
void SortByPTypeProcess::Execute(aiScene *pScene) {
|
||||
if (0 == pScene->mNumMeshes) {
|
||||
ASSIMP_LOG_DEBUG("SortByPTypeProcess skipped, there are no meshes");
|
||||
return;
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG("SortByPTypeProcess begin");
|
||||
|
||||
unsigned int aiNumMeshesPerPType[4] = {0,0,0,0};
|
||||
unsigned int aiNumMeshesPerPType[4] = { 0, 0, 0, 0 };
|
||||
|
||||
std::vector<aiMesh*> outMeshes;
|
||||
outMeshes.reserve(pScene->mNumMeshes<<1u);
|
||||
std::vector<aiMesh *> outMeshes;
|
||||
outMeshes.reserve(static_cast<size_t>(pScene->mNumMeshes) << 1u);
|
||||
|
||||
bool bAnyChanges = false;
|
||||
|
||||
std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes*4,UINT_MAX);
|
||||
std::vector<unsigned int> replaceMeshIndex(pScene->mNumMeshes * 4, UINT_MAX);
|
||||
std::vector<unsigned int>::iterator meshIdx = replaceMeshIndex.begin();
|
||||
for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
aiMesh* const mesh = pScene->mMeshes[i];
|
||||
ai_assert(0 != mesh->mPrimitiveTypes);
|
||||
aiMesh *const mesh = pScene->mMeshes[i];
|
||||
if (mesh->mPrimitiveTypes == 0) {
|
||||
throw DeadlyImportError("Mesh with invalid primitive type: ", mesh->mName.C_Str());
|
||||
}
|
||||
|
||||
// if there's just one primitive type in the mesh there's nothing to do for us
|
||||
unsigned int num = 0;
|
||||
|
|
@ -173,11 +160,11 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
|
||||
if (1 == num) {
|
||||
if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) {
|
||||
*meshIdx = static_cast<unsigned int>( outMeshes.size() );
|
||||
*meshIdx = static_cast<unsigned int>(outMeshes.size());
|
||||
outMeshes.push_back(mesh);
|
||||
} else {
|
||||
delete mesh;
|
||||
pScene->mMeshes[ i ] = nullptr;
|
||||
pScene->mMeshes[i] = nullptr;
|
||||
bAnyChanges = true;
|
||||
}
|
||||
|
||||
|
|
@ -188,32 +175,29 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
|
||||
// reuse our current mesh arrays for the submesh
|
||||
// with the largest number of primitives
|
||||
unsigned int aiNumPerPType[4] = {0,0,0,0};
|
||||
aiFace* pFirstFace = mesh->mFaces;
|
||||
aiFace* const pLastFace = pFirstFace + mesh->mNumFaces;
|
||||
unsigned int aiNumPerPType[4] = { 0, 0, 0, 0 };
|
||||
aiFace *pFirstFace = mesh->mFaces;
|
||||
aiFace *const pLastFace = pFirstFace + mesh->mNumFaces;
|
||||
|
||||
unsigned int numPolyVerts = 0;
|
||||
for (;pFirstFace != pLastFace; ++pFirstFace) {
|
||||
for (; pFirstFace != pLastFace; ++pFirstFace) {
|
||||
if (pFirstFace->mNumIndices <= 3)
|
||||
++aiNumPerPType[pFirstFace->mNumIndices-1];
|
||||
else
|
||||
{
|
||||
++aiNumPerPType[pFirstFace->mNumIndices - 1];
|
||||
else {
|
||||
++aiNumPerPType[3];
|
||||
numPolyVerts += pFirstFace-> mNumIndices;
|
||||
numPolyVerts += pFirstFace->mNumIndices;
|
||||
}
|
||||
}
|
||||
|
||||
VertexWeightTable* avw = ComputeVertexBoneWeightTable(mesh);
|
||||
for (unsigned int real = 0; real < 4; ++real,++meshIdx)
|
||||
{
|
||||
if ( !aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real))
|
||||
{
|
||||
VertexWeightTable *avw = ComputeVertexBoneWeightTable(mesh);
|
||||
for (unsigned int real = 0; real < 4; ++real, ++meshIdx) {
|
||||
if (!aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*meshIdx = (unsigned int) outMeshes.size();
|
||||
*meshIdx = (unsigned int)outMeshes.size();
|
||||
outMeshes.push_back(new aiMesh());
|
||||
aiMesh* out = outMeshes.back();
|
||||
aiMesh *out = outMeshes.back();
|
||||
|
||||
// the name carries the adjacency information between the meshes
|
||||
out->mName = mesh->mName;
|
||||
|
|
@ -224,13 +208,13 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
|
||||
// allocate output storage
|
||||
out->mNumFaces = aiNumPerPType[real];
|
||||
aiFace* outFaces = out->mFaces = new aiFace[out->mNumFaces];
|
||||
aiFace *outFaces = out->mFaces = new aiFace[out->mNumFaces];
|
||||
|
||||
out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real+1));
|
||||
out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real + 1));
|
||||
|
||||
aiVector3D *vert(nullptr), *nor(nullptr), *tan(nullptr), *bit(nullptr);
|
||||
aiVector3D *uv [AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
aiColor4D *cols [AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
aiVector3D *uv[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
aiColor4D *cols[AI_MAX_NUMBER_OF_COLOR_SETS];
|
||||
|
||||
if (mesh->mVertices) {
|
||||
vert = out->mVertices = new aiVector3D[out->mNumVertices];
|
||||
|
|
@ -241,11 +225,11 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
}
|
||||
|
||||
if (mesh->mTangents) {
|
||||
tan = out->mTangents = new aiVector3D[out->mNumVertices];
|
||||
tan = out->mTangents = new aiVector3D[out->mNumVertices];
|
||||
bit = out->mBitangents = new aiVector3D[out->mNumVertices];
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS;++j) {
|
||||
for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++j) {
|
||||
uv[j] = nullptr;
|
||||
if (mesh->mTextureCoords[j]) {
|
||||
uv[j] = out->mTextureCoords[j] = new aiVector3D[out->mNumVertices];
|
||||
|
|
@ -254,73 +238,127 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
out->mNumUVComponents[j] = mesh->mNumUVComponents[j];
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS;++j) {
|
||||
for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS; ++j) {
|
||||
cols[j] = nullptr;
|
||||
if (mesh->mColors[j]) {
|
||||
cols[j] = out->mColors[j] = new aiColor4D[out->mNumVertices];
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::vector< aiVertexWeight > TempBoneInfo;
|
||||
std::vector< TempBoneInfo > tempBones(mesh->mNumBones);
|
||||
if (mesh->mNumAnimMeshes > 0 && mesh->mAnimMeshes) {
|
||||
out->mNumAnimMeshes = mesh->mNumAnimMeshes;
|
||||
out->mAnimMeshes = new aiAnimMesh *[out->mNumAnimMeshes];
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < mesh->mNumAnimMeshes; ++j) {
|
||||
aiAnimMesh *animMesh = mesh->mAnimMeshes[j];
|
||||
aiAnimMesh *outAnimMesh = out->mAnimMeshes[j] = new aiAnimMesh;
|
||||
outAnimMesh->mNumVertices = out->mNumVertices;
|
||||
if (animMesh->mVertices)
|
||||
outAnimMesh->mVertices = new aiVector3D[out->mNumVertices];
|
||||
else
|
||||
outAnimMesh->mVertices = nullptr;
|
||||
if (animMesh->mNormals)
|
||||
outAnimMesh->mNormals = new aiVector3D[out->mNumVertices];
|
||||
else
|
||||
outAnimMesh->mNormals = nullptr;
|
||||
if (animMesh->mTangents)
|
||||
outAnimMesh->mTangents = new aiVector3D[out->mNumVertices];
|
||||
else
|
||||
outAnimMesh->mTangents = nullptr;
|
||||
if (animMesh->mBitangents)
|
||||
outAnimMesh->mBitangents = new aiVector3D[out->mNumVertices];
|
||||
else
|
||||
outAnimMesh->mBitangents = nullptr;
|
||||
for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) {
|
||||
if (animMesh->mColors[jj])
|
||||
outAnimMesh->mColors[jj] = new aiColor4D[out->mNumVertices];
|
||||
else
|
||||
outAnimMesh->mColors[jj] = nullptr;
|
||||
}
|
||||
for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) {
|
||||
if (animMesh->mTextureCoords[jj])
|
||||
outAnimMesh->mTextureCoords[jj] = new aiVector3D[out->mNumVertices];
|
||||
else
|
||||
outAnimMesh->mTextureCoords[jj] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::vector<aiVertexWeight> TempBoneInfo;
|
||||
std::vector<TempBoneInfo> tempBones(mesh->mNumBones);
|
||||
|
||||
// try to guess how much storage we'll need
|
||||
for (unsigned int q = 0; q < mesh->mNumBones;++q)
|
||||
{
|
||||
tempBones[q].reserve(mesh->mBones[q]->mNumWeights / (num-1));
|
||||
for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
|
||||
tempBones[q].reserve(mesh->mBones[q]->mNumWeights / (num - 1));
|
||||
}
|
||||
|
||||
unsigned int outIdx = 0;
|
||||
for (unsigned int m = 0; m < mesh->mNumFaces; ++m)
|
||||
{
|
||||
aiFace& in = mesh->mFaces[m];
|
||||
if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real+1))
|
||||
{
|
||||
unsigned int amIdx = 0; // AnimMesh index
|
||||
for (unsigned int m = 0; m < mesh->mNumFaces; ++m) {
|
||||
aiFace &in = mesh->mFaces[m];
|
||||
if ((real == 3 && in.mNumIndices <= 3) || (real != 3 && in.mNumIndices != real + 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
outFaces->mNumIndices = in.mNumIndices;
|
||||
outFaces->mIndices = in.mIndices;
|
||||
outFaces->mIndices = in.mIndices;
|
||||
|
||||
for (unsigned int q = 0; q < in.mNumIndices; ++q)
|
||||
{
|
||||
for (unsigned int q = 0; q < in.mNumIndices; ++q) {
|
||||
unsigned int idx = in.mIndices[q];
|
||||
|
||||
// process all bones of this index
|
||||
if (avw)
|
||||
{
|
||||
VertexWeightTable& tbl = avw[idx];
|
||||
if (avw) {
|
||||
VertexWeightTable &tbl = avw[idx];
|
||||
for (VertexWeightTable::const_iterator it = tbl.begin(), end = tbl.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
tempBones[ (*it).first ].push_back( aiVertexWeight(outIdx, (*it).second) );
|
||||
it != end; ++it) {
|
||||
tempBones[(*it).first].push_back(aiVertexWeight(outIdx, (*it).second));
|
||||
}
|
||||
}
|
||||
|
||||
if (vert)
|
||||
{
|
||||
if (vert) {
|
||||
*vert++ = mesh->mVertices[idx];
|
||||
//mesh->mVertices[idx].x = get_qnan();
|
||||
}
|
||||
if (nor )*nor++ = mesh->mNormals[idx];
|
||||
if (tan )
|
||||
{
|
||||
*tan++ = mesh->mTangents[idx];
|
||||
*bit++ = mesh->mBitangents[idx];
|
||||
if (nor) *nor++ = mesh->mNormals[idx];
|
||||
if (tan) {
|
||||
*tan++ = mesh->mTangents[idx];
|
||||
*bit++ = mesh->mBitangents[idx];
|
||||
}
|
||||
|
||||
for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp)
|
||||
{
|
||||
if (!uv[pp])break;
|
||||
for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++pp) {
|
||||
if (!uv[pp]) break;
|
||||
*uv[pp]++ = mesh->mTextureCoords[pp][idx];
|
||||
}
|
||||
|
||||
for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp)
|
||||
{
|
||||
if (!cols[pp])break;
|
||||
for (unsigned int pp = 0; pp < AI_MAX_NUMBER_OF_COLOR_SETS; ++pp) {
|
||||
if (!cols[pp]) break;
|
||||
*cols[pp]++ = mesh->mColors[pp][idx];
|
||||
}
|
||||
|
||||
unsigned int pp = 0;
|
||||
for (; pp < mesh->mNumAnimMeshes; ++pp) {
|
||||
aiAnimMesh *animMesh = mesh->mAnimMeshes[pp];
|
||||
aiAnimMesh *outAnimMesh = out->mAnimMeshes[pp];
|
||||
if (animMesh->mVertices)
|
||||
outAnimMesh->mVertices[amIdx] = animMesh->mVertices[idx];
|
||||
if (animMesh->mNormals)
|
||||
outAnimMesh->mNormals[amIdx] = animMesh->mNormals[idx];
|
||||
if (animMesh->mTangents)
|
||||
outAnimMesh->mTangents[amIdx] = animMesh->mTangents[idx];
|
||||
if (animMesh->mBitangents)
|
||||
outAnimMesh->mBitangents[amIdx] = animMesh->mBitangents[idx];
|
||||
for (int jj = 0; jj < AI_MAX_NUMBER_OF_COLOR_SETS; ++jj) {
|
||||
if (animMesh->mColors[jj])
|
||||
outAnimMesh->mColors[jj][amIdx] = animMesh->mColors[jj][idx];
|
||||
}
|
||||
for (int jj = 0; jj < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++jj) {
|
||||
if (animMesh->mTextureCoords[jj])
|
||||
outAnimMesh->mTextureCoords[jj][amIdx] = animMesh->mTextureCoords[jj][idx];
|
||||
}
|
||||
}
|
||||
if (pp == mesh->mNumAnimMeshes)
|
||||
amIdx++;
|
||||
|
||||
in.mIndices[q] = outIdx++;
|
||||
}
|
||||
|
||||
|
|
@ -330,19 +368,22 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
ai_assert(outFaces == out->mFaces + out->mNumFaces);
|
||||
|
||||
// now generate output bones
|
||||
for (unsigned int q = 0; q < mesh->mNumBones;++q)
|
||||
if (!tempBones[q].empty())++out->mNumBones;
|
||||
for (unsigned int q = 0; q < mesh->mNumBones; ++q) {
|
||||
if (!tempBones[q].empty()) {
|
||||
++out->mNumBones;
|
||||
}
|
||||
}
|
||||
|
||||
if (out->mNumBones)
|
||||
{
|
||||
out->mBones = new aiBone*[out->mNumBones];
|
||||
for (unsigned int q = 0, real = 0; q < mesh->mNumBones;++q)
|
||||
{
|
||||
TempBoneInfo& in = tempBones[q];
|
||||
if (in.empty())continue;
|
||||
if (out->mNumBones) {
|
||||
out->mBones = new aiBone *[out->mNumBones];
|
||||
for (unsigned int q = 0, boneIdx = 0; q < mesh->mNumBones; ++q) {
|
||||
TempBoneInfo &in = tempBones[q];
|
||||
if (in.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aiBone* srcBone = mesh->mBones[q];
|
||||
aiBone* bone = out->mBones[real] = new aiBone();
|
||||
aiBone *srcBone = mesh->mBones[q];
|
||||
aiBone *bone = out->mBones[boneIdx] = new aiBone();
|
||||
|
||||
bone->mName = srcBone->mName;
|
||||
bone->mOffsetMatrix = srcBone->mOffsetMatrix;
|
||||
|
|
@ -350,9 +391,9 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
bone->mNumWeights = (unsigned int)in.size();
|
||||
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
||||
|
||||
::memcpy(bone->mWeights,&in[0],bone->mNumWeights*sizeof(aiVertexWeight));
|
||||
::memcpy(bone->mWeights, &in[0], bone->mNumWeights * sizeof(aiVertexWeight));
|
||||
|
||||
++real;
|
||||
++boneIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -364,40 +405,35 @@ void SortByPTypeProcess::Execute( aiScene* pScene) {
|
|||
delete mesh;
|
||||
|
||||
// avoid invalid pointer
|
||||
pScene->mMeshes[i] = NULL;
|
||||
pScene->mMeshes[i] = nullptr;
|
||||
}
|
||||
|
||||
if (outMeshes.empty())
|
||||
{
|
||||
if (outMeshes.empty()) {
|
||||
// This should not occur
|
||||
throw DeadlyImportError("No meshes remaining");
|
||||
}
|
||||
|
||||
// If we added at least one mesh process all nodes in the node
|
||||
// graph and update their respective mesh indices.
|
||||
if (bAnyChanges)
|
||||
{
|
||||
UpdateNodes(replaceMeshIndex,pScene->mRootNode);
|
||||
if (bAnyChanges) {
|
||||
UpdateNodes(replaceMeshIndex, pScene->mRootNode);
|
||||
}
|
||||
|
||||
if (outMeshes.size() != pScene->mNumMeshes)
|
||||
{
|
||||
if (outMeshes.size() != pScene->mNumMeshes) {
|
||||
delete[] pScene->mMeshes;
|
||||
pScene->mNumMeshes = (unsigned int)outMeshes.size();
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
pScene->mMeshes = new aiMesh *[pScene->mNumMeshes];
|
||||
}
|
||||
::memcpy(pScene->mMeshes,&outMeshes[0],pScene->mNumMeshes*sizeof(void*));
|
||||
::memcpy(pScene->mMeshes, &outMeshes[0], pScene->mNumMeshes * sizeof(void *));
|
||||
|
||||
if (!DefaultLogger::isNullLogger())
|
||||
{
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
char buffer[1024];
|
||||
::ai_snprintf(buffer,1024,"Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)",
|
||||
aiNumMeshesPerPType[0], ((mConfigRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""),
|
||||
aiNumMeshesPerPType[1], ((mConfigRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""),
|
||||
aiNumMeshesPerPType[2], ((mConfigRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""),
|
||||
aiNumMeshesPerPType[3], ((mConfigRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : ""));
|
||||
::ai_snprintf(buffer, 1024, "Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)",
|
||||
aiNumMeshesPerPType[0], ((mConfigRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""),
|
||||
aiNumMeshesPerPType[1], ((mConfigRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""),
|
||||
aiNumMeshesPerPType[2], ((mConfigRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""),
|
||||
aiNumMeshesPerPType[3], ((mConfigRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : ""));
|
||||
ASSIMP_LOG_INFO(buffer);
|
||||
ASSIMP_LOG_DEBUG("SortByPTypeProcess finished");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,480 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
/// @file SplitByBoneCountProcess.cpp
|
||||
/// Implementation of the SplitByBoneCount postprocessing step
|
||||
|
||||
// internal headers of the post-processing framework
|
||||
#include "SplitByBoneCountProcess.h"
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <set>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
SplitByBoneCountProcess::SplitByBoneCountProcess()
|
||||
{
|
||||
// set default, might be overridden by importer config
|
||||
mMaxBoneCount = AI_SBBC_DEFAULT_MAX_BONES;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
SplitByBoneCountProcess::~SplitByBoneCountProcess()
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the processing step is present in the given flag.
|
||||
bool SplitByBoneCountProcess::IsActive( unsigned int pFlags) const
|
||||
{
|
||||
return !!(pFlags & aiProcess_SplitByBoneCount);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Updates internal properties
|
||||
void SplitByBoneCountProcess::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
mMaxBoneCount = pImp->GetPropertyInteger(AI_CONFIG_PP_SBBC_MAX_BONES,AI_SBBC_DEFAULT_MAX_BONES);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Executes the post processing step on the given imported data.
|
||||
void SplitByBoneCountProcess::Execute( aiScene* pScene)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("SplitByBoneCountProcess begin");
|
||||
|
||||
// early out
|
||||
bool isNecessary = false;
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
|
||||
if( pScene->mMeshes[a]->mNumBones > mMaxBoneCount )
|
||||
{
|
||||
isNecessary = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if( !isNecessary )
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("SplitByBoneCountProcess early-out: no meshes with more than ", mMaxBoneCount, " bones." );
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to do something. Let's go.
|
||||
mSubMeshIndices.clear();
|
||||
mSubMeshIndices.resize( pScene->mNumMeshes);
|
||||
|
||||
// build a new array of meshes for the scene
|
||||
std::vector<aiMesh*> meshes;
|
||||
|
||||
for( unsigned int a = 0; a < pScene->mNumMeshes; ++a)
|
||||
{
|
||||
aiMesh* srcMesh = pScene->mMeshes[a];
|
||||
|
||||
std::vector<aiMesh*> newMeshes;
|
||||
SplitMesh( pScene->mMeshes[a], newMeshes);
|
||||
|
||||
// mesh was split
|
||||
if( !newMeshes.empty() )
|
||||
{
|
||||
// store new meshes and indices of the new meshes
|
||||
for( unsigned int b = 0; b < newMeshes.size(); ++b)
|
||||
{
|
||||
mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
|
||||
meshes.push_back( newMeshes[b]);
|
||||
}
|
||||
|
||||
// and destroy the source mesh. It should be completely contained inside the new submeshes
|
||||
delete srcMesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mesh is kept unchanged - store it's new place in the mesh array
|
||||
mSubMeshIndices[a].push_back( static_cast<unsigned int>(meshes.size()));
|
||||
meshes.push_back( srcMesh);
|
||||
}
|
||||
}
|
||||
|
||||
// rebuild the scene's mesh array
|
||||
pScene->mNumMeshes = static_cast<unsigned int>(meshes.size());
|
||||
delete [] pScene->mMeshes;
|
||||
pScene->mMeshes = new aiMesh*[pScene->mNumMeshes];
|
||||
std::copy( meshes.begin(), meshes.end(), pScene->mMeshes);
|
||||
|
||||
// recurse through all nodes and translate the node's mesh indices to fit the new mesh array
|
||||
UpdateNode( pScene->mRootNode);
|
||||
|
||||
ASSIMP_LOG_DEBUG( "SplitByBoneCountProcess end: split ", mSubMeshIndices.size(), " meshes into ", meshes.size(), " submeshes." );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Splits the given mesh by bone count.
|
||||
void SplitByBoneCountProcess::SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const
|
||||
{
|
||||
// skip if not necessary
|
||||
if( pMesh->mNumBones <= mMaxBoneCount )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// necessary optimisation: build a list of all affecting bones for each vertex
|
||||
// TODO: (thom) maybe add a custom allocator here to avoid allocating tens of thousands of small arrays
|
||||
typedef std::pair<unsigned int, float> BoneWeight;
|
||||
std::vector< std::vector<BoneWeight> > vertexBones( pMesh->mNumVertices);
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; ++a)
|
||||
{
|
||||
const aiBone* bone = pMesh->mBones[a];
|
||||
for( unsigned int b = 0; b < bone->mNumWeights; ++b)
|
||||
{
|
||||
if (bone->mWeights[b].mWeight > 0.0f)
|
||||
{
|
||||
int vertexId = bone->mWeights[b].mVertexId;
|
||||
vertexBones[vertexId].push_back( BoneWeight( a, bone->mWeights[b].mWeight));
|
||||
if (vertexBones[vertexId].size() > mMaxBoneCount)
|
||||
{
|
||||
throw DeadlyImportError("SplitByBoneCountProcess: Single face requires more bones than specified max bone count!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int numFacesHandled = 0;
|
||||
std::vector<bool> isFaceHandled( pMesh->mNumFaces, false);
|
||||
while( numFacesHandled < pMesh->mNumFaces )
|
||||
{
|
||||
// which bones are used in the current submesh
|
||||
unsigned int numBones = 0;
|
||||
std::vector<bool> isBoneUsed( pMesh->mNumBones, false);
|
||||
// indices of the faces which are going to go into this submesh
|
||||
std::vector<unsigned int> subMeshFaces;
|
||||
subMeshFaces.reserve( pMesh->mNumFaces);
|
||||
// accumulated vertex count of all the faces in this submesh
|
||||
unsigned int numSubMeshVertices = 0;
|
||||
|
||||
// add faces to the new submesh as long as all bones affecting the faces' vertices fit in the limit
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; ++a)
|
||||
{
|
||||
// skip if the face is already stored in a submesh
|
||||
if( isFaceHandled[a] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// a small local set of new bones for the current face. State of all used bones for that face
|
||||
// can only be updated AFTER the face is completely analysed. Thanks to imre for the fix.
|
||||
std::set<unsigned int> newBonesAtCurrentFace;
|
||||
|
||||
const aiFace& face = pMesh->mFaces[a];
|
||||
// check every vertex if its bones would still fit into the current submesh
|
||||
for( unsigned int b = 0; b < face.mNumIndices; ++b )
|
||||
{
|
||||
const std::vector<BoneWeight>& vb = vertexBones[face.mIndices[b]];
|
||||
for( unsigned int c = 0; c < vb.size(); ++c)
|
||||
{
|
||||
unsigned int boneIndex = vb[c].first;
|
||||
if( !isBoneUsed[boneIndex] )
|
||||
{
|
||||
newBonesAtCurrentFace.insert(boneIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// leave out the face if the new bones required for this face don't fit the bone count limit anymore
|
||||
if( numBones + newBonesAtCurrentFace.size() > mMaxBoneCount )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// mark all new bones as necessary
|
||||
for (std::set<unsigned int>::iterator it = newBonesAtCurrentFace.begin(); it != newBonesAtCurrentFace.end(); ++it)
|
||||
{
|
||||
if (!isBoneUsed[*it])
|
||||
{
|
||||
isBoneUsed[*it] = true;
|
||||
numBones++;
|
||||
}
|
||||
}
|
||||
|
||||
// store the face index and the vertex count
|
||||
subMeshFaces.push_back( a);
|
||||
numSubMeshVertices += face.mNumIndices;
|
||||
|
||||
// remember that this face is handled
|
||||
isFaceHandled[a] = true;
|
||||
numFacesHandled++;
|
||||
}
|
||||
|
||||
// create a new mesh to hold this subset of the source mesh
|
||||
aiMesh* newMesh = new aiMesh;
|
||||
if( pMesh->mName.length > 0 )
|
||||
{
|
||||
newMesh->mName.Set( format() << pMesh->mName.data << "_sub" << poNewMeshes.size());
|
||||
}
|
||||
newMesh->mMaterialIndex = pMesh->mMaterialIndex;
|
||||
newMesh->mPrimitiveTypes = pMesh->mPrimitiveTypes;
|
||||
poNewMeshes.push_back( newMesh);
|
||||
|
||||
// create all the arrays for this mesh if the old mesh contained them
|
||||
newMesh->mNumVertices = numSubMeshVertices;
|
||||
newMesh->mNumFaces = static_cast<unsigned int>(subMeshFaces.size());
|
||||
newMesh->mVertices = new aiVector3D[newMesh->mNumVertices];
|
||||
if( pMesh->HasNormals() )
|
||||
{
|
||||
newMesh->mNormals = new aiVector3D[newMesh->mNumVertices];
|
||||
}
|
||||
if( pMesh->HasTangentsAndBitangents() )
|
||||
{
|
||||
newMesh->mTangents = new aiVector3D[newMesh->mNumVertices];
|
||||
newMesh->mBitangents = new aiVector3D[newMesh->mNumVertices];
|
||||
}
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
|
||||
{
|
||||
if( pMesh->HasTextureCoords( a) )
|
||||
{
|
||||
newMesh->mTextureCoords[a] = new aiVector3D[newMesh->mNumVertices];
|
||||
}
|
||||
newMesh->mNumUVComponents[a] = pMesh->mNumUVComponents[a];
|
||||
}
|
||||
for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
|
||||
{
|
||||
if( pMesh->HasVertexColors( a) )
|
||||
{
|
||||
newMesh->mColors[a] = new aiColor4D[newMesh->mNumVertices];
|
||||
}
|
||||
}
|
||||
|
||||
// and copy over the data, generating faces with linear indices along the way
|
||||
newMesh->mFaces = new aiFace[subMeshFaces.size()];
|
||||
unsigned int nvi = 0; // next vertex index
|
||||
std::vector<unsigned int> previousVertexIndices( numSubMeshVertices, std::numeric_limits<unsigned int>::max()); // per new vertex: its index in the source mesh
|
||||
for( unsigned int a = 0; a < subMeshFaces.size(); ++a )
|
||||
{
|
||||
const aiFace& srcFace = pMesh->mFaces[subMeshFaces[a]];
|
||||
aiFace& dstFace = newMesh->mFaces[a];
|
||||
dstFace.mNumIndices = srcFace.mNumIndices;
|
||||
dstFace.mIndices = new unsigned int[dstFace.mNumIndices];
|
||||
|
||||
// accumulate linearly all the vertices of the source face
|
||||
for( unsigned int b = 0; b < dstFace.mNumIndices; ++b )
|
||||
{
|
||||
unsigned int srcIndex = srcFace.mIndices[b];
|
||||
dstFace.mIndices[b] = nvi;
|
||||
previousVertexIndices[nvi] = srcIndex;
|
||||
|
||||
newMesh->mVertices[nvi] = pMesh->mVertices[srcIndex];
|
||||
if( pMesh->HasNormals() )
|
||||
{
|
||||
newMesh->mNormals[nvi] = pMesh->mNormals[srcIndex];
|
||||
}
|
||||
if( pMesh->HasTangentsAndBitangents() )
|
||||
{
|
||||
newMesh->mTangents[nvi] = pMesh->mTangents[srcIndex];
|
||||
newMesh->mBitangents[nvi] = pMesh->mBitangents[srcIndex];
|
||||
}
|
||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++c )
|
||||
{
|
||||
if( pMesh->HasTextureCoords( c) )
|
||||
{
|
||||
newMesh->mTextureCoords[c][nvi] = pMesh->mTextureCoords[c][srcIndex];
|
||||
}
|
||||
}
|
||||
for( unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c )
|
||||
{
|
||||
if( pMesh->HasVertexColors( c) )
|
||||
{
|
||||
newMesh->mColors[c][nvi] = pMesh->mColors[c][srcIndex];
|
||||
}
|
||||
}
|
||||
|
||||
nvi++;
|
||||
}
|
||||
}
|
||||
|
||||
ai_assert( nvi == numSubMeshVertices );
|
||||
|
||||
// Create the bones for the new submesh: first create the bone array
|
||||
newMesh->mNumBones = 0;
|
||||
newMesh->mBones = new aiBone*[numBones];
|
||||
|
||||
std::vector<unsigned int> mappedBoneIndex( pMesh->mNumBones, std::numeric_limits<unsigned int>::max());
|
||||
for( unsigned int a = 0; a < pMesh->mNumBones; ++a )
|
||||
{
|
||||
if( !isBoneUsed[a] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// create the new bone
|
||||
const aiBone* srcBone = pMesh->mBones[a];
|
||||
aiBone* dstBone = new aiBone;
|
||||
mappedBoneIndex[a] = newMesh->mNumBones;
|
||||
newMesh->mBones[newMesh->mNumBones++] = dstBone;
|
||||
dstBone->mName = srcBone->mName;
|
||||
dstBone->mOffsetMatrix = srcBone->mOffsetMatrix;
|
||||
dstBone->mNumWeights = 0;
|
||||
}
|
||||
|
||||
ai_assert( newMesh->mNumBones == numBones );
|
||||
|
||||
// iterate over all new vertices and count which bones affected its old vertex in the source mesh
|
||||
for( unsigned int a = 0; a < numSubMeshVertices; ++a )
|
||||
{
|
||||
unsigned int oldIndex = previousVertexIndices[a];
|
||||
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[oldIndex];
|
||||
|
||||
for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b )
|
||||
{
|
||||
unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
|
||||
if( newBoneIndex != std::numeric_limits<unsigned int>::max() )
|
||||
{
|
||||
newMesh->mBones[newBoneIndex]->mNumWeights++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allocate all bone weight arrays accordingly
|
||||
for( unsigned int a = 0; a < newMesh->mNumBones; ++a )
|
||||
{
|
||||
aiBone* bone = newMesh->mBones[a];
|
||||
ai_assert( bone->mNumWeights > 0 );
|
||||
bone->mWeights = new aiVertexWeight[bone->mNumWeights];
|
||||
bone->mNumWeights = 0; // for counting up in the next step
|
||||
}
|
||||
|
||||
// now copy all the bone vertex weights for all the vertices which made it into the new submesh
|
||||
for( unsigned int a = 0; a < numSubMeshVertices; ++a)
|
||||
{
|
||||
// find the source vertex for it in the source mesh
|
||||
unsigned int previousIndex = previousVertexIndices[a];
|
||||
// these bones were affecting it
|
||||
const std::vector<BoneWeight>& bonesOnThisVertex = vertexBones[previousIndex];
|
||||
// all of the bones affecting it should be present in the new submesh, or else
|
||||
// the face it comprises shouldn't be present
|
||||
for( unsigned int b = 0; b < bonesOnThisVertex.size(); ++b)
|
||||
{
|
||||
unsigned int newBoneIndex = mappedBoneIndex[ bonesOnThisVertex[b].first ];
|
||||
ai_assert( newBoneIndex != std::numeric_limits<unsigned int>::max() );
|
||||
aiVertexWeight* dstWeight = newMesh->mBones[newBoneIndex]->mWeights + newMesh->mBones[newBoneIndex]->mNumWeights;
|
||||
newMesh->mBones[newBoneIndex]->mNumWeights++;
|
||||
|
||||
dstWeight->mVertexId = a;
|
||||
dstWeight->mWeight = bonesOnThisVertex[b].second;
|
||||
}
|
||||
}
|
||||
|
||||
// ... and copy all the morph targets for all the vertices which made it into the new submesh
|
||||
if (pMesh->mNumAnimMeshes > 0) {
|
||||
newMesh->mNumAnimMeshes = pMesh->mNumAnimMeshes;
|
||||
newMesh->mAnimMeshes = new aiAnimMesh*[newMesh->mNumAnimMeshes];
|
||||
|
||||
for (unsigned int morphIdx = 0; morphIdx < newMesh->mNumAnimMeshes; ++morphIdx) {
|
||||
aiAnimMesh* origTarget = pMesh->mAnimMeshes[morphIdx];
|
||||
aiAnimMesh* newTarget = new aiAnimMesh;
|
||||
newTarget->mName = origTarget->mName;
|
||||
newTarget->mWeight = origTarget->mWeight;
|
||||
newTarget->mNumVertices = numSubMeshVertices;
|
||||
newTarget->mVertices = new aiVector3D[numSubMeshVertices];
|
||||
newMesh->mAnimMeshes[morphIdx] = newTarget;
|
||||
|
||||
if (origTarget->HasNormals()) {
|
||||
newTarget->mNormals = new aiVector3D[numSubMeshVertices];
|
||||
}
|
||||
|
||||
if (origTarget->HasTangentsAndBitangents()) {
|
||||
newTarget->mTangents = new aiVector3D[numSubMeshVertices];
|
||||
newTarget->mBitangents = new aiVector3D[numSubMeshVertices];
|
||||
}
|
||||
|
||||
for( unsigned int vi = 0; vi < numSubMeshVertices; ++vi) {
|
||||
// find the source vertex for it in the source mesh
|
||||
unsigned int previousIndex = previousVertexIndices[vi];
|
||||
newTarget->mVertices[vi] = origTarget->mVertices[previousIndex];
|
||||
|
||||
if (newTarget->HasNormals()) {
|
||||
newTarget->mNormals[vi] = origTarget->mNormals[previousIndex];
|
||||
}
|
||||
if (newTarget->HasTangentsAndBitangents()) {
|
||||
newTarget->mTangents[vi] = origTarget->mTangents[previousIndex];
|
||||
newTarget->mBitangents[vi] = origTarget->mBitangents[previousIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I have the strange feeling that this will break apart at some point in time...
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void SplitByBoneCountProcess::UpdateNode( aiNode* pNode) const
|
||||
{
|
||||
// rebuild the node's mesh index list
|
||||
if( pNode->mNumMeshes > 0 )
|
||||
{
|
||||
std::vector<unsigned int> newMeshList;
|
||||
for( unsigned int a = 0; a < pNode->mNumMeshes; ++a)
|
||||
{
|
||||
unsigned int srcIndex = pNode->mMeshes[a];
|
||||
const std::vector<unsigned int>& replaceMeshes = mSubMeshIndices[srcIndex];
|
||||
newMeshList.insert( newMeshList.end(), replaceMeshes.begin(), replaceMeshes.end());
|
||||
}
|
||||
|
||||
delete [] pNode->mMeshes;
|
||||
pNode->mNumMeshes = static_cast<unsigned int>(newMeshList.size());
|
||||
pNode->mMeshes = new unsigned int[pNode->mNumMeshes];
|
||||
std::copy( newMeshList.begin(), newMeshList.end(), pNode->mMeshes);
|
||||
}
|
||||
|
||||
// do that also recursively for all children
|
||||
for( unsigned int a = 0; a < pNode->mNumChildren; ++a )
|
||||
{
|
||||
UpdateNode( pNode->mChildren[a]);
|
||||
}
|
||||
}
|
||||
111
Engine/lib/assimp/code/PostProcessing/SplitByBoneCountProcess.h
Normal file
111
Engine/lib/assimp/code/PostProcessing/SplitByBoneCountProcess.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/// @file SplitByBoneCountProcess.h
|
||||
/// Defines a post processing step to split meshes with many bones into submeshes
|
||||
#ifndef AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
#define AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
|
||||
#include <vector>
|
||||
#include "Common/BaseProcess.h"
|
||||
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/scene.h>
|
||||
|
||||
namespace Assimp
|
||||
{
|
||||
|
||||
|
||||
/** Postprocessing filter to split meshes with many bones into submeshes
|
||||
* so that each submesh has a certain max bone count.
|
||||
*
|
||||
* Applied BEFORE the JoinVertices-Step occurs.
|
||||
* Returns NON-UNIQUE vertices, splits by bone count.
|
||||
*/
|
||||
class SplitByBoneCountProcess : public BaseProcess
|
||||
{
|
||||
public:
|
||||
|
||||
SplitByBoneCountProcess();
|
||||
~SplitByBoneCountProcess();
|
||||
|
||||
public:
|
||||
/** Returns whether the processing step is present in the given flag.
|
||||
* @param pFlags The processing flags the importer was called with. A
|
||||
* bitwise combination of #aiPostProcessSteps.
|
||||
* @return true if the process is present in this flag fields,
|
||||
* false if not.
|
||||
*/
|
||||
bool IsActive( unsigned int pFlags) const;
|
||||
|
||||
/** Called prior to ExecuteOnScene().
|
||||
* The function is a request to the process to update its configuration
|
||||
* basing on the Importer's configuration property list.
|
||||
*/
|
||||
virtual void SetupProperties(const Importer* pImp);
|
||||
|
||||
protected:
|
||||
/** Executes the post processing step on the given imported data.
|
||||
* At the moment a process is not supposed to fail.
|
||||
* @param pScene The imported data to work at.
|
||||
*/
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
/// Splits the given mesh by bone count.
|
||||
/// @param pMesh the Mesh to split. Is not changed at all, but might be superfluous in case it was split.
|
||||
/// @param poNewMeshes Array of submeshes created in the process. Empty if splitting was not necessary.
|
||||
void SplitMesh( const aiMesh* pMesh, std::vector<aiMesh*>& poNewMeshes) const;
|
||||
|
||||
/// Recursively updates the node's mesh list to account for the changed mesh list
|
||||
void UpdateNode( aiNode* pNode) const;
|
||||
|
||||
public:
|
||||
/// Max bone count. Splitting occurs if a mesh has more than that number of bones.
|
||||
size_t mMaxBoneCount;
|
||||
|
||||
/// Per mesh index: Array of indices of the new submeshes.
|
||||
std::vector< std::vector<unsigned int> > mSubMeshIndices;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
||||
#endif // !!AI_SPLITBYBONECOUNTPROCESS_H_INC
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/**
|
||||
/**
|
||||
* @file Implementation of the SplitLargeMeshes postprocessing step
|
||||
*/
|
||||
|
||||
|
|
@ -129,7 +129,7 @@ void SplitLargeMeshesProcess_Triangle::UpdateNode(aiNode* pcNode,
|
|||
pcNode->mMeshes[b] = aiEntries[b];
|
||||
}
|
||||
|
||||
// recusively update all other nodes
|
||||
// recursively update all other nodes
|
||||
for (unsigned int i = 0; i < pcNode->mNumChildren;++i) {
|
||||
UpdateNode ( pcNode->mChildren[i], avList );
|
||||
}
|
||||
|
|
@ -353,7 +353,7 @@ void SplitLargeMeshesProcess_Vertex::Execute( aiScene* pScene) {
|
|||
|
||||
std::vector<std::pair<aiMesh*, unsigned int> > avList;
|
||||
|
||||
//Check for point cloud first,
|
||||
//Check for point cloud first,
|
||||
//Do not process point cloud, splitMesh works only with faces data
|
||||
for (unsigned int a = 0; a < pScene->mNumMeshes; a++) {
|
||||
if ( pScene->mMeshes[a]->mPrimitiveTypes == aiPrimitiveType_POINT ) {
|
||||
|
|
@ -575,8 +575,9 @@ void SplitLargeMeshesProcess_Vertex::SplitMesh(
|
|||
for (unsigned int k = 0; k < pMesh->mNumBones;++k) {
|
||||
// check whether the bone is existing
|
||||
BoneWeightList* pcWeightList;
|
||||
if ((pcWeightList = (BoneWeightList*)pcMesh->mBones[k])) {
|
||||
aiBone* pcOldBone = pMesh->mBones[k];
|
||||
pcWeightList = (BoneWeightList *)pcMesh->mBones[k];
|
||||
if (nullptr != pcWeightList) {
|
||||
aiBone *pcOldBone = pMesh->mBones[k];
|
||||
aiBone* pcOut( nullptr );
|
||||
*ppCurrent++ = pcOut = new aiBone();
|
||||
pcOut->mName = aiString(pcOldBone->mName);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -92,9 +92,8 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
* are applied is - as always - scaling, rotation, translation.
|
||||
*/
|
||||
|
||||
char szTemp[512];
|
||||
int rounded = 0;
|
||||
|
||||
int rounded;
|
||||
char szTemp[512];
|
||||
|
||||
/* Optimize the rotation angle. That's slightly difficult as
|
||||
* we have an inprecise floating-point number (when comparing
|
||||
|
|
@ -105,10 +104,11 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
if (info.mRotation)
|
||||
{
|
||||
float out = info.mRotation;
|
||||
if ((rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI)))))
|
||||
rounded = static_cast<int>((info.mRotation / static_cast<float>(AI_MATH_TWO_PI)));
|
||||
if (rounded)
|
||||
{
|
||||
out -= rounded * static_cast<float>(AI_MATH_PI);
|
||||
ASSIMP_LOG_INFO_F("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out);
|
||||
ASSIMP_LOG_INFO("Texture coordinate rotation ", info.mRotation, " can be simplified to ", out);
|
||||
}
|
||||
|
||||
// Next step - convert negative rotation angles to positives
|
||||
|
|
@ -125,7 +125,8 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
* type (e.g. if mirroring is active there IS a difference between
|
||||
* offset 2 and 3)
|
||||
*/
|
||||
if ((rounded = (int)info.mTranslation.x)) {
|
||||
rounded = (int)info.mTranslation.x;
|
||||
if (rounded) {
|
||||
float out = 0.0f;
|
||||
szTemp[0] = 0;
|
||||
if (aiTextureMapMode_Wrap == info.mapU) {
|
||||
|
|
@ -158,7 +159,8 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
* type (e.g. if mirroring is active there IS a difference between
|
||||
* offset 2 and 3)
|
||||
*/
|
||||
if ((rounded = (int)info.mTranslation.y)) {
|
||||
rounded = (int)info.mTranslation.y;
|
||||
if (rounded) {
|
||||
float out = 0.0f;
|
||||
szTemp[0] = 0;
|
||||
if (aiTextureMapMode_Wrap == info.mapV) {
|
||||
|
|
@ -176,7 +178,7 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
}
|
||||
else if (aiTextureMapMode_Clamp == info.mapV || aiTextureMapMode_Decal == info.mapV) {
|
||||
// Clamp - translations beyond 1,1 are senseless
|
||||
::ai_snprintf(szTemp,512,"[c] UV V offset %f canbe clamped to 1.0f",info.mTranslation.y);
|
||||
::ai_snprintf(szTemp,512,"[c] UV V offset %f can be clamped to 1.0f",info.mTranslation.y);
|
||||
|
||||
out = 1.f;
|
||||
}
|
||||
|
|
@ -185,7 +187,6 @@ void TextureTransformStep::PreProcessUVTransform(STransformVecInfo& info)
|
|||
info.mTranslation.y = out;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
@ -428,7 +429,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
|
|||
// at the end of the list
|
||||
bool ref[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
||||
for (unsigned int n = 0; n < AI_MAX_NUMBER_OF_TEXTURECOORDS;++n)
|
||||
ref[n] = (!mesh->mTextureCoords[n] ? true : false);
|
||||
ref[n] = !mesh->mTextureCoords[n];
|
||||
|
||||
for (it = trafo.begin();it != trafo.end(); ++it)
|
||||
ref[(*it).uvIndex] = true;
|
||||
|
|
@ -447,7 +448,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
|
|||
if (size > AI_MAX_NUMBER_OF_TEXTURECOORDS) {
|
||||
|
||||
if (!DefaultLogger::isNullLogger()) {
|
||||
ASSIMP_LOG_ERROR_F(static_cast<unsigned int>(trafo.size()), " UV channels required but just ",
|
||||
ASSIMP_LOG_ERROR(static_cast<unsigned int>(trafo.size()), " UV channels required but just ",
|
||||
AI_MAX_NUMBER_OF_TEXTURECOORDS, " available");
|
||||
}
|
||||
size = AI_MAX_NUMBER_OF_TEXTURECOORDS;
|
||||
|
|
@ -507,7 +508,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
|
|||
aiVector3D* dest, *end;
|
||||
dest = mesh->mTextureCoords[n];
|
||||
|
||||
ai_assert(NULL != src);
|
||||
ai_assert(nullptr != src);
|
||||
|
||||
// Copy the data to the destination array
|
||||
if (dest != src)
|
||||
|
|
@ -538,7 +539,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
|
|||
m5.a3 += trl.x; m5.b3 += trl.y;
|
||||
matrix = m2 * m4 * matrix * m3 * m5;
|
||||
|
||||
for (src = dest; src != end; ++src) { /* manual homogenious divide */
|
||||
for (src = dest; src != end; ++src) { /* manual homogeneous divide */
|
||||
src->z = 1.f;
|
||||
*src = matrix * *src;
|
||||
src->x /= src->z;
|
||||
|
|
@ -556,7 +557,7 @@ void TextureTransformStep::Execute( aiScene* pScene)
|
|||
if (!DefaultLogger::isNullLogger()) {
|
||||
|
||||
if (transformedChannels) {
|
||||
ASSIMP_LOG_INFO_F("TransformUVCoordsProcess end: ", outChannels, " output channels (in: ", inChannels, ", modified: ", transformedChannels,")");
|
||||
ASSIMP_LOG_INFO("TransformUVCoordsProcess end: ", outChannels, " output channels (in: ", inChannels, ", modified: ", transformedChannels,")");
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG("TransformUVCoordsProcess finished");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
|
@ -64,6 +64,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "Common/PolyTools.h"
|
||||
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
//#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||
//#define AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
|
|
@ -75,6 +76,87 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Helper struct used to simplify NGON encoding functions.
|
||||
*/
|
||||
struct NGONEncoder {
|
||||
NGONEncoder() : mLastNGONFirstIndex((unsigned int)-1) {}
|
||||
|
||||
/**
|
||||
* @brief Encode the current triangle, and make sure it is recognized as a triangle.
|
||||
*
|
||||
* This method will rotate indices in tri if needed in order to avoid tri to be considered
|
||||
* part of the previous ngon. This method is to be used whenever you want to emit a real triangle,
|
||||
* and make sure it is seen as a triangle.
|
||||
*
|
||||
* @param tri Triangle to encode.
|
||||
*/
|
||||
void ngonEncodeTriangle(aiFace * tri) {
|
||||
ai_assert(tri->mNumIndices == 3);
|
||||
|
||||
// Rotate indices in new triangle to avoid ngon encoding false ngons
|
||||
// Otherwise, the new triangle would be considered part of the previous NGON.
|
||||
if (isConsideredSameAsLastNgon(tri)) {
|
||||
std::swap(tri->mIndices[0], tri->mIndices[2]);
|
||||
std::swap(tri->mIndices[1], tri->mIndices[2]);
|
||||
}
|
||||
|
||||
mLastNGONFirstIndex = tri->mIndices[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encode a quad (2 triangles) in ngon encoding, and make sure they are seen as a single ngon.
|
||||
*
|
||||
* @param tri1 First quad triangle
|
||||
* @param tri2 Second quad triangle
|
||||
*
|
||||
* @pre Triangles must be properly fanned from the most appropriate vertex.
|
||||
*/
|
||||
void ngonEncodeQuad(aiFace *tri1, aiFace *tri2) {
|
||||
ai_assert(tri1->mNumIndices == 3);
|
||||
ai_assert(tri2->mNumIndices == 3);
|
||||
ai_assert(tri1->mIndices[0] == tri2->mIndices[0]);
|
||||
|
||||
// If the selected fanning vertex is the same as the previously
|
||||
// emitted ngon, we use the opposite vertex which also happens to work
|
||||
// for tri-fanning a concave quad.
|
||||
// ref: https://github.com/assimp/assimp/pull/3695#issuecomment-805999760
|
||||
if (isConsideredSameAsLastNgon(tri1)) {
|
||||
// Right-rotate indices for tri1 (index 2 becomes the new fanning vertex)
|
||||
std::swap(tri1->mIndices[0], tri1->mIndices[2]);
|
||||
std::swap(tri1->mIndices[1], tri1->mIndices[2]);
|
||||
|
||||
// Left-rotate indices for tri2 (index 2 becomes the new fanning vertex)
|
||||
std::swap(tri2->mIndices[1], tri2->mIndices[2]);
|
||||
std::swap(tri2->mIndices[0], tri2->mIndices[2]);
|
||||
|
||||
ai_assert(tri1->mIndices[0] == tri2->mIndices[0]);
|
||||
}
|
||||
|
||||
mLastNGONFirstIndex = tri1->mIndices[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check whether this triangle would be considered part of the lastly emitted ngon or not.
|
||||
*
|
||||
* @param tri Current triangle.
|
||||
* @return true If used as is, this triangle will be part of last ngon.
|
||||
* @return false If used as is, this triangle is not considered part of the last ngon.
|
||||
*/
|
||||
bool isConsideredSameAsLastNgon(const aiFace * tri) const {
|
||||
ai_assert(tri->mNumIndices == 3);
|
||||
return tri->mIndices[0] == mLastNGONFirstIndex;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int mLastNGONFirstIndex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
TriangulateProcess::TriangulateProcess()
|
||||
|
|
@ -141,7 +223,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
}
|
||||
|
||||
// Find out how many output faces we'll get
|
||||
unsigned int numOut = 0, max_out = 0;
|
||||
uint32_t numOut = 0, max_out = 0;
|
||||
bool get_normals = true;
|
||||
for( unsigned int a = 0; a < pMesh->mNumFaces; a++) {
|
||||
aiFace& face = pMesh->mFaces[a];
|
||||
|
|
@ -161,7 +243,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
// Just another check whether aiMesh::mPrimitiveTypes is correct
|
||||
ai_assert(numOut != pMesh->mNumFaces);
|
||||
|
||||
aiVector3D* nor_out = NULL;
|
||||
aiVector3D *nor_out = nullptr;
|
||||
|
||||
// if we don't have normals yet, but expect them to be a cheap side
|
||||
// product of triangulation anyway, allocate storage for them.
|
||||
|
|
@ -174,10 +256,15 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
pMesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE;
|
||||
pMesh->mPrimitiveTypes &= ~aiPrimitiveType_POLYGON;
|
||||
|
||||
// The mesh becomes NGON encoded now, during the triangulation process.
|
||||
pMesh->mPrimitiveTypes |= aiPrimitiveType_NGONEncodingFlag;
|
||||
|
||||
aiFace* out = new aiFace[numOut](), *curOut = out;
|
||||
std::vector<aiVector3D> temp_verts3d(max_out+2); /* temporary storage for vertices */
|
||||
std::vector<aiVector2D> temp_verts(max_out+2);
|
||||
|
||||
NGONEncoder ngonEncoder;
|
||||
|
||||
// Apply vertex colors to represent the face winding?
|
||||
#ifdef AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING
|
||||
if (!pMesh->mColors[0])
|
||||
|
|
@ -219,8 +306,11 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
aiFace& nface = *curOut++;
|
||||
nface.mNumIndices = face.mNumIndices;
|
||||
nface.mIndices = face.mIndices;
|
||||
face.mIndices = nullptr;
|
||||
|
||||
// points and lines don't require ngon encoding (and are not supported either!)
|
||||
if (nface.mNumIndices == 3) ngonEncoder.ngonEncodeTriangle(&nface);
|
||||
|
||||
face.mIndices = NULL;
|
||||
continue;
|
||||
}
|
||||
// optimized code for quadrilaterals
|
||||
|
|
@ -272,7 +362,10 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
sface.mIndices[2] = temp[(start_vertex + 3) % 4];
|
||||
|
||||
// prevent double deletion of the indices field
|
||||
face.mIndices = NULL;
|
||||
face.mIndices = nullptr;
|
||||
|
||||
ngonEncoder.ngonEncodeQuad(&nface, &sface);
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
|
@ -283,11 +376,11 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
// modeling suite to make extensive use of highly concave, monster polygons ...
|
||||
// so we need to apply the full 'ear cutting' algorithm to get it right.
|
||||
|
||||
// RERQUIREMENT: polygon is expected to be simple and *nearly* planar.
|
||||
// REQUIREMENT: polygon is expected to be simple and *nearly* planar.
|
||||
// We project it onto a plane to get a 2d triangle.
|
||||
|
||||
// Collect all vertices of of the polygon.
|
||||
for (tmp = 0; tmp < max; ++tmp) {
|
||||
for (tmp = 0; tmp < max; ++tmp) {
|
||||
temp_verts3d[tmp] = verts[idx[tmp]];
|
||||
}
|
||||
|
||||
|
|
@ -419,7 +512,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
num = 0;
|
||||
break;
|
||||
|
||||
curOut -= (max-num); /* undo all previous work */
|
||||
/*curOut -= (max-num); // undo all previous work
|
||||
for (tmp = 0; tmp < max-2; ++tmp) {
|
||||
aiFace& nface = *curOut++;
|
||||
|
||||
|
|
@ -433,7 +526,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
|
||||
}
|
||||
num = 0;
|
||||
break;
|
||||
break;*/
|
||||
}
|
||||
|
||||
aiFace& nface = *curOut++;
|
||||
|
|
@ -490,7 +583,7 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
// drop dumb 0-area triangles - deactivated for now:
|
||||
//FindDegenerates post processing step can do the same thing
|
||||
//if (std::fabs(GetArea2D(temp_verts[i[0]],temp_verts[i[1]],temp_verts[i[2]])) < 1e-5f) {
|
||||
// ASSIMP_LOG_DEBUG("Dropping triangle with area 0");
|
||||
// ASSIMP_LOG_VERBOSE_DEBUG("Dropping triangle with area 0");
|
||||
// --curOut;
|
||||
|
||||
// delete[] f->mIndices;
|
||||
|
|
@ -507,11 +600,16 @@ bool TriangulateProcess::TriangulateMesh( aiMesh* pMesh)
|
|||
i[0] = idx[i[0]];
|
||||
i[1] = idx[i[1]];
|
||||
i[2] = idx[i[2]];
|
||||
|
||||
// IMPROVEMENT: Polygons are not supported yet by this ngon encoding + triangulation step.
|
||||
// So we encode polygons as regular triangles. No way to reconstruct the original
|
||||
// polygon in this case.
|
||||
ngonEncoder.ngonEncodeTriangle(f);
|
||||
++f;
|
||||
}
|
||||
|
||||
delete[] face.mIndices;
|
||||
face.mIndices = NULL;
|
||||
face.mIndices = nullptr;
|
||||
}
|
||||
|
||||
#ifdef AI_BUILD_TRIANGULATE_DEBUG_POLYS
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
|||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
Copyright (c) 2006-2022, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
|
@ -55,6 +55,7 @@ struct aiBone;
|
|||
struct aiMesh;
|
||||
struct aiAnimation;
|
||||
struct aiNodeAnim;
|
||||
struct aiMeshMorphAnim;
|
||||
struct aiTexture;
|
||||
struct aiMaterial;
|
||||
struct aiNode;
|
||||
|
|
@ -150,6 +151,13 @@ protected:
|
|||
void Validate( const aiAnimation* pAnimation,
|
||||
const aiNodeAnim* pBoneAnim);
|
||||
|
||||
/** Validates a mesh morph animation channel.
|
||||
* @param pAnimation Input animation.
|
||||
* @param pMeshMorphAnim Mesh morph animation channel.
|
||||
* */
|
||||
void Validate( const aiAnimation* pAnimation,
|
||||
const aiMeshMorphAnim* pMeshMorphAnim);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Validates a node and all of its subnodes
|
||||
* @param Node Input node*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue