diff --git a/assimpTargets.cmake.in b/assimpTargets.cmake.in index ab1a8d2c7b..afef9cbd11 100644 --- a/assimpTargets.cmake.in +++ b/assimpTargets.cmake.in @@ -5,6 +5,9 @@ if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) endif() cmake_policy(PUSH) cmake_policy(VERSION 2.6) +# Required for the evaluation of "if(@BUILD_SHARED_LIBS@)" below to function +cmake_policy(SET CMP0012 NEW) + #---------------------------------------------------------------- # Generated CMake target import file. #---------------------------------------------------------------- diff --git a/code/Collada/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp index 6fd31ed3b4..a93dfa59aa 100644 --- a/code/Collada/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -92,6 +92,36 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p } // end of namespace Assimp +// ------------------------------------------------------------------------------------------------ +// Encodes a string into a valid XML ID using the xsd:ID schema qualifications. +static const std::string XMLIDEncode(const std::string& name) { + const char XML_ID_CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-."; + const unsigned int XML_ID_CHARS_COUNT = sizeof(XML_ID_CHARS) / sizeof(char); + + if (name.length() == 0) { + return name; + } + + std::stringstream idEncoded; + + // xsd:ID must start with letter or underscore + if (!((name[0] >= 'A' && name[0] <= 'z') || name[0] == '_')) { + idEncoded << '_'; + } + + for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) { + // xsd:ID can only contain letters, digits, underscores, hyphens and periods + if (strchr(XML_ID_CHARS, *it) != nullptr) { + idEncoded << *it; + } else { + // Select placeholder character based on invalid character to prevent name collisions + idEncoded << XML_ID_CHARS[(*it) % XML_ID_CHARS_COUNT]; + } + } + + return idEncoded.str(); +} + // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) @@ -146,7 +176,7 @@ void ColladaExporter::WriteFile() { // useless Collada fu at the end, just in case we haven't had enough indirections, yet. mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mRootNode->mName.C_Str()) + "\" />" << endstr; + mOutput << startstr << "mRootNode->mName.C_Str()) + "\" />" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -356,9 +386,10 @@ void ColladaExporter::WriteCamerasLibrary() { void ColladaExporter::WriteCamera(size_t pIndex){ const aiCamera *cam = mScene->mCameras[pIndex]; - const std::string idstrEscaped = XMLEscape(cam->mName.C_Str()); + const std::string cameraName = XMLEscape(cam->mName.C_Str()); + const std::string cameraId = XMLIDEncode(cam->mName.C_Str()); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); @@ -412,10 +443,11 @@ void ColladaExporter::WriteLightsLibrary() { void ColladaExporter::WriteLight(size_t pIndex){ const aiLight *light = mScene->mLights[pIndex]; - const std::string idstrEscaped = XMLEscape(light->mName.C_Str()); + const std::string lightName = XMLEscape(light->mName.C_Str()); + const std::string lightId = XMLIDEncode(light->mName.C_Str()); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); @@ -586,7 +618,7 @@ static bool isalnum_C(char c) { void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) { if( !pSurface.texture.empty() ) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << ""; @@ -619,7 +651,7 @@ void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std } else { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } PopTag(); mOutput << startstr << "" << endstr; @@ -633,21 +665,21 @@ void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture if( !pSurface.texture.empty() ) { - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << XMLEscape(pMatName) << "-" << pTypeName << "-image" << endstr; + mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-image" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << XMLEscape(pMatName) << "-" << pTypeName << "-surface" << endstr; + mOutput << startstr << "" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface" << endstr; PopTag(); mOutput << startstr << "" << endstr; PopTag(); @@ -699,11 +731,6 @@ void ColladaExporter::WriteMaterials() materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName); } } - for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) { - if( !isalnum_C( *it ) ) { - *it = '_'; - } - } aiShadingMode shading = aiShadingMode_Flat; materials[a].shading_model = "phong"; @@ -768,7 +795,7 @@ void ColladaExporter::WriteMaterials() { const Material& mat = *it; // this is so ridiculous it must be right - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; PushTag(); @@ -819,9 +846,9 @@ void ColladaExporter::WriteMaterials() for( std::vector::const_iterator it = materials.begin(); it != materials.end(); ++it ) { const Material& mat = *it; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; } @@ -850,8 +877,8 @@ void ColladaExporter::WriteControllerLibrary() void ColladaExporter::WriteController( size_t pIndex) { const aiMesh* mesh = mScene->mMeshes[pIndex]; - const std::string idstr = GetMeshId( pIndex); - const std::string idstrEscaped = XMLEscape(idstr); + const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); + const std::string idstrEscaped = XMLIDEncode(idstr); if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) return; @@ -886,7 +913,7 @@ void ColladaExporter::WriteController( size_t pIndex) mOutput << startstr << "mNumBones << "\">"; for( size_t i = 0; i < mesh->mNumBones; ++i ) - mOutput << XMLEscape(mesh->mBones[i]->mName.C_Str()) << " "; + mOutput << XMLIDEncode(mesh->mBones[i]->mName.C_Str()) << " "; mOutput << "" << endstr; @@ -1021,14 +1048,15 @@ void ColladaExporter::WriteGeometryLibrary() void ColladaExporter::WriteGeometry( size_t pIndex) { const aiMesh* mesh = mScene->mMeshes[pIndex]; - const std::string idstr = GetMeshId( pIndex); - const std::string idstrEscaped = XMLEscape(idstr); + const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str(); + const std::string geometryName = XMLEscape(idstr); + const std::string geometryId = XMLIDEncode(idstr); if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) return; // opening tag - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; @@ -1059,9 +1087,9 @@ void ColladaExporter::WriteGeometry( size_t pIndex) // assemble vertex structure // Only write input for POSITION since we will write other as shared inputs in polygon definition - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PopTag(); mOutput << startstr << "" << endstr; @@ -1079,18 +1107,18 @@ void ColladaExporter::WriteGeometry( size_t pIndex) { mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; if( mesh->HasNormals() ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) { if( mesh->HasTextureCoords(static_cast(a)) ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) { if( mesh->HasVertexColors(static_cast(a) ) ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } mOutput << startstr << "

