Merge branch 'master' into memleak

pull/5134/head
Kim Kulling 2023-06-13 19:46:56 +02:00 committed by GitHub
commit 3ccf242bdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 48 deletions

View File

@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF)
IF(ASSIMP_HUNTER_ENABLED) IF(ASSIMP_HUNTER_ENABLED)
include("cmake-modules/HunterGate.cmake") include("cmake-modules/HunterGate.cmake")
HunterGate( HunterGate(
URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz" URL "https://github.com/cpp-pm/hunter/archive/v0.24.17.tar.gz"
SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd" SHA1 "e6396699e414120e32557fe92db097b7655b760b"
) )
add_definitions(-DASSIMP_USE_HUNTER) add_definitions(-DASSIMP_USE_HUNTER)

View File

@ -229,14 +229,19 @@ bool MD5Parser::ParseSection(Section &out) {
// parse a string, enclosed in quotation marks // parse a string, enclosed in quotation marks
#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \ #define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \
while ('\"' != *sz) \ out.length = 0; \
while ('\"' != *sz && '\0' != *sz) \
++sz; \ ++sz; \
if ('\0' != *sz) { \
const char *szStart = ++sz; \ const char *szStart = ++sz; \
while ('\"' != *sz) \ while ('\"' != *sz && '\0' != *sz) \
++sz; \ ++sz; \
if ('\0' != *sz) { \
const char *szEnd = (sz++); \ const char *szEnd = (sz++); \
out.length = (ai_uint32)(szEnd - szStart); \ out.length = (ai_uint32)(szEnd - szStart); \
::memcpy(out.data, szStart, out.length); \ ::memcpy(out.data, szStart, out.length); \
} \
} \
out.data[out.length] = '\0'; out.data[out.length] = '\0';
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// .MD5MESH parsing function // .MD5MESH parsing function

View File

@ -100,8 +100,6 @@ glTF2Importer::glTF2Importer() :
// empty // empty
} }
glTF2Importer::~glTF2Importer() = default;
const aiImporterDesc *glTF2Importer::GetInfo() const { const aiImporterDesc *glTF2Importer::GetInfo() const {
return &desc; return &desc;
} }
@ -443,10 +441,10 @@ static inline bool CheckValidFacesIndices(aiFace *faces, unsigned nFaces, unsign
#endif // ASSIMP_BUILD_DEBUG #endif // ASSIMP_BUILD_DEBUG
template <typename T> template <typename T>
aiColor4D *GetVertexColorsForType(Ref<Accessor> input) { aiColor4D *GetVertexColorsForType(Ref<Accessor> input, std::vector<unsigned int> *vertexRemappingTable) {
constexpr float max = std::numeric_limits<T>::max(); constexpr float max = std::numeric_limits<T>::max();
aiColor4t<T> *colors; aiColor4t<T> *colors;
input->ExtractData(colors); input->ExtractData(colors, vertexRemappingTable);
auto output = new aiColor4D[input->count]; auto output = new aiColor4D[input->count];
for (size_t i = 0; i < input->count; i++) { for (size_t i = 0; i < input->count; i++) {
output[i] = aiColor4D( output[i] = aiColor4D(
@ -461,20 +459,26 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
ASSIMP_LOG_DEBUG("Importing ", r.meshes.Size(), " meshes"); ASSIMP_LOG_DEBUG("Importing ", r.meshes.Size(), " meshes");
std::vector<std::unique_ptr<aiMesh>> meshes; std::vector<std::unique_ptr<aiMesh>> meshes;
unsigned int k = 0;
meshOffsets.clear(); meshOffsets.clear();
meshOffsets.reserve(r.meshes.Size() + 1);
mVertexRemappingTables.clear();
// Count the number of aiMeshes
unsigned int num_aiMeshes = 0;
for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
meshOffsets.push_back(num_aiMeshes);
num_aiMeshes += unsigned(r.meshes[m].primitives.size());
}
meshOffsets.push_back(num_aiMeshes); // add a last element so we can always do meshOffsets[n+1] - meshOffsets[n]
std::vector<unsigned int> usedVertexIndices;
std::vector<unsigned int> reverseMappingIndices; std::vector<unsigned int> reverseMappingIndices;
std::vector<unsigned int> indexBuffer; std::vector<unsigned int> indexBuffer;
meshes.reserve(num_aiMeshes);
mVertexRemappingTables.resize(num_aiMeshes);
for (unsigned int m = 0; m < r.meshes.Size(); ++m) { for (unsigned int m = 0; m < r.meshes.Size(); ++m) {
Mesh &mesh = r.meshes[m]; Mesh &mesh = r.meshes[m];
meshOffsets.push_back(k);
k += unsigned(mesh.primitives.size());
for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { for (unsigned int p = 0; p < mesh.primitives.size(); ++p) {
Mesh::Primitive &prim = mesh.primitives[p]; Mesh::Primitive &prim = mesh.primitives[p];
@ -488,14 +492,14 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
// Extract used vertices: // Extract used vertices:
bool useIndexBuffer = prim.indices; bool useIndexBuffer = prim.indices;
std::vector<unsigned int>* vertexRemappingTable = nullptr; std::vector<unsigned int> *vertexRemappingTable = nullptr;
if (useIndexBuffer) { if (useIndexBuffer) {
size_t count = prim.indices->count; size_t count = prim.indices->count;
indexBuffer.resize(count); indexBuffer.resize(count);
usedVertexIndices.clear();
reverseMappingIndices.clear(); reverseMappingIndices.clear();
usedVertexIndices.reserve(count / 3); // this is a very rough heuristic to reduce re-allocations vertexRemappingTable = &mVertexRemappingTables[meshes.size()];
vertexRemappingTable = &usedVertexIndices; vertexRemappingTable->reserve(count / 3); // this is a very rough heuristic to reduce re-allocations
Accessor::Indexer data = prim.indices->GetIndexer(); Accessor::Indexer data = prim.indices->GetIndexer();
if (!data.IsValid()) { if (!data.IsValid()) {
throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name)); throw DeadlyImportError("GLTF: Invalid accessor without data in mesh ", getContextForErrorMessages(mesh.id, mesh.name));
@ -515,8 +519,8 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
reverseMappingIndices.resize(index + 1, unusedIndex); reverseMappingIndices.resize(index + 1, unusedIndex);
} }
if (reverseMappingIndices[index] == unusedIndex) { if (reverseMappingIndices[index] == unusedIndex) {
reverseMappingIndices[index] = static_cast<unsigned int>(usedVertexIndices.size()); reverseMappingIndices[index] = static_cast<unsigned int>(vertexRemappingTable->size());
usedVertexIndices.push_back(index); vertexRemappingTable->push_back(index);
} }
indexBuffer[i] = reverseMappingIndices[index]; indexBuffer[i] = reverseMappingIndices[index];
} }
@ -597,9 +601,9 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
attr.color[c]->ExtractData(aim->mColors[c], vertexRemappingTable); attr.color[c]->ExtractData(aim->mColors[c], vertexRemappingTable);
} else { } else {
if (componentType == glTF2::ComponentType_UNSIGNED_BYTE) { if (componentType == glTF2::ComponentType_UNSIGNED_BYTE) {
aim->mColors[c] = GetVertexColorsForType<unsigned char>(attr.color[c]); aim->mColors[c] = GetVertexColorsForType<unsigned char>(attr.color[c], vertexRemappingTable);
} else if (componentType == glTF2::ComponentType_UNSIGNED_SHORT) { } else if (componentType == glTF2::ComponentType_UNSIGNED_SHORT) {
aim->mColors[c] = GetVertexColorsForType<unsigned short>(attr.color[c]); aim->mColors[c] = GetVertexColorsForType<unsigned short>(attr.color[c], vertexRemappingTable);
} }
} }
} }
@ -875,8 +879,6 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
} }
} }
meshOffsets.push_back(k);
CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes);
} }
@ -1009,7 +1011,8 @@ static void GetNodeTransform(aiMatrix4x4 &matrix, const glTF2::Node &node) {
} }
} }
static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std::vector<aiVertexWeight>> &map) { static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std::vector<aiVertexWeight>> &map, std::vector<unsigned int>* vertexRemappingTablePtr) {
Mesh::Primitive::Attributes &attr = primitive.attributes; Mesh::Primitive::Attributes &attr = primitive.attributes;
if (attr.weight.empty() || attr.joint.empty()) { if (attr.weight.empty() || attr.joint.empty()) {
return; return;
@ -1018,14 +1021,14 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std
return; return;
} }
size_t num_vertices = attr.weight[0]->count; size_t num_vertices = 0;
struct Weights { struct Weights {
float values[4]; float values[4];
}; };
Weights **weights = new Weights*[attr.weight.size()]; Weights **weights = new Weights*[attr.weight.size()];
for (size_t w = 0; w < attr.weight.size(); ++w) { for (size_t w = 0; w < attr.weight.size(); ++w) {
attr.weight[w]->ExtractData(weights[w]); num_vertices = attr.weight[w]->ExtractData(weights[w], vertexRemappingTablePtr);
} }
struct Indices8 { struct Indices8 {
@ -1039,12 +1042,12 @@ static void BuildVertexWeightMapping(Mesh::Primitive &primitive, std::vector<std
if (attr.joint[0]->GetElementSize() == 4) { if (attr.joint[0]->GetElementSize() == 4) {
indices8 = new Indices8*[attr.joint.size()]; indices8 = new Indices8*[attr.joint.size()];
for (size_t j = 0; j < attr.joint.size(); ++j) { for (size_t j = 0; j < attr.joint.size(); ++j) {
attr.joint[j]->ExtractData(indices8[j]); attr.joint[j]->ExtractData(indices8[j], vertexRemappingTablePtr);
} }
} else { } else {
indices16 = new Indices16 *[attr.joint.size()]; indices16 = new Indices16 *[attr.joint.size()];
for (size_t j = 0; j < attr.joint.size(); ++j) { for (size_t j = 0; j < attr.joint.size(); ++j) {
attr.joint[j]->ExtractData(indices16[j]); attr.joint[j]->ExtractData(indices16[j], vertexRemappingTablePtr);
} }
} }
// //
@ -1109,7 +1112,7 @@ void ParseExtras(aiMetadata* metadata, const Extras& extras) {
} }
} }
aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) { aiNode *glTF2Importer::ImportNode(glTF2::Asset &r, glTF2::Ref<glTF2::Node> &ptr) {
Node &node = *ptr; Node &node = *ptr;
aiNode *ainode = new aiNode(GetNodeName(node)); aiNode *ainode = new aiNode(GetNodeName(node));
@ -1121,7 +1124,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
std::fill(ainode->mChildren, ainode->mChildren + ainode->mNumChildren, nullptr); std::fill(ainode->mChildren, ainode->mChildren + ainode->mNumChildren, nullptr);
for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { for (unsigned int i = 0; i < ainode->mNumChildren; ++i) {
aiNode *child = ImportNode(pScene, r, meshOffsets, node.children[i]); aiNode *child = ImportNode(r, node.children[i]);
child->mParent = ainode; child->mParent = ainode;
ainode->mChildren[i] = child; ainode->mChildren[i] = child;
} }
@ -1154,11 +1157,13 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
if (node.skin) { if (node.skin) {
for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) {
aiMesh *mesh = pScene->mMeshes[meshOffsets[mesh_idx] + primitiveNo]; unsigned int aiMeshIdx = meshOffsets[mesh_idx] + primitiveNo;
aiMesh *mesh = mScene->mMeshes[aiMeshIdx];
unsigned int numBones = static_cast<unsigned int>(node.skin->jointNames.size()); unsigned int numBones = static_cast<unsigned int>(node.skin->jointNames.size());
std::vector<unsigned int> *vertexRemappingTablePtr = mVertexRemappingTables[aiMeshIdx].empty() ? nullptr : &mVertexRemappingTables[aiMeshIdx];
std::vector<std::vector<aiVertexWeight>> weighting(numBones); std::vector<std::vector<aiVertexWeight>> weighting(numBones);
BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting, vertexRemappingTablePtr);
mesh->mNumBones = static_cast<unsigned int>(numBones); mesh->mNumBones = static_cast<unsigned int>(numBones);
mesh->mBones = new aiBone *[mesh->mNumBones]; mesh->mBones = new aiBone *[mesh->mNumBones];
@ -1175,7 +1180,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
// mapping which makes things doubly-slow. // mapping which makes things doubly-slow.
mat4 *pbindMatrices = nullptr; mat4 *pbindMatrices = nullptr;
node.skin->inverseBindMatrices->ExtractData(pbindMatrices); node.skin->inverseBindMatrices->ExtractData(pbindMatrices, nullptr);
for (uint32_t i = 0; i < numBones; ++i) { for (uint32_t i = 0; i < numBones; ++i) {
const std::vector<aiVertexWeight> &weights = weighting[i]; const std::vector<aiVertexWeight> &weights = weighting[i];
@ -1221,11 +1226,11 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
} }
if (node.camera) { if (node.camera) {
pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; mScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName;
} }
if (node.light) { if (node.light) {
pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; mScene->mLights[node.light.GetIndex()]->mName = ainode->mName;
// range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual // range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
// it is added to meta data of parent node, because there is no other place to put it // it is added to meta data of parent node, because there is no other place to put it
@ -1257,7 +1262,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) {
// The root nodes // The root nodes
unsigned int numRootNodes = unsigned(rootNodes.size()); unsigned int numRootNodes = unsigned(rootNodes.size());
if (numRootNodes == 1) { // a single root node: use it if (numRootNodes == 1) { // a single root node: use it
mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); mScene->mRootNode = ImportNode(r, rootNodes[0]);
} else if (numRootNodes > 1) { // more than one root node: create a fake root } else if (numRootNodes > 1) { // more than one root node: create a fake root
aiNode *root = mScene->mRootNode = new aiNode("ROOT"); aiNode *root = mScene->mRootNode = new aiNode("ROOT");
@ -1265,7 +1270,7 @@ void glTF2Importer::ImportNodes(glTF2::Asset &r) {
std::fill(root->mChildren, root->mChildren + numRootNodes, nullptr); std::fill(root->mChildren, root->mChildren + numRootNodes, nullptr);
for (unsigned int i = 0; i < numRootNodes; ++i) { for (unsigned int i = 0; i < numRootNodes; ++i) {
aiNode *node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); aiNode *node = ImportNode(r, rootNodes[i]);
node->mParent = root; node->mParent = root;
root->mChildren[root->mNumChildren++] = node; root->mChildren[root->mNumChildren++] = node;
} }
@ -1666,6 +1671,7 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
// clean all member arrays // clean all member arrays
meshOffsets.clear(); meshOffsets.clear();
mVertexRemappingTables.clear();
mEmbeddedTexIdxs.clear(); mEmbeddedTexIdxs.clear();
this->mScene = pScene; this->mScene = pScene;

View File

@ -43,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_GLTF2IMPORTER_H_INC #define AI_GLTF2IMPORTER_H_INC
#include <assimp/BaseImporter.h> #include <assimp/BaseImporter.h>
#include <AssetLib/glTF2/glTF2Asset.h>
struct aiNode; struct aiNode;
@ -59,7 +60,7 @@ namespace Assimp {
class glTF2Importer : public BaseImporter { class glTF2Importer : public BaseImporter {
public: public:
glTF2Importer(); glTF2Importer();
~glTF2Importer() override; ~glTF2Importer() override = default;
bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override; bool CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const override;
protected: protected:
@ -76,10 +77,12 @@ private:
void ImportNodes(glTF2::Asset &a); void ImportNodes(glTF2::Asset &a);
void ImportAnimations(glTF2::Asset &a); void ImportAnimations(glTF2::Asset &a);
void ImportCommonMetadata(glTF2::Asset &a); void ImportCommonMetadata(glTF2::Asset &a);
aiNode *ImportNode(glTF2::Asset &r, glTF2::Ref<glTF2::Node> &ptr);
private: private:
std::vector<unsigned int> meshOffsets; std::vector<unsigned int> meshOffsets;
std::vector<int> mEmbeddedTexIdxs; std::vector<int> mEmbeddedTexIdxs;
std::vector<std::vector<unsigned int>> mVertexRemappingTables; // for each converted aiMesh in the scene, it stores a list of vertices that are actually used
aiScene *mScene; aiScene *mScene;
/// An instance of rapidjson::IRemoteSchemaDocumentProvider /// An instance of rapidjson::IRemoteSchemaDocumentProvider

View File

@ -81,6 +81,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene) {
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) { void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) {
this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS); this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS);
this->mRemoveEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, 1) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -172,9 +173,9 @@ void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) {
} }
// remove empty bones // remove empty bones
#ifdef AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES if (mRemoveEmptyBones) {
pMesh->mNumBones = removeEmptyBones(pMesh); pMesh->mNumBones = removeEmptyBones(pMesh);
#endif // AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES }
if (!DefaultLogger::isNullLogger()) { if (!DefaultLogger::isNullLogger()) {
ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones); ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones);

View File

@ -133,6 +133,7 @@ public:
/** Maximum number of bones influencing any single vertex. */ /** Maximum number of bones influencing any single vertex. */
unsigned int mMaxWeights; unsigned int mMaxWeights;
bool mRemoveEmptyBones;
}; };
} // end of namespace Assimp } // end of namespace Assimp