diff --git a/code/glTF/glTFImporter.cpp b/code/glTF/glTFImporter.cpp index 9ecd742f6..9ec13ea69 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 c2106e26f..b3141fd96 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/test/models/glTF/IncorrectVertexArrays/Cube.bin b/test/models/glTF/IncorrectVertexArrays/Cube.bin new file mode 100644 index 000000000..fa55b363a 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 000000000..c076c5bcb --- /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 000000000..fa55b363a 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 000000000..0ca17e1e5 --- /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 829d31451..6925098b9 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 562cb05b9..90f0758bb 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 @@ public: 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); +}