"; @@ -1113,18 +1141,18 @@ void ColladaExporter::WriteGeometry( size_t pIndex) { mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; if( mesh->HasNormals() ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) { if( mesh->HasTextureCoords(static_cast(a)) ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) { if( mesh->HasVertexColors(static_cast(a) ) ) - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; } mOutput << startstr << ""; @@ -1173,13 +1201,13 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy return; } - std::string arrayId = pIdString + "-array"; + std::string arrayId = XMLIDEncode(pIdString) + "-array"; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); // source array - mOutput << startstr << " "; + mOutput << startstr << " "; PushTag(); if( pType == FloatType_TexCoord2 ) @@ -1265,11 +1293,12 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy // Writes the scene library void ColladaExporter::WriteSceneLibrary() { - const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str()); + const std::string sceneName = XMLEscape(mScene->mRootNode->mName.C_Str()); + const std::string sceneId = XMLIDEncode(mScene->mRootNode->mName.C_Str()); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); // start recursive write at the root node @@ -1300,7 +1329,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) idstr = idstr + ending; } - const std::string idstrEscaped = XMLEscape(idstr); + const std::string idstrEscaped = XMLIDEncode(idstr); mOutput << startstr << "" << endstr; PushTag(); @@ -1372,13 +1401,13 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) } const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-interpolation"); - std::string arrayId = node_idstr + "-array"; + std::string arrayId = XMLIDEncode(node_idstr) + "-array"; - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); // source array - mOutput << startstr << " "; + mOutput << startstr << " "; for( size_t a = 0; a < names.size(); ++a ) { mOutput << names[a] << " "; } @@ -1387,7 +1416,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); mOutput << startstr << "" << endstr; @@ -1409,12 +1438,12 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) { // samplers const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler"); - mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr; - mOutput << startstr << "mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr; - mOutput << startstr << "mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr; + mOutput << startstr << "mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr; + mOutput << startstr << "mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr; + mOutput << startstr << "mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr; PopTag(); mOutput << startstr << "" << endstr; @@ -1426,7 +1455,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) { // channels - mOutput << startstr << "mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLEscape(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr; + mOutput << startstr << "mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLIDEncode(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr; } } @@ -1437,8 +1466,6 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex) // ------------------------------------------------------------------------------------------------ void ColladaExporter::WriteAnimationsLibrary() { - const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str()); - if ( mScene->mNumAnimations > 0 ) { mOutput << startstr << "" << endstr; PushTag(); @@ -1546,16 +1573,17 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) } } - const std::string node_name_escaped = XMLEscape(pNode->mName.data); + const std::string node_id = XMLIDEncode(pNode->mName.data); + const std::string node_name = XMLEscape(pNode->mName.data); mOutput << startstr << "" << endstr; PushTag(); @@ -1594,14 +1622,14 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) //check if it is a camera node for(size_t i=0; imNumCameras; i++){ if(mScene->mCameras[i]->mName == pNode->mName){ - mOutput << startstr <<"" << endstr; + mOutput << startstr <<"" << endstr; break; } } //check if it is a light node for(size_t i=0; imNumLights; i++){ if(mScene->mLights[i]->mName == pNode->mName){ - mOutput << startstr <<"" << endstr; + mOutput << startstr <<"" << endstr; break; } } @@ -1615,15 +1643,17 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) continue; + const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str(); + if( mesh->mNumBones == 0 ) { - mOutput << startstr << "mMeshes[a])) << "\">" << endstr; + mOutput << startstr << "" << endstr; PushTag(); } else { mOutput << startstr - << "mMeshes[a])) << "-skin\">" + << "" << endstr; PushTag(); @@ -1631,7 +1661,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) // use the first bone to find skeleton root const aiNode * skeletonRootBoneNode = findSkeletonRootNode( pScene, mesh ); if ( skeletonRootBoneNode ) { - mFoundSkeletonRootNodeID = XMLEscape( skeletonRootBoneNode->mName.C_Str() ); + mFoundSkeletonRootNodeID = XMLIDEncode( skeletonRootBoneNode->mName.C_Str() ); } mOutput << startstr << "#" << mFoundSkeletonRootNodeID << "" << endstr; } @@ -1639,7 +1669,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) PushTag(); mOutput << startstr << "" << endstr; PushTag(); - mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; + mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; PushTag(); for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) { diff --git a/code/Common/BaseImporter.cpp b/code/Common/BaseImporter.cpp index b77bbfe23c..5c1e605549 100644 --- a/code/Common/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -67,7 +67,20 @@ using namespace Assimp; // Constructor to be privately used by Importer BaseImporter::BaseImporter() AI_NO_EXCEPT : m_progress() { - // nothing to do here + /** + * Assimp Importer + * unit conversions available + * if you need another measurment unit add it below. + * it's currently defined in assimp that we prefer meters. + * + * NOTE: Initialised here rather than in the header file + * to workaround a VS2013 bug with brace initialisers + * */ + importerUnits[ImporterUnits::M] = 1.0; + importerUnits[ImporterUnits::CM] = 0.01; + importerUnits[ImporterUnits::MM] = 0.001; + importerUnits[ImporterUnits::INCHES] = 0.0254; + importerUnits[ImporterUnits::FEET] = 0.3048; } // ------------------------------------------------------------------------------------------------ diff --git a/code/glTF/glTFImporter.cpp b/code/glTF/glTFImporter.cpp index 9ecd742f60..9ec13ea696 100644 --- a/code/glTF/glTFImporter.cpp +++ b/code/glTF/glTFImporter.cpp @@ -170,6 +170,8 @@ void glTFImporter::ImportMaterials(glTF::Asset& r) { if (mScene->mNumMaterials == 0) { mScene->mNumMaterials = 1; + // Delete the array of length zero created above. + delete[] mScene->mMaterials; mScene->mMaterials = new aiMaterial*[1]; mScene->mMaterials[0] = new aiMaterial(); } @@ -330,6 +332,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) case PrimitiveMode_LINES: { nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = nFaces * 2; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 2) { SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1)); @@ -353,6 +359,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) case PrimitiveMode_TRIANGLES: { nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = nFaces * 3; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 3) { SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); @@ -395,6 +405,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) case PrimitiveMode_LINES: { nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = nFaces * 2; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 2) { SetFace(faces[i / 2], i, i + 1); @@ -418,6 +432,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) case PrimitiveMode_TRIANGLES: { nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = nFaces * 3; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 3) { SetFace(faces[i / 3], i, i + 1, i + 2); diff --git a/code/glTF2/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp index c2106e26ff..b3141fd960 100644 --- a/code/glTF2/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -530,6 +530,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) case PrimitiveMode_LINES: { nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = nFaces * 2; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 2) { SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1)); @@ -553,6 +557,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) case PrimitiveMode_TRIANGLES: { nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = nFaces * 3; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 3) { SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); @@ -604,6 +612,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) case PrimitiveMode_LINES: { nFaces = count / 2; + if (nFaces * 2 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped."); + count = nFaces * 2; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 2) { SetFace(faces[i / 2], i, i + 1); @@ -627,6 +639,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) case PrimitiveMode_TRIANGLES: { nFaces = count / 3; + if (nFaces * 3 != count) { + ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped."); + count = nFaces * 3; + } faces = new aiFace[nFaces]; for (unsigned int i = 0; i < count; i += 3) { SetFace(faces[i / 3], i, i + 1, i + 2); diff --git a/include/assimp/BaseImporter.h b/include/assimp/BaseImporter.h index bd0451be32..ad8a3dafd8 100644 --- a/include/assimp/BaseImporter.h +++ b/include/assimp/BaseImporter.h @@ -196,16 +196,13 @@ class ASSIMP_API BaseImporter { /** * Assimp Importer * unit conversions available - * if you need another measurment unit add it below. - * it's currently defined in assimp that we prefer meters. + * NOTE: Valid options are initialised in the + * constructor in the implementation file to + * work around a VS2013 compiler bug if support + * for that compiler is dropped in the future + * initialisation can be moved back here * */ - std::map importerUnits = { - {ImporterUnits::M, 1}, - {ImporterUnits::CM, 0.01}, - {ImporterUnits::MM, 0.001}, - {ImporterUnits::INCHES, 0.0254}, - {ImporterUnits::FEET, 0.3048} - }; + std::map importerUnits; virtual void SetApplicationUnits( const ImporterUnits& unit ) { diff --git a/test/models/glTF/IncorrectVertexArrays/Cube.bin b/test/models/glTF/IncorrectVertexArrays/Cube.bin new file mode 100644 index 0000000000..fa55b363a3 Binary files /dev/null and b/test/models/glTF/IncorrectVertexArrays/Cube.bin differ diff --git a/test/models/glTF/IncorrectVertexArrays/Cube_v1.gltf b/test/models/glTF/IncorrectVertexArrays/Cube_v1.gltf new file mode 100644 index 0000000000..c076c5bcb1 --- /dev/null +++ b/test/models/glTF/IncorrectVertexArrays/Cube_v1.gltf @@ -0,0 +1,283 @@ +{ + "accessors" : { + "accessor_0" : { + "bufferView" : "bufferView_0", + "byteOffset" : 0, + "componentType" : 5123, + "count" : 36, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + "accessor_1" : { + "bufferView" : "bufferView_1", + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000001 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + "accessor_2" : { + "bufferView" : "bufferView_2", + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + "accessor_3" : { + "bufferView" : "bufferView_3", + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + -0.000000, + -0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -0.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC4" + }, + "accessor_4" : { + "bufferView" : "bufferView_4", + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000 + ], + "type" : "VEC2" + }, + "accessor_5" : { + "bufferView" : "bufferView_1", + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "type" : "VEC3" + }, + "accessor_6" : { + "bufferView" : "bufferView_1", + "byteOffset" : 0, + "componentType" : 5126, + "count" : 35, + "type" : "VEC3" + }, + "accessor_7" : { + "bufferView" : "bufferView_0", + "byteOffset" : 0, + "componentType" : 5123, + "count" : 35, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + } + }, + "asset" : { + "generator" : "VKTS glTF 2.0 exporter", + "version" : "1.0" + }, + "bufferViews" : { + "bufferView_0" : { + "buffer" : "buffer_0", + "byteLength" : 72, + "byteOffset" : 0, + "target" : 34963 + }, + "bufferView_1" : { + "buffer" : "buffer_0", + "byteLength" : 432, + "byteOffset" : 72, + "target" : 34962 + }, + "bufferView_2" : { + "buffer" : "buffer_0", + "byteLength" : 432, + "byteOffset" : 504, + "target" : 34962 + }, + "bufferView_3" : { + "buffer" : "buffer_0", + "byteLength" : 576, + "byteOffset" : 936, + "target" : 34962 + }, + "bufferView_4" : { + "buffer" : "buffer_0", + "byteLength" : 288, + "byteOffset" : 1512, + "target" : 34962 + } + }, + "buffers" : { + "buffer_0" : { + "byteLength" : 514, + "uri" : "Cube.bin" + } + }, + "meshes" : { + "mesh_0" : { + "name" : "Cube", + "primitives" : [ + { + "attributes" : { + "POSITION" : "accessor_1" + }, + "mode" : 4 + } + ] + }, + "mesh_1" : { + "name" : "TruncatedCube", + "primitives" : [ { + "attributes" : { + "POSITION" : "accessor_6" + }, + "mode" : 4 + } ] + }, + "mesh_2" : { + "name" : "Lines", + "primitives" : [ { + "attributes" : { + "POSITION" : "accessor_5" + }, + "mode" : 1 + } ] + }, + "mesh_3" : { + "name" : "TruncatedLines", + "primitives" : [ { + "attributes" : { + "POSITION" : "accessor_6" + }, + "mode" : 1 + } ] + }, + "mesh_4" : { + "name" : "IndexedCube", + "primitives" : [ { + "attributes" : { + "POSITION" : "accessor_1" + }, + "mode" : 4, + "indices" : "accessor_0" + } ] + }, + "mesh_5" : { + "name" : "TruncatedIndexedCube", + "primitives" : [ { + "attributes" : { + "POSITION" : "accessor_6" + }, + "mode" : 4, + "indices" : "accessor_7" + } ] + }, + "mesh_6" : { + "name" : "IndexedLines", + "primitives" : [ { + "attributes" : { + "POSITION" : "accessor_5" + }, + "mode" : 1, + "indices" : "accessor_0" + } ] + }, + "mesh_7" : { + "name" : "TruncatedIndexedLines", + "primitives" : [ { + "attributes" : { + "POSITION" : "accessor_6" + }, + "mode" : 1, + "indices" : "accessor_7" + } ] + } + }, + "nodes" : { + "node_0" : { + "meshes" : [ "mesh_0" ], + "name" : "Cube" + }, + "node_1" : { + "meshes" : [ "mesh_1" ], + "name" : "TruncatedCube", + "translation": [ 2.5, 0.0, 2.5 ] + }, + "node_2" : { + "meshes" : [ "mesh_2" ], + "name" : "Lines", + "translation": [ 2.5, 0.0, 0.0 ] + }, + "node_3" : { + "meshes" : [ "mesh_3" ], + "name" : "TruncatedLines", + "translation": [ 2.5, 0.0, -2.5 ] + }, + "node_4" : { + "meshes" : [ "mesh_4" ], + "name" : "IndexedCube", + "translation": [ -2.5, 0.0, 2.5 ] + }, + "node_5" : { + "meshes" : [ "mesh_5" ], + "name" : "TruncatedIndexedCube", + "translation": [ -2.5, 0.0, 0.0 ] + }, + "node_6" : { + "meshes" : [ "mesh_6" ], + "name" : "IndexedLines", + "translation": [ -2.5, 0.0, -2.5 ] + }, + "node_7" : { + "meshes" : [ "mesh_7" ], + "name" : "TruncatedIndexedLines", + "translation": [ 0.0, 0.0, -2.5 ] + } + }, + "scene" : "defaultScene", + "scenes" : { + "defaultScene" : { + "nodes" : [ + "node_0", "node_1", "node_2", "node_3", "node_4", "node_5", "node_6", "node_7" + ] + } + } +} diff --git a/test/models/glTF2/IncorrectVertexArrays/Cube.bin b/test/models/glTF2/IncorrectVertexArrays/Cube.bin new file mode 100644 index 0000000000..fa55b363a3 Binary files /dev/null and b/test/models/glTF2/IncorrectVertexArrays/Cube.bin differ diff --git a/test/models/glTF2/IncorrectVertexArrays/Cube.gltf b/test/models/glTF2/IncorrectVertexArrays/Cube.gltf new file mode 100644 index 0000000000..0ca17e1e53 --- /dev/null +++ b/test/models/glTF2/IncorrectVertexArrays/Cube.gltf @@ -0,0 +1,286 @@ +{ + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 36, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000001 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC3" + }, + { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + -0.000000, + -0.000000, + 1.000000 + ], + "min" : [ + 0.000000, + -0.000000, + -1.000000, + -1.000000 + ], + "type" : "VEC4" + }, + { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "max" : [ + 1.000000, + 1.000000 + ], + "min" : [ + -1.000000, + -1.000000 + ], + "type" : "VEC2" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 36, + "type" : "VEC3" + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 35, + "type" : "VEC3" + }, + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 35, + "max" : [ + 35 + ], + "min" : [ + 0 + ], + "type" : "SCALAR" + } + ], + "asset" : { + "generator" : "VKTS glTF 2.0 exporter", + "version" : "2.0" + }, + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 0, + "target" : 34963 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 72, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 432, + "byteOffset" : 504, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 576, + "byteOffset" : 936, + "target" : 34962 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 1512, + "target" : 34962 + } + ], + "buffers" : [ + { + "byteLength" : 514, + "uri" : "Cube.bin" + } + ], + "meshes" : [ + { + "name" : "Cube", + "primitives" : [ + { + "attributes" : { + "POSITION" : 1 + }, + "mode" : 4 + } + ] + }, + { + "name" : "TruncatedCube", + "primitives" : [ { + "attributes" : { + "POSITION" : 6 + }, + "mode" : 4 + } ] + }, + { + "name" : "Lines", + "primitives" : [ { + "attributes" : { + "POSITION" : 5 + }, + "mode" : 1 + } ] + }, + { + "name" : "TruncatedLines", + "primitives" : [ { + "attributes" : { + "POSITION" : 6 + }, + "mode" : 1 + } ] + }, + { + "name" : "IndexedCube", + "primitives" : [ { + "attributes" : { + "POSITION" : 1 + }, + "mode" : 4, + "indices" : 0 + } ] + }, + { + "name" : "TruncatedIndexedCube", + "primitives" : [ { + "attributes" : { + "POSITION" : 6 + }, + "mode" : 4, + "indices" : 7 + } ] + }, + { + "name" : "IndexedLines", + "primitives" : [ { + "attributes" : { + "POSITION" : 5 + }, + "mode" : 1, + "indices" : 0 + } ] + }, + { + "name" : "TruncatedIndexedLines", + "primitives" : [ { + "attributes" : { + "POSITION" : 6 + }, + "mode" : 1, + "indices" : 7 + } ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Cube" + }, + { + "mesh" : 1, + "name" : "TruncatedCube", + "translation": [ 2.5, 0.0, 2.5 ] + }, + { + "mesh" : 2, + "name" : "Lines", + "translation": [ 2.5, 0.0, 0.0 ] + }, + { + "mesh" : 3, + "name" : "TruncatedLines", + "translation": [ 2.5, 0.0, -2.5 ] + }, + { + "mesh" : 4, + "name" : "IndexedCube", + "translation": [ -2.5, 0.0, 2.5 ] + }, + { + "mesh" : 5, + "name" : "TruncatedIndexedCube", + "translation": [ -2.5, 0.0, 0.0 ] + }, + { + "mesh" : 6, + "name" : "IndexedLines", + "translation": [ -2.5, 0.0, -2.5 ] + }, + { + "mesh" : 7, + "name" : "TruncatedIndexedLines", + "translation": [ 0.0, 0.0, -2.5 ] + } + ], + "samplers" : [ + {} + ], + "scene" : 0, + "scenes" : [ + { + "nodes" : [ + 0, 1, 2, 3, 4, 5, 6, 7 + ] + } + ] +} diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 829d314518..6925098b94 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -382,6 +382,29 @@ TEST_F(utglTF2ImportExport, import_cameras) { EXPECT_NE(nullptr, scene); } +TEST_F(utglTF2ImportExport, incorrect_vertex_arrays) { + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/IncorrectVertexArrays/Cube.gltf", + aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 12u); + EXPECT_EQ(scene->mMeshes[1]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[1]->mNumFaces, 11u); + EXPECT_EQ(scene->mMeshes[2]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[2]->mNumFaces, 18u); + EXPECT_EQ(scene->mMeshes[3]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[3]->mNumFaces, 17u); + EXPECT_EQ(scene->mMeshes[4]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[4]->mNumFaces, 12u); + EXPECT_EQ(scene->mMeshes[5]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[5]->mNumFaces, 11u); + EXPECT_EQ(scene->mMeshes[6]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[6]->mNumFaces, 18u); + EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u); +} + #ifndef ASSIMP_BUILD_NO_EXPORT TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) { EXPECT_TRUE( exporterTest() ); diff --git a/test/unit/utglTFImportExport.cpp b/test/unit/utglTFImportExport.cpp index 562cb05b96..90f0758bb0 100644 --- a/test/unit/utglTFImportExport.cpp +++ b/test/unit/utglTFImportExport.cpp @@ -46,6 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include + using namespace Assimp; class utglTFImportExport : public AbstractImportExportBase { @@ -60,3 +62,26 @@ class utglTFImportExport : public AbstractImportExportBase { TEST_F( utglTFImportExport, importglTFFromFileTest ) { EXPECT_TRUE( importerTest() ); } + +TEST_F(utglTFImportExport, incorrect_vertex_arrays) { + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF/IncorrectVertexArrays/Cube_v1.gltf", + aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 12u); + EXPECT_EQ(scene->mMeshes[1]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[1]->mNumFaces, 11u); + EXPECT_EQ(scene->mMeshes[2]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[2]->mNumFaces, 18u); + EXPECT_EQ(scene->mMeshes[3]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[3]->mNumFaces, 17u); + EXPECT_EQ(scene->mMeshes[4]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[4]->mNumFaces, 12u); + EXPECT_EQ(scene->mMeshes[5]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[5]->mNumFaces, 11u); + EXPECT_EQ(scene->mMeshes[6]->mNumVertices, 36u); + EXPECT_EQ(scene->mMeshes[6]->mNumFaces, 18u); + EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u); + EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u); +}