Merge branch 'master' into scenepreprocessor-memoryleak
commit
ea60563822
|
@ -641,7 +641,11 @@ void ParseVectorDataArray(std::vector<aiVector3D>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
|
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t count3 = count / 3;
|
const uint32_t count3 = count / 3;
|
||||||
out.reserve(count3);
|
out.reserve(count3);
|
||||||
|
@ -728,7 +732,11 @@ void ParseVectorDataArray(std::vector<aiColor4D>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
|
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t count4 = count / 4;
|
const uint32_t count4 = count / 4;
|
||||||
out.reserve(count4);
|
out.reserve(count4);
|
||||||
|
@ -807,7 +815,11 @@ void ParseVectorDataArray(std::vector<aiVector2D>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
|
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
const uint32_t count2 = count / 2;
|
const uint32_t count2 = count / 2;
|
||||||
out.reserve(count2);
|
out.reserve(count2);
|
||||||
|
@ -879,7 +891,11 @@ void ParseVectorDataArray(std::vector<int>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * 4);
|
uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
out.reserve(count);
|
out.reserve(count);
|
||||||
|
|
||||||
|
@ -937,7 +953,11 @@ void ParseVectorDataArray(std::vector<float>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * (type == 'd' ? 8 : 4));
|
uint64_t dataToRead = static_cast<uint64_t>(count) * (type == 'd' ? 8 : 4);
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
if (type == 'd') {
|
if (type == 'd') {
|
||||||
const double* d = reinterpret_cast<const double*>(&buff[0]);
|
const double* d = reinterpret_cast<const double*>(&buff[0]);
|
||||||
|
@ -998,7 +1018,11 @@ void ParseVectorDataArray(std::vector<unsigned int>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * 4);
|
uint64_t dataToRead = static_cast<uint64_t>(count) * 4;
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
out.reserve(count);
|
out.reserve(count);
|
||||||
|
|
||||||
|
@ -1063,7 +1087,11 @@ void ParseVectorDataArray(std::vector<uint64_t>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * 8);
|
uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
out.reserve(count);
|
out.reserve(count);
|
||||||
|
|
||||||
|
@ -1121,7 +1149,11 @@ void ParseVectorDataArray(std::vector<int64_t>& out, const Element& el)
|
||||||
ReadBinaryDataArray(type, count, data, end, buff, el);
|
ReadBinaryDataArray(type, count, data, end, buff, el);
|
||||||
|
|
||||||
ai_assert(data == end);
|
ai_assert(data == end);
|
||||||
ai_assert(buff.size() == count * 8);
|
uint64_t dataToRead = static_cast<uint64_t>(count) * 8;
|
||||||
|
ai_assert(buff.size() == dataToRead);
|
||||||
|
if (dataToRead > buff.size()) {
|
||||||
|
ParseError("Invalid read size (binary)",&el);
|
||||||
|
}
|
||||||
|
|
||||||
out.reserve(count);
|
out.reserve(count);
|
||||||
|
|
||||||
|
|
|
@ -863,6 +863,7 @@ struct Sampler : public Object {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Scene : public Object {
|
struct Scene : public Object {
|
||||||
|
std::string name;
|
||||||
std::vector<Ref<Node>> nodes;
|
std::vector<Ref<Node>> nodes;
|
||||||
|
|
||||||
Scene() {}
|
Scene() {}
|
||||||
|
|
|
@ -1400,6 +1400,11 @@ inline void Node::Read(Value &obj, Asset &r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Scene::Read(Value &obj, Asset &r) {
|
inline void Scene::Read(Value &obj, Asset &r) {
|
||||||
|
if (Value *scene_name = FindString(obj, "name")) {
|
||||||
|
if (scene_name->IsString()) {
|
||||||
|
this->name = scene_name->GetString();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (Value *array = FindArray(obj, "nodes")) {
|
if (Value *array = FindArray(obj, "nodes")) {
|
||||||
for (unsigned int i = 0; i < array->Size(); ++i) {
|
for (unsigned int i = 0; i < array->Size(); ++i) {
|
||||||
if (!(*array)[i].IsUint()) continue;
|
if (!(*array)[i].IsUint()) continue;
|
||||||
|
|
|
@ -453,11 +453,16 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||||
aim->mNumAnimMeshes = (unsigned int)targets.size();
|
aim->mNumAnimMeshes = (unsigned int)targets.size();
|
||||||
aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes];
|
aim->mAnimMeshes = new aiAnimMesh *[aim->mNumAnimMeshes];
|
||||||
for (size_t i = 0; i < targets.size(); i++) {
|
for (size_t i = 0; i < targets.size(); i++) {
|
||||||
aim->mAnimMeshes[i] = aiCreateAnimMesh(aim);
|
bool needPositions = targets[i].position.size() > 0;
|
||||||
|
bool needNormals = targets[i].normal.size() > 0;
|
||||||
|
bool needTangents = targets[i].tangent.size() > 0;
|
||||||
|
// GLTF morph does not support colors and texCoords
|
||||||
|
aim->mAnimMeshes[i] = aiCreateAnimMesh(aim,
|
||||||
|
needPositions, needNormals, needTangents, false, false);
|
||||||
aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]);
|
aiAnimMesh &aiAnimMesh = *(aim->mAnimMeshes[i]);
|
||||||
Mesh::Primitive::Target &target = targets[i];
|
Mesh::Primitive::Target &target = targets[i];
|
||||||
|
|
||||||
if (target.position.size() > 0) {
|
if (needPositions) {
|
||||||
aiVector3D *positionDiff = nullptr;
|
aiVector3D *positionDiff = nullptr;
|
||||||
target.position[0]->ExtractData(positionDiff);
|
target.position[0]->ExtractData(positionDiff);
|
||||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
||||||
|
@ -465,7 +470,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||||
}
|
}
|
||||||
delete[] positionDiff;
|
delete[] positionDiff;
|
||||||
}
|
}
|
||||||
if (target.normal.size() > 0) {
|
if (needNormals) {
|
||||||
aiVector3D *normalDiff = nullptr;
|
aiVector3D *normalDiff = nullptr;
|
||||||
target.normal[0]->ExtractData(normalDiff);
|
target.normal[0]->ExtractData(normalDiff);
|
||||||
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
for (unsigned int vertexId = 0; vertexId < aim->mNumVertices; vertexId++) {
|
||||||
|
@ -473,7 +478,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
|
||||||
}
|
}
|
||||||
delete[] normalDiff;
|
delete[] normalDiff;
|
||||||
}
|
}
|
||||||
if (target.tangent.size() > 0) {
|
if (needTangents) {
|
||||||
Tangent *tangent = nullptr;
|
Tangent *tangent = nullptr;
|
||||||
attr.tangent[0]->ExtractData(tangent);
|
attr.tangent[0]->ExtractData(tangent);
|
||||||
|
|
||||||
|
@ -1069,9 +1074,11 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler
|
||||||
samplers.translation->output->ExtractData(values);
|
samplers.translation->output->ExtractData(values);
|
||||||
anim->mNumPositionKeys = static_cast<uint32_t>(samplers.translation->input->count);
|
anim->mNumPositionKeys = static_cast<uint32_t>(samplers.translation->input->count);
|
||||||
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys];
|
||||||
|
unsigned int ii = (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
|
||||||
for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
|
for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) {
|
||||||
anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
anim->mPositionKeys[i].mValue = values[i];
|
anim->mPositionKeys[i].mValue = values[ii];
|
||||||
|
ii += (samplers.translation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
|
||||||
}
|
}
|
||||||
delete[] times;
|
delete[] times;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
@ -1091,12 +1098,14 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler
|
||||||
samplers.rotation->output->ExtractData(values);
|
samplers.rotation->output->ExtractData(values);
|
||||||
anim->mNumRotationKeys = static_cast<uint32_t>(samplers.rotation->input->count);
|
anim->mNumRotationKeys = static_cast<uint32_t>(samplers.rotation->input->count);
|
||||||
anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
|
anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys];
|
||||||
|
unsigned int ii = (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
|
||||||
for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
|
for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) {
|
||||||
anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
anim->mRotationKeys[i].mValue.x = values[i].w;
|
anim->mRotationKeys[i].mValue.x = values[ii].w;
|
||||||
anim->mRotationKeys[i].mValue.y = values[i].x;
|
anim->mRotationKeys[i].mValue.y = values[ii].x;
|
||||||
anim->mRotationKeys[i].mValue.z = values[i].y;
|
anim->mRotationKeys[i].mValue.z = values[ii].y;
|
||||||
anim->mRotationKeys[i].mValue.w = values[i].z;
|
anim->mRotationKeys[i].mValue.w = values[ii].z;
|
||||||
|
ii += (samplers.rotation->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
|
||||||
}
|
}
|
||||||
delete[] times;
|
delete[] times;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
@ -1117,9 +1126,11 @@ aiNodeAnim *CreateNodeAnim(glTF2::Asset&, Node &node, AnimationSamplers &sampler
|
||||||
samplers.scale->output->ExtractData(values);
|
samplers.scale->output->ExtractData(values);
|
||||||
anim->mNumScalingKeys = static_cast<uint32_t>(samplers.scale->input->count);
|
anim->mNumScalingKeys = static_cast<uint32_t>(samplers.scale->input->count);
|
||||||
anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
|
anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys];
|
||||||
|
unsigned int ii = (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
|
||||||
for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) {
|
for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) {
|
||||||
anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
anim->mScalingKeys[i].mValue = values[i];
|
anim->mScalingKeys[i].mValue = values[ii];
|
||||||
|
ii += (samplers.scale->interpolation == Interpolation_CUBICSPLINE) ? 3 : 1;
|
||||||
}
|
}
|
||||||
delete[] times;
|
delete[] times;
|
||||||
delete[] values;
|
delete[] values;
|
||||||
|
@ -1148,11 +1159,14 @@ aiMeshMorphAnim *CreateMeshMorphAnim(glTF2::Asset&, Node &node, AnimationSampler
|
||||||
samplers.weight->output->ExtractData(values);
|
samplers.weight->output->ExtractData(values);
|
||||||
anim->mNumKeys = static_cast<uint32_t>(samplers.weight->input->count);
|
anim->mNumKeys = static_cast<uint32_t>(samplers.weight->input->count);
|
||||||
|
|
||||||
const unsigned int numMorphs = (unsigned int)samplers.weight->output->count / anim->mNumKeys;
|
// for Interpolation_CUBICSPLINE can have more outputs
|
||||||
|
const unsigned int weightStride = (unsigned int)samplers.weight->output->count / anim->mNumKeys;
|
||||||
|
const unsigned int numMorphs = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? weightStride - 2 : weightStride;
|
||||||
|
|
||||||
anim->mKeys = new aiMeshMorphKey[anim->mNumKeys];
|
anim->mKeys = new aiMeshMorphKey[anim->mNumKeys];
|
||||||
unsigned int k = 0u;
|
unsigned int ii = (samplers.weight->interpolation == Interpolation_CUBICSPLINE) ? 1 : 0;
|
||||||
for (unsigned int i = 0u; i < anim->mNumKeys; ++i) {
|
for (unsigned int i = 0u; i < anim->mNumKeys; ++i) {
|
||||||
|
unsigned int k = weightStride * i + ii;
|
||||||
anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds;
|
||||||
anim->mKeys[i].mNumValuesAndWeights = numMorphs;
|
anim->mKeys[i].mNumValuesAndWeights = numMorphs;
|
||||||
anim->mKeys[i].mValues = new unsigned int[numMorphs];
|
anim->mKeys[i].mValues = new unsigned int[numMorphs];
|
||||||
|
@ -1386,6 +1400,9 @@ void glTF2Importer::InternReadFile(const std::string &pFile, aiScene *pScene, IO
|
||||||
// read the asset file
|
// read the asset file
|
||||||
glTF2::Asset asset(pIOHandler);
|
glTF2::Asset asset(pIOHandler);
|
||||||
asset.Load(pFile, GetExtension(pFile) == "glb");
|
asset.Load(pFile, GetExtension(pFile) == "glb");
|
||||||
|
if (asset.scene) {
|
||||||
|
pScene->mName = asset.scene->name;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Copy the data out
|
// Copy the data out
|
||||||
|
|
|
@ -44,27 +44,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh, bool needPositions, bool needNormals, bool needTangents, bool needColors, bool needTexCoords)
|
||||||
{
|
{
|
||||||
aiAnimMesh *animesh = new aiAnimMesh;
|
aiAnimMesh *animesh = new aiAnimMesh;
|
||||||
animesh->mNumVertices = mesh->mNumVertices;
|
animesh->mNumVertices = mesh->mNumVertices;
|
||||||
if (mesh->mVertices) {
|
if (needPositions && mesh->mVertices) {
|
||||||
animesh->mVertices = new aiVector3D[animesh->mNumVertices];
|
animesh->mVertices = new aiVector3D[animesh->mNumVertices];
|
||||||
std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D));
|
std::memcpy(animesh->mVertices, mesh->mVertices, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
}
|
}
|
||||||
if (mesh->mNormals) {
|
if (needNormals && mesh->mNormals) {
|
||||||
animesh->mNormals = new aiVector3D[animesh->mNumVertices];
|
animesh->mNormals = new aiVector3D[animesh->mNumVertices];
|
||||||
std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D));
|
std::memcpy(animesh->mNormals, mesh->mNormals, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
}
|
}
|
||||||
if (mesh->mTangents) {
|
if (needTangents && mesh->mTangents) {
|
||||||
animesh->mTangents = new aiVector3D[animesh->mNumVertices];
|
animesh->mTangents = new aiVector3D[animesh->mNumVertices];
|
||||||
std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D));
|
std::memcpy(animesh->mTangents, mesh->mTangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
}
|
}
|
||||||
if (mesh->mBitangents) {
|
if (needTangents && mesh->mBitangents) {
|
||||||
animesh->mBitangents = new aiVector3D[animesh->mNumVertices];
|
animesh->mBitangents = new aiVector3D[animesh->mNumVertices];
|
||||||
std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D));
|
std::memcpy(animesh->mBitangents, mesh->mBitangents, mesh->mNumVertices * sizeof(aiVector3D));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (needColors) {
|
||||||
for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
|
for (int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) {
|
||||||
if (mesh->mColors[i]) {
|
if (mesh->mColors[i]) {
|
||||||
animesh->mColors[i] = new aiColor4D[animesh->mNumVertices];
|
animesh->mColors[i] = new aiColor4D[animesh->mNumVertices];
|
||||||
|
@ -73,7 +74,9 @@ aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
||||||
animesh->mColors[i] = nullptr;
|
animesh->mColors[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needTexCoords) {
|
||||||
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||||
if (mesh->mTextureCoords[i]) {
|
if (mesh->mTextureCoords[i]) {
|
||||||
animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices];
|
animesh->mTextureCoords[i] = new aiVector3D[animesh->mNumVertices];
|
||||||
|
@ -82,6 +85,7 @@ aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh)
|
||||||
animesh->mTextureCoords[i] = nullptr;
|
animesh->mTextureCoords[i] = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return animesh;
|
return animesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
|
||||||
|
|
||||||
Copyright (c) 2006-2020, assimp team
|
Copyright (c) 2006-2020, assimp team
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use of this software in source and binary forms,
|
Redistribution and use of this software in source and binary forms,
|
||||||
|
@ -45,25 +43,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* @brief Implementation of the FindDegenerates post-process step.
|
* @brief Implementation of the FindDegenerates post-process step.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// internal headers
|
|
||||||
#include "ProcessHelper.h"
|
#include "ProcessHelper.h"
|
||||||
#include "FindDegenerates.h"
|
#include "FindDegenerates.h"
|
||||||
|
|
||||||
#include <assimp/Exceptional.h>
|
#include <assimp/Exceptional.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
//remove mesh at position 'index' from the scene
|
// Correct node indices to meshes and remove references to deleted mesh
|
||||||
static void removeMesh(aiScene* pScene, unsigned const index);
|
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap);
|
||||||
//correct node indices to meshes and remove references to deleted mesh
|
|
||||||
static void updateSceneGraph(aiNode* pNode, unsigned const index);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
FindDegeneratesProcess::FindDegeneratesProcess()
|
FindDegeneratesProcess::FindDegeneratesProcess() :
|
||||||
: mConfigRemoveDegenerates( false )
|
mConfigRemoveDegenerates( false ),
|
||||||
, mConfigCheckAreaOfTriangle( false ){
|
mConfigCheckAreaOfTriangle( false ){
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,50 +87,50 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
|
||||||
// Executes the post processing step on the given imported data.
|
// Executes the post processing step on the given imported data.
|
||||||
void FindDegeneratesProcess::Execute( aiScene* pScene) {
|
void FindDegeneratesProcess::Execute( aiScene* pScene) {
|
||||||
ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
|
ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
|
||||||
for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
|
if ( nullptr == pScene) {
|
||||||
{
|
return;
|
||||||
//Do not process point cloud, ExecuteOnMesh works only with faces data
|
}
|
||||||
|
|
||||||
|
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])) {
|
if ((pScene->mMeshes[i]->mPrimitiveTypes != aiPrimitiveType::aiPrimitiveType_POINT) && ExecuteOnMesh(pScene->mMeshes[i])) {
|
||||||
removeMesh(pScene, i);
|
delete pScene->mMeshes[i];
|
||||||
--i; //the current i is removed, do not skip the next one
|
// 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");
|
ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removeMesh(aiScene* pScene, unsigned const index) {
|
static void updateSceneGraph(aiNode* pNode, const std::unordered_map<unsigned int, unsigned int>& meshMap) {
|
||||||
//we start at index and copy the pointers one position forward
|
unsigned int targetIndex = 0;
|
||||||
//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) {
|
|
||||||
for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
|
for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
|
||||||
if (pNode->mMeshes[i] > index) {
|
const unsigned int sourceMeshIndex = pNode->mMeshes[i];
|
||||||
--(pNode->mMeshes[i]);
|
auto it = meshMap.find(sourceMeshIndex);
|
||||||
continue;
|
if (it != meshMap.end()) {
|
||||||
}
|
pNode->mMeshes[targetIndex] = it->second;
|
||||||
if (pNode->mMeshes[i] == index) {
|
++targetIndex;
|
||||||
for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) {
|
|
||||||
pNode->mMeshes[j] = pNode->mMeshes[j+1];
|
|
||||||
}
|
|
||||||
--(pNode->mNumMeshes);
|
|
||||||
--i;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pNode->mNumMeshes = targetIndex;
|
||||||
//recurse to all children
|
//recurse to all children
|
||||||
for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
|
for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
|
||||||
updateSceneGraph(pNode->mChildren[i], index);
|
updateSceneGraph(pNode->mChildren[i], meshMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,9 +58,19 @@ namespace Assimp {
|
||||||
/**
|
/**
|
||||||
* Create aiAnimMesh from aiMesh.
|
* Create aiAnimMesh from aiMesh.
|
||||||
* @param mesh The input mesh to create an animated mesh from.
|
* @param mesh The input mesh to create an animated mesh from.
|
||||||
|
* @param needPositions If true, positions will be copied from.
|
||||||
|
* @param needNormals If true, normals will be copied from.
|
||||||
|
* @param needTangents If true, tangents and bitangents will be copied from.
|
||||||
|
* @param needColors If true, colors will be copied from.
|
||||||
|
* @param needTexCoords If true, texCoords will be copied from.
|
||||||
* @return The new created animated mesh.
|
* @return The new created animated mesh.
|
||||||
*/
|
*/
|
||||||
ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh);
|
ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh,
|
||||||
|
bool needPositions = true,
|
||||||
|
bool needNormals = true,
|
||||||
|
bool needTangents = true,
|
||||||
|
bool needColors = true,
|
||||||
|
bool needTexCoords = true);
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
||||||
|
|
|
@ -341,6 +341,9 @@ struct aiScene
|
||||||
*/
|
*/
|
||||||
C_STRUCT aiMetadata* mMetaData;
|
C_STRUCT aiMetadata* mMetaData;
|
||||||
|
|
||||||
|
/** The name of the scene itself.
|
||||||
|
*/
|
||||||
|
C_STRUCT aiString mName;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
#include "UnitTestPCH.h"
|
#include "UnitTestPCH.h"
|
||||||
|
|
||||||
|
#include "../../include/assimp/scene.h"
|
||||||
#include "PostProcessing/FindDegenerates.h"
|
#include "PostProcessing/FindDegenerates.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
|
@ -147,3 +150,59 @@ TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) {
|
||||||
|
|
||||||
EXPECT_EQ(mMesh->mNumUVComponents[1] - 100, mMesh->mNumFaces);
|
EXPECT_EQ(mMesh->mNumUVComponents[1] - 100, mMesh->mNumFaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::unique_ptr<aiMesh> getDegenerateMesh()
|
||||||
|
{
|
||||||
|
std::unique_ptr<aiMesh> mesh(new aiMesh);
|
||||||
|
mesh->mNumVertices = 2;
|
||||||
|
mesh->mVertices = new aiVector3D[2];
|
||||||
|
mesh->mVertices[0] = aiVector3D{ 0.0f, 0.0f, 0.0f };
|
||||||
|
mesh->mVertices[1] = aiVector3D{ 1.0f, 0.0f, 0.0f };
|
||||||
|
mesh->mNumFaces = 1;
|
||||||
|
mesh->mFaces = new aiFace[1];
|
||||||
|
mesh->mFaces[0].mNumIndices = 3;
|
||||||
|
mesh->mFaces[0].mIndices = new unsigned int[3];
|
||||||
|
mesh->mFaces[0].mIndices[0] = 0;
|
||||||
|
mesh->mFaces[0].mIndices[1] = 1;
|
||||||
|
mesh->mFaces[0].mIndices[2] = 0;
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(FindDegeneratesProcessTest, meshRemoval) {
|
||||||
|
mProcess->EnableAreaCheck(true);
|
||||||
|
mProcess->EnableInstantRemoval(true);
|
||||||
|
mProcess->ExecuteOnMesh(mMesh);
|
||||||
|
|
||||||
|
std::unique_ptr<aiScene> scene(new aiScene);
|
||||||
|
scene->mNumMeshes = 5;
|
||||||
|
scene->mMeshes = new aiMesh*[5];
|
||||||
|
|
||||||
|
/// Use the mesh which doesn't get completely stripped of faces from the main test.
|
||||||
|
aiMesh* meshWhichSurvives = mMesh;
|
||||||
|
mMesh = nullptr;
|
||||||
|
|
||||||
|
scene->mMeshes[0] = getDegenerateMesh().release();
|
||||||
|
scene->mMeshes[1] = getDegenerateMesh().release();
|
||||||
|
scene->mMeshes[2] = meshWhichSurvives;
|
||||||
|
scene->mMeshes[3] = getDegenerateMesh().release();
|
||||||
|
scene->mMeshes[4] = getDegenerateMesh().release();
|
||||||
|
|
||||||
|
scene->mRootNode = new aiNode;
|
||||||
|
scene->mRootNode->mNumMeshes = 5;
|
||||||
|
scene->mRootNode->mMeshes = new unsigned int[5];
|
||||||
|
scene->mRootNode->mMeshes[0] = 0;
|
||||||
|
scene->mRootNode->mMeshes[1] = 1;
|
||||||
|
scene->mRootNode->mMeshes[2] = 2;
|
||||||
|
scene->mRootNode->mMeshes[3] = 3;
|
||||||
|
scene->mRootNode->mMeshes[4] = 4;
|
||||||
|
|
||||||
|
mProcess->Execute(scene.get());
|
||||||
|
|
||||||
|
EXPECT_EQ(scene->mNumMeshes, 1);
|
||||||
|
EXPECT_EQ(scene->mMeshes[0], meshWhichSurvives);
|
||||||
|
EXPECT_EQ(scene->mRootNode->mNumMeshes, 1);
|
||||||
|
EXPECT_EQ(scene->mRootNode->mMeshes[0], 0);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue