diff --git a/source/Irrlicht/CGLTFMeshFileLoader.cpp b/source/Irrlicht/CGLTFMeshFileLoader.cpp index e3cc27ca..4a9261bb 100644 --- a/source/Irrlicht/CGLTFMeshFileLoader.cpp +++ b/source/Irrlicht/CGLTFMeshFileLoader.cpp @@ -63,7 +63,7 @@ static bool tryParseGLTF(io::IReadFile* file, tinygltf::Model& model) } template -static T readPrimative(const BufferOffset& readFrom) { +static T readPrimitive(const BufferOffset& readFrom) { unsigned char d[sizeof(T)]{}; for (std::size_t i = 0; i < sizeof(T); ++i) { d[i] = readFrom.at(i); @@ -75,16 +75,16 @@ static core::vector3df readVector(const BufferOffset& readFrom) { // glTF coordinates are right-handed, minetest ones are left-handed // 1 glTF coordinate is equivalent to 10 Irrlicht coordinates return core::vector3df( - -1.0 * readPrimative(readFrom), - 1.0 * readPrimative(BufferOffset(readFrom, sizeof(float))), - 1.0 * readPrimative(BufferOffset(readFrom, 2 * sizeof(float)))); + -1.0f * readPrimitive(readFrom), + 1.0f * readPrimitive(BufferOffset(readFrom, sizeof(float))), + 1.0 * readPrimitive(BufferOffset(readFrom, 2 * sizeof(float)))); } static u16* readIndices(const BufferOffset& readFrom, const std::size_t count) { auto* indices = new u16[count]{}; for (std::size_t i = 0; i < count; ++i) { - indices[i] = readPrimative(BufferOffset(readFrom, i * sizeof(u16))); + indices[i] = readPrimitive(BufferOffset(readFrom, i * sizeof(u16))); } return indices; } @@ -94,26 +94,25 @@ video::S3DVertex* getVertices(const tinygltf::Model& model, const std::size_t ac const auto& view = model.bufferViews[ model.accessors[accessorId].bufferView]; const auto& buffer = model.buffers[view.buffer]; - const auto v1 = readVector(BufferOffset( - buffer.data, view.byteOffset)); - const auto v2 = readVector(BufferOffset( - buffer.data, view.byteOffset + (3 * sizeof(float)))); - const auto v3 = readVector(BufferOffset( - buffer.data, view.byteOffset + (6 * sizeof(float)))); - return (new video::S3DVertex[3] { - {v1, {0.0f, 0.0f, 1.0f}, {}, {0.0f, 0.0f}}, - {v2, {0.0f, 0.0f, 1.0f}, {}, {1.0f, 0.0f}}, - {v3, {0.0f, 0.0f, 1.0f}, {}, {0.0f, 1.0f}} } ); + auto* vertices = new video::S3DVertex[model.accessors[accessorId].count]; + + for (std::size_t i = 0; i < model.accessors[accessorId].count; ++i) { + const auto v = readVector(BufferOffset( + buffer.data, view.byteOffset + 3 * sizeof(float) * i)); + vertices[i] = {v, {0.0f, 0.0f, 0.0f}, {}, {0.0f, 0.0f}}; + } + + return vertices; } u16* getIndices(const tinygltf::Model& model, const std::size_t accessorId) { - const auto& indicesView = model.bufferViews[ + const auto& view = model.bufferViews[ model.accessors[accessorId].bufferView]; - const auto& indicesBuffer = model.buffers[indicesView.buffer]; + const auto& indicesBuffer = model.buffers[view.buffer]; return readIndices( - BufferOffset(indicesBuffer.data, indicesView.byteOffset), + BufferOffset(indicesBuffer.data, view.byteOffset), model.accessors[0].count); } @@ -135,13 +134,18 @@ IAnimatedMesh* CGLTFMeshFileLoader::createMesh(io::IReadFile* file) return nullptr; } - auto* indices = getIndices(model, 0); - auto* vertices = getVertices(model, 1); + const auto indicesAccessorId = + model.meshes[0].primitives[0].indices; + const auto positionAccessorId = + model.meshes[0].primitives[0].attributes["POSITION"]; + + auto* indices = getIndices(model, indicesAccessorId); + auto* vertices = getVertices(model, positionAccessorId); SMeshBuffer* meshbuf { new SMeshBuffer {} }; - meshbuf->append(vertices, model.accessors[1].count, - indices, model.accessors[0].count); + meshbuf->append(vertices, model.accessors[positionAccessorId].count, + indices, model.accessors[indicesAccessorId].count); SMesh* mesh { new SMesh {} }; mesh->addMeshBuffer(meshbuf); diff --git a/source/Irrlicht/tests/CMakeLists.txt b/source/Irrlicht/tests/CMakeLists.txt index 3112eab4..cef86516 100644 --- a/source/Irrlicht/tests/CMakeLists.txt +++ b/source/Irrlicht/tests/CMakeLists.txt @@ -1,5 +1,4 @@ add_executable(tests - inMemoryFile.cpp inMemoryFile.h testCGLTFMeshFileLoader.cpp ) diff --git a/source/Irrlicht/tests/assets/blender_cube.gltf b/source/Irrlicht/tests/assets/blender_cube.gltf new file mode 100644 index 00000000..d3c4cc32 --- /dev/null +++ b/source/Irrlicht/tests/assets/blender_cube.gltf @@ -0,0 +1,105 @@ +{ + "asset" : { + "generator" : "Khronos glTF Blender I/O v1.7.33", + "version" : "2.0" + }, + "scene" : 0, + "scenes" : [ + { + "name" : "Scene", + "nodes" : [ + 0 + ] + } + ], + "nodes" : [ + { + "mesh" : 0, + "name" : "Cube", + "scale" : [ + 10, + 10, + 10 + ] + } + ], + "meshes" : [ + { + "name" : "Cube.004", + "primitives" : [ + { + "attributes" : { + "POSITION" : 0, + "NORMAL" : 1, + "TEXCOORD_0" : 2 + }, + "indices" : 3 + } + ] + } + ], + "accessors" : [ + { + "bufferView" : 0, + "componentType" : 5126, + "count" : 24, + "max" : [ + 1, + 1, + 1 + ], + "min" : [ + -1, + -1, + -1 + ], + "type" : "VEC3" + }, + { + "bufferView" : 1, + "componentType" : 5126, + "count" : 24, + "type" : "VEC3" + }, + { + "bufferView" : 2, + "componentType" : 5126, + "count" : 24, + "type" : "VEC2" + }, + { + "bufferView" : 3, + "componentType" : 5123, + "count" : 36, + "type" : "SCALAR" + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 0 + }, + { + "buffer" : 0, + "byteLength" : 288, + "byteOffset" : 288 + }, + { + "buffer" : 0, + "byteLength" : 192, + "byteOffset" : 576 + }, + { + "buffer" : 0, + "byteLength" : 72, + "byteOffset" : 768 + } + ], + "buffers" : [ + { + "byteLength" : 840, + "uri" : "data:application/octet-stream;base64,AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIC/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgL8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgD8AAIA/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgL8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAPwAAgD8AAIC/AACAvwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAvwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAvwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIA/AACAPwAAAAAAAACAAAAAAAAAAAAAAIA/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAAAAAAAAgL8AAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAgD8AAACAAACAPwAAAAAAAACAAADAPgAAgD8AAAA+AACAPgAAwD4AAAAAAAAgPwAAgD8AACA/AAAAAAAAYD8AAIA+AADAPgAAQD8AAAA+AAAAPwAAwD4AAEA/AAAgPwAAQD8AACA/AABAPwAAYD8AAAA/AADAPgAAgD4AAMA+AACAPgAAwD4AAIA+AAAgPwAAgD4AACA/AACAPgAAID8AAIA+AADAPgAAAD8AAMA+AAAAPwAAwD4AAAA/AAAgPwAAAD8AACA/AAAAPwAAID8AAAA/AAADAAkAAAAJAAYACAAKABUACAAVABMAFAAXABEAFAARAA4ADQAPAAQADQAEAAIABwASAAwABwAMAAEAFgALAAUAFgAFABAA" + } + ] +} diff --git a/source/Irrlicht/tests/assets/empty.gltf b/source/Irrlicht/tests/assets/empty.gltf new file mode 100644 index 00000000..e69de29b diff --git a/source/Irrlicht/tests/assets/json_missing_brace.gltf b/source/Irrlicht/tests/assets/json_missing_brace.gltf new file mode 100644 index 00000000..98232c64 --- /dev/null +++ b/source/Irrlicht/tests/assets/json_missing_brace.gltf @@ -0,0 +1 @@ +{ diff --git a/source/Irrlicht/tests/inMemoryFile.cpp b/source/Irrlicht/tests/inMemoryFile.cpp deleted file mode 100644 index 61402e1d..00000000 --- a/source/Irrlicht/tests/inMemoryFile.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "inMemoryFile.h" - -#include - -#include - -namespace irr -{ - -namespace io -{ - -InMemoryFile::InMemoryFile(const io::path& filename, const std::string& s) - : m_filename { filename } - , m_sstream { s } -{ -} - -std::size_t InMemoryFile::read(void* buffer, std::size_t sizeToRead) -{ - m_sstream.read(reinterpret_cast(buffer), sizeToRead); - return m_sstream.gcount(); -} - -bool InMemoryFile::seek(long finalPos, bool relativeMovement) -{ - if (relativeMovement) { - m_sstream.seekg(finalPos, std::ios::beg); - } else { - m_sstream.seekg(finalPos); - } - - return m_sstream.fail(); -} - -long InMemoryFile::getSize() const -{ - return m_sstream.str().size(); -} - -long InMemoryFile::getPos() const -{ - return m_sstream.tellg(); -} - -const io::path& InMemoryFile::getFileName() const -{ - return m_filename; -} - -} // namespace irr - -} // namespace io - diff --git a/source/Irrlicht/tests/inMemoryFile.h b/source/Irrlicht/tests/inMemoryFile.h deleted file mode 100644 index be33ad4a..00000000 --- a/source/Irrlicht/tests/inMemoryFile.h +++ /dev/null @@ -1,32 +0,0 @@ -#include - -#include -#include -#include - -namespace irr -{ - -namespace io -{ - -class InMemoryFile: public IReadFile -{ -public: - InMemoryFile(const io::path& filename, const std::string& s); - - std::size_t read(void* buffer, std::size_t sizeToRead) override; - bool seek(long finalPos, bool relativeMovement=false) override; - long getSize() const override; - long getPos() const override; - const io::path& getFileName() const override; - -private: - io::path m_filename; - mutable std::stringstream m_sstream; -}; - -} // namespace io - -} // namespace irr - diff --git a/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp b/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp index 4bccfaa5..129a59f8 100644 --- a/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp +++ b/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp @@ -1,5 +1,3 @@ -#include "inMemoryFile.h" - #define CATCH_CONFIG_MAIN #include #include @@ -40,53 +38,70 @@ private: }; TEST_CASE("load empty gltf file") { - irr::io::InMemoryFile filebuf {"test.gltf", ""}; - ScopedMesh sm { &filebuf }; + ScopedMesh sm("source/Irrlicht/tests/assets/empty.gltf"); CHECK(sm.getMesh() == nullptr); } TEST_CASE("minimal triangle") { - ScopedMesh sm { "source/Irrlicht/tests/assets/minimal_triangle.gltf" }; - - auto* mesh = sm.getMesh(); - REQUIRE(mesh != nullptr); - REQUIRE(mesh->getMeshBufferCount() == 1); - auto* meshbuf = mesh->getMeshBuffer(0); + ScopedMesh sm("source/Irrlicht/tests/assets/minimal_triangle.gltf"); + REQUIRE(sm.getMesh() != nullptr); + REQUIRE(sm.getMesh()->getMeshBufferCount() == 1); SECTION("vertex coordinates are correct") { - REQUIRE(meshbuf->getVertexCount() == 3); - auto* vertices = reinterpret_cast( - meshbuf->getVertices()); + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getVertexCount() == 3); + const auto* vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getVertices()); CHECK(vertices[0].Pos == irr::core::vector3df {0.0f, 0.0f, 0.0f}); CHECK(vertices[1].Pos == irr::core::vector3df {-1.0f, 0.0f, 0.0f}); CHECK(vertices[2].Pos == irr::core::vector3df {0.0f, 1.0f, 0.0f}); } SECTION("vertex indices are correct") { - REQUIRE(meshbuf->getIndexCount() == 3); - auto* indices = reinterpret_cast(meshbuf->getIndices()); + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getIndexCount() == 3); + const auto* indices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getIndices()); CHECK(indices[0] == 0); CHECK(indices[1] == 1); CHECK(indices[2] == 2); } } +TEST_CASE("blender cube") { + ScopedMesh sm("source/Irrlicht/tests/assets/blender_cube.gltf"); + REQUIRE(sm.getMesh() != nullptr); + REQUIRE(sm.getMesh()->getMeshBufferCount() == 1); + SECTION("vertex coordinates are correct") { + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getVertexCount() == 24); + const auto* vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getVertices()); + CHECK(vertices[0].Pos == irr::core::vector3df{1.0f, -1.0f, 1.0f}); + CHECK(vertices[3].Pos == irr::core::vector3df{1.0f, 1.0f, 1.0f}); + CHECK(vertices[6].Pos == irr::core::vector3df{1.0f, -1.0f, -1.0f}); + CHECK(vertices[9].Pos == irr::core::vector3df{1.0f, 1.0f, -1.0f}); + CHECK(vertices[12].Pos == irr::core::vector3df{-1.0f, -1.0f, 1.0f}); + CHECK(vertices[15].Pos == irr::core::vector3df{-1.0f, 1.0f, 1.0f}); + CHECK(vertices[18].Pos == irr::core::vector3df{-1.0f, -1.0f, -1.0f}); + CHECK(vertices[21].Pos == irr::core::vector3df{-1.0f, 1.0f, -1.0f}); + } + + SECTION("vertex indices are correct") + { + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getIndexCount() == 36); + const auto* indices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getIndices()); + CHECK(indices[0] == 0); + CHECK(indices[1] == 3); + CHECK(indices[2] == 9); + } +} + TEST_CASE("mesh loader returns nullptr when given null file pointer") { - ScopedMesh sm { nullptr }; + ScopedMesh sm(nullptr); CHECK(sm.getMesh() == nullptr); } TEST_CASE("invalid JSON returns nullptr") { - SECTION("missing closing brace") { - irr::io::InMemoryFile filebuf {"test.gltf", "{"}; - ScopedMesh sm { &filebuf }; - CHECK(sm.getMesh() == nullptr); - } - - SECTION("missing colon") { - irr::io::InMemoryFile filebuf {"test.gltf", "{\"a\" \"b\"}"}; - ScopedMesh sm { &filebuf }; - CHECK(sm.getMesh() == nullptr); - } + ScopedMesh sm("source/Irrlicht/tests/assets/json_missing_brace.gltf"); + CHECK(sm.getMesh() == nullptr); }