diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..c942d0445 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.associations": { + "*.tcc": "cpp", + "iomanip": "cpp" + } +} \ No newline at end of file diff --git a/source/Irrlicht/CGLTFMeshFileLoader.cpp b/source/Irrlicht/CGLTFMeshFileLoader.cpp index 7734889b6..83c0eaf5a 100644 --- a/source/Irrlicht/CGLTFMeshFileLoader.cpp +++ b/source/Irrlicht/CGLTFMeshFileLoader.cpp @@ -10,8 +10,6 @@ #include "SColor.h" #include "SMesh.h" #include "vector3d.h" -#include -#include #define TINYGLTF_IMPLEMENTATION #include @@ -20,6 +18,8 @@ #include #include #include +#include +#include template struct Span @@ -55,8 +55,9 @@ private: }; // A helper function to disable tinygltf embedded image loading -bool turn_off_textures_hack(tinygltf::Image *a, const int b, std::string *c, - std::string *d, int e, int f, const unsigned char * g,int h, void *user_pointer) +bool dummyImageLoader(tinygltf::Image *a, const int b, std::string *c, + std::string *d, int e, int f, const unsigned char * g, + int h, void *user_pointer) { return false; }; @@ -72,8 +73,7 @@ static bool tryParseGLTF(io::IReadFile* file, tinygltf::Model& model) tinygltf::TinyGLTF loader {}; // Stop embedded textures from making model fail to load - void *the_void = 0; - loader.SetImageLoader(turn_off_textures_hack, the_void); + loader.SetImageLoader(dummyImageLoader, nullptr); std::string err {}; std::string warn {}; @@ -81,7 +81,12 @@ static bool tryParseGLTF(io::IReadFile* file, tinygltf::Model& model) auto buf = std::make_unique(file->getSize()); file->read(buf.get(), file->getSize()); - return loader.LoadASCIIFromString(&model, &err, &warn, buf.get(), file->getSize(), "", 1); + if (err != "" || warn != "") { + return false; + } + + return loader.LoadASCIIFromString(&model, &err, &warn, buf.get(), + file->getSize(), "", 1); } template @@ -98,7 +103,8 @@ static T readPrimitive(const BufferOffset& readFrom) static core::vector2df readVec2DF(const BufferOffset& readFrom) { - return core::vector2df( readPrimitive(readFrom), readPrimitive( BufferOffset( readFrom, sizeof(float) ) ) ); + return core::vector2df(readPrimitive(readFrom), + readPrimitive(BufferOffset( readFrom, sizeof(float)))); } @@ -110,7 +116,8 @@ static core::vector3df readVec3DF(const BufferOffset& readFrom, return core::vector3df( scale * readPrimitive(readFrom), scale * readPrimitive(BufferOffset(readFrom, sizeof(float))), - -scale * readPrimitive(BufferOffset(readFrom, 2 * sizeof(float)))); + -scale * readPrimitive(BufferOffset(readFrom, 2 * + sizeof(float)))); } float getScale(const tinygltf::Model& model) @@ -121,81 +128,93 @@ float getScale(const tinygltf::Model& model) return 1.0f; } - - - - -static void copyPositions(const tinygltf::Model& model, const Span vertices, const std::size_t accessorId) +static void copyPositions(const tinygltf::Model& model, + const Span vertices, const std::size_t accessorId) { - const auto& view = model.bufferViews[ model.accessors[accessorId].bufferView]; + const auto& view = model.bufferViews[ + model.accessors[accessorId].bufferView]; const auto& buffer = model.buffers[view.buffer]; const auto count = model.accessors[accessorId].count; float scale = getScale(model); for (std::size_t i = 0; i < count; i++) { - const auto v = readVec3DF(BufferOffset( buffer.data, view.byteOffset + (3 * sizeof(float) * i)), scale); + const auto v = readVec3DF(BufferOffset( + buffer.data, view.byteOffset + (3 * sizeof(float) * i)),scale); vertices.buffer[i].Pos = v; } } -static void copyNormals(const tinygltf::Model& model, const Span vertices, const std::size_t accessorId) +static void copyNormals(const tinygltf::Model& model, +const Span vertices,const std::size_t accessorId) { - const auto& view = model.bufferViews[model.accessors[accessorId].bufferView]; + const auto& view = model.bufferViews[ + model.accessors[accessorId].bufferView]; const auto& buffer = model.buffers[view.buffer]; const auto count = model.accessors[accessorId].count; - for (std::size_t i = 0; i < count; ++i) { - const auto n = readVec3DF(BufferOffset( buffer.data, view.byteOffset + 3 * sizeof(float) * i )); + for (std::size_t i = 0; i < count; i++) { + const auto n = readVec3DF(BufferOffset( buffer.data, + view.byteOffset + 3 * sizeof(float) * i )); vertices.buffer[i].Normal = n; } } -static void copyTCoords(const tinygltf::Model& model, const Span vertices, const std::size_t accessorId) +static void copyTCoords(const tinygltf::Model& model, + const Span vertices, const std::size_t accessorId) { - const auto& view = model.bufferViews[ model.accessors[accessorId].bufferView ]; + const auto& view = model.bufferViews[ + model.accessors[accessorId].bufferView]; const auto& buffer = model.buffers[view.buffer]; const auto count = model.accessors[accessorId].count; for (std::size_t i = 0; i < count; ++i) { - const auto t = readVec2DF(BufferOffset(buffer.data, view.byteOffset + 2 * sizeof(float) * i)); + const auto t = readVec2DF(BufferOffset( + buffer.data, view.byteOffset + 2 * sizeof(float) * i)); vertices.buffer[i].TCoords = t; } } -static void getIndices(const tinygltf::Model& model, const std::size_t accessorId, std::vector *indicesBuffer) +static void getIndices(const tinygltf::Model& model, + const std::size_t accessorId, std::vector& indicesBuffer) { - const auto& view = model.bufferViews[model.accessors[accessorId].bufferView]; + const auto& view = model.bufferViews[ + model.accessors[accessorId].bufferView]; const auto& modelIndices = model.buffers[view.buffer]; - auto bufferobject = BufferOffset(modelIndices.data, view.byteOffset); + auto buffOffset = BufferOffset(modelIndices.data, view.byteOffset); auto count = model.accessors[accessorId].count; for (std::size_t i = 0; i < count; i++) { - auto current = readPrimitive(BufferOffset(bufferobject, i * sizeof(u16))); - // Inverse the order of indices - indicesBuffer->insert(indicesBuffer->begin(), current); + indicesBuffer[i] = readPrimitive(BufferOffset( + buffOffset, i * sizeof(u16))); } } -// Returns a tuple of the current counts (current_vertex_index, current_normals_index, current_tcoords_index) +//Returns a tuple of the current counts (current_vertex_index, +// current_normals_index, current_tcoords_index) static void getVertices -( const tinygltf::Model& model, const std::size_t accessorId, Span *verticesBuffer, -std::size_t mesh_index, std::size_t primitive_index ) +( const tinygltf::Model& model, const std::size_t accessorId, + Span& verticesBuffer, + std::size_t mesh_index, std::size_t primitive_index ) { - copyPositions(model, *verticesBuffer, accessorId); + copyPositions(model, verticesBuffer, accessorId); - const auto normalsField = model.meshes[mesh_index].primitives[primitive_index].attributes.find("NORMAL"); + const auto normalsField = model.meshes[mesh_index] + .primitives[primitive_index].attributes.find("NORMAL"); - if (normalsField != model.meshes[mesh_index].primitives[primitive_index].attributes.end()) { - copyNormals(model, *verticesBuffer, normalsField->second); + if (normalsField != model.meshes[mesh_index] + .primitives[primitive_index].attributes.end()) { + copyNormals(model, verticesBuffer, normalsField->second); } - const auto tCoordsField = model.meshes[mesh_index].primitives[primitive_index].attributes.find("TEXCOORD_0"); + const auto tCoordsField = model.meshes[mesh_index] + .primitives[primitive_index].attributes.find("TEXCOORD_0"); - if (tCoordsField != model.meshes[mesh_index].primitives[primitive_index].attributes.end()) { - copyTCoords(model, *verticesBuffer, tCoordsField->second); + if (tCoordsField != model.meshes[mesh_index] + .primitives[primitive_index].attributes.end()) { + copyTCoords(model, verticesBuffer, tCoordsField->second); } } @@ -221,30 +240,42 @@ IAnimatedMesh* CGLTFMeshFileLoader::createMesh(io::IReadFile* file) SMesh* mesh { new SMesh {} }; // Iterate models - for (std::size_t mesh_index = 0; mesh_index < model.meshes.size(); mesh_index++) { + for (std::size_t mesh_index = 0; + mesh_index < model.meshes.size(); mesh_index++) { // Iterate primitives - for (std::size_t primitive_index = 0; primitive_index < model.meshes[mesh_index].primitives.size(); primitive_index++) { + for (std::size_t primitive_index = 0; primitive_index < model + .meshes[mesh_index].primitives.size(); primitive_index++) { - const auto positionAccessorId = model.meshes[mesh_index].primitives[primitive_index].attributes["POSITION"]; - const auto indicesAccessorId = model.meshes[mesh_index].primitives[primitive_index].indices; + const auto positionAccessorId = model.meshes[mesh_index] + .primitives[primitive_index].attributes["POSITION"]; + const auto indicesAccessorId = model.meshes[mesh_index] + .primitives[primitive_index].indices; // Creates counts for preallocation std::size_t vertices_count = model.accessors[positionAccessorId].count; // We must count to create containers for the data - // Create new buffer for vertices, positions, and normals. Will loop through this soon - auto* vertexBuffer = new video::S3DVertex[vertices_count]{}; + // Create new buffer for vertices, positions, and normals + auto* vertexBuffer = new video::S3DVertex[vertices_count](); // This is used to copy data into the vertexBuffer - Span verticesBuffer{ vertexBuffer, vertices_count }; - // Create dynamic indices buffer so it's easier to work with - std::vector indicesBuffer; + Span verticesBuffer{vertexBuffer,vertices_count}; + // Create dynamic indices buffer so it's easier to work with. + // Preallocate needed resources to boost game startup speed + std::vector indicesBuffer(model.accessors[ + indicesAccessorId].count); - getIndices(model, indicesAccessorId, &indicesBuffer); - getVertices(model, positionAccessorId, &verticesBuffer, mesh_index, primitive_index); + getIndices(model, indicesAccessorId, indicesBuffer); + getVertices(model, positionAccessorId, verticesBuffer, + mesh_index, primitive_index); + + // Inverse the order of indices due to the axis of the model being + // inverted when going from left handed to right handed coordinates + std::reverse(indicesBuffer.begin(),indicesBuffer.end()); // Create the mesh buffer SMeshBuffer* meshbuf { new SMeshBuffer {} }; - meshbuf->append(vertexBuffer, vertices_count, indicesBuffer.data(), indicesBuffer.size()); + meshbuf->append(vertexBuffer, vertices_count, indicesBuffer.data(), + indicesBuffer.size()); mesh->addMeshBuffer(meshbuf); diff --git a/source/Irrlicht/tests/assets/snow_man.gltf b/source/Irrlicht/tests/assets/snow_man.gltf new file mode 100644 index 000000000..d384867c3 --- /dev/null +++ b/source/Irrlicht/tests/assets/snow_man.gltf @@ -0,0 +1 @@ +{"asset":{"version":"2.0","generator":"Blockbench 4.6.0 glTF exporter"},"scenes":[{"nodes":[3],"name":"blockbench_export"}],"scene":0,"nodes":[{"name":"cube","mesh":0},{"name":"cube","mesh":1},{"name":"cube","mesh":2},{"children":[0,1,2]}],"bufferViews":[{"buffer":0,"byteOffset":0,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":288,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":576,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":768,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":840,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1128,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1416,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":1608,"byteLength":72,"target":34963},{"buffer":0,"byteOffset":1680,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":1968,"byteLength":288,"target":34962,"byteStride":12},{"buffer":0,"byteOffset":2256,"byteLength":192,"target":34962,"byteStride":8},{"buffer":0,"byteOffset":2448,"byteLength":72,"target":34963}],"buffers":[{"byteLength":2520,"uri":"data:application/octet-stream;base64,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"}],"accessors":[{"bufferView":0,"componentType":5126,"count":24,"max":[3,24,3],"min":[-3,18,-3],"type":"VEC3"},{"bufferView":1,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":2,"componentType":5126,"count":24,"max":[0.8333333134651184,1],"min":[0,0.25],"type":"VEC2"},{"bufferView":3,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":4,"componentType":5126,"count":24,"max":[5,10,5],"min":[-5,0,-5],"type":"VEC3"},{"bufferView":5,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":6,"componentType":5126,"count":24,"max":[0.625,1],"min":[0,0.375],"type":"VEC2"},{"bufferView":7,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"},{"bufferView":8,"componentType":5126,"count":24,"max":[4,18,4],"min":[-4,10,-4],"type":"VEC3"},{"bufferView":9,"componentType":5126,"count":24,"max":[1,1,1],"min":[-1,-1,-1],"type":"VEC3"},{"bufferView":10,"componentType":5126,"count":24,"max":[0.7083333134651184,0.7916666865348816],"min":[0.2083333283662796,0.25],"type":"VEC2"},{"bufferView":11,"componentType":5123,"count":36,"max":[23],"min":[0],"type":"SCALAR"}],"materials":[{"pbrMetallicRoughness":{"metallicFactor":0,"roughnessFactor":1},"alphaMode":"MASK","alphaCutoff":0.05,"doubleSided":true}],"meshes":[{"primitives":[{"mode":4,"attributes":{"POSITION":0,"NORMAL":1,"TEXCOORD_0":2},"indices":3,"material":0}]},{"primitives":[{"mode":4,"attributes":{"POSITION":4,"NORMAL":5,"TEXCOORD_0":6},"indices":7,"material":0}]},{"primitives":[{"mode":4,"attributes":{"POSITION":8,"NORMAL":9,"TEXCOORD_0":10},"indices":11,"material":0}]}]} \ No newline at end of file diff --git a/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp b/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp index 21d62634a..78bc82d34 100644 --- a/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp +++ b/source/Irrlicht/tests/testCGLTFMeshFileLoader.cpp @@ -1,6 +1,9 @@ #define CATCH_CONFIG_MAIN #include #include +#include + +using namespace std; class ScopedMesh { @@ -60,9 +63,9 @@ TEST_CASE("minimal triangle") { REQUIRE(sm.getMesh()->getMeshBuffer(0)->getIndexCount() == 3); const auto* indices = reinterpret_cast( sm.getMesh()->getMeshBuffer(0)->getIndices()); - CHECK(indices[0] == 0); + CHECK(indices[0] == 2); CHECK(indices[1] == 1); - CHECK(indices[2] == 2); + CHECK(indices[2] == 0); } } @@ -88,10 +91,10 @@ TEST_CASE("blender cube") { 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); - CHECK(indices[35] == 16); + CHECK(indices[0] == 16); + CHECK(indices[1] == 5); + CHECK(indices[2] == 22); + CHECK(indices[35] == 0); } SECTION("vertex normals are correct") { @@ -129,3 +132,142 @@ TEST_CASE("invalid JSON returns nullptr") { CHECK(sm.getMesh() == nullptr); } +TEST_CASE("snow man") { + ScopedMesh sm("source/Irrlicht/tests/assets/snow_man.gltf"); + REQUIRE(sm.getMesh() != nullptr); + REQUIRE(sm.getMesh()->getMeshBufferCount() == 3); + + SECTION("vertex coordinates are correct for all buffers") { + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getVertexCount() == 24); + const auto* vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getVertices()); + + CHECK(vertices[0].Pos == irr::core::vector3df{3.0f, 24.0f, -3.0f}); + CHECK(vertices[3].Pos == irr::core::vector3df{3.0f, 18.0f, 3.0f}); + CHECK(vertices[6].Pos == irr::core::vector3df{-3.0f, 18.0f, -3.0f}); + CHECK(vertices[9].Pos == irr::core::vector3df{3.0f, 24.0f, 3.0f}); + CHECK(vertices[12].Pos == irr::core::vector3df{3.0f, 18.0f, -3.0f}); + CHECK(vertices[15].Pos == irr::core::vector3df{-3.0f, 18.0f, 3.0f}); + CHECK(vertices[18].Pos == irr::core::vector3df{3.0f, 18.0f, -3.0f}); + CHECK(vertices[21].Pos == irr::core::vector3df{3.0f, 18.0f, 3.0f}); + + vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(1)->getVertices()); + + CHECK(vertices[2].Pos == irr::core::vector3df{5.0f, 10.0f, 5.0f}); + CHECK(vertices[3].Pos == irr::core::vector3df{5.0f, 0.0f, 5.0f}); + CHECK(vertices[7].Pos == irr::core::vector3df{-5.0f, 0.0f, 5.0f}); + CHECK(vertices[8].Pos == irr::core::vector3df{5.0f, 10.0f, -5.0f}); + CHECK(vertices[14].Pos == irr::core::vector3df{5.0f, 0.0f, 5.0f}); + CHECK(vertices[16].Pos == irr::core::vector3df{5.0f, 10.0f, -5.0f}); + CHECK(vertices[22].Pos == irr::core::vector3df{-5.0f, 10.0f, 5.0f}); + CHECK(vertices[23].Pos == irr::core::vector3df{-5.0f, 0.0f, 5.0f}); + + vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(2)->getVertices()); + + CHECK(vertices[1].Pos == irr::core::vector3df{4.0f, 10.0f, -4.0f}); + CHECK(vertices[2].Pos == irr::core::vector3df{4.0f, 18.0f, 4.0f}); + CHECK(vertices[3].Pos == irr::core::vector3df{4.0f, 10.0f, 4.0f}); + CHECK(vertices[10].Pos == irr::core::vector3df{-4.0f, 18.0f, -4.0f}); + CHECK(vertices[11].Pos == irr::core::vector3df{-4.0f, 18.0f, 4.0f}); + CHECK(vertices[12].Pos == irr::core::vector3df{4.0f, 10.0f, -4.0f}); + CHECK(vertices[17].Pos == irr::core::vector3df{-4.0f, 18.0f, -4.0f}); + CHECK(vertices[18].Pos == irr::core::vector3df{4.0f, 10.0f, -4.0f}); + } + + SECTION("vertex indices are correct for all buffers") { + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getIndexCount() == 36); + const auto* indices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getIndices()); + CHECK(indices[0] == 23); + CHECK(indices[1] == 21); + CHECK(indices[2] == 22); + CHECK(indices[35] == 2); + + REQUIRE(sm.getMesh()->getMeshBuffer(1)->getIndexCount() == 36); + indices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(1)->getIndices()); + CHECK(indices[10] == 16); + CHECK(indices[11] == 18); + CHECK(indices[15] == 13); + CHECK(indices[27] == 5); + + REQUIRE(sm.getMesh()->getMeshBuffer(1)->getIndexCount() == 36); + indices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(2)->getIndices()); + CHECK(indices[26] == 6); + CHECK(indices[27] == 5); + CHECK(indices[29] == 6); + CHECK(indices[32] == 2); + } + + + SECTION("vertex normals are correct for all buffers") { + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getVertexCount() == 24); + const auto* vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getVertices()); + CHECK(vertices[0].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[1].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[2].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[3].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[6].Normal == irr::core::vector3df{-1.0f, 0.0f, -0.0f}); + CHECK(vertices[23].Normal == irr::core::vector3df{0.0f, 0.0f, 1.0f}); + + vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(1)->getVertices()); + + CHECK(vertices[0].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[1].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[3].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[6].Normal == irr::core::vector3df{-1.0f, 0.0f, -0.0f}); + CHECK(vertices[7].Normal == irr::core::vector3df{-1.0f, 0.0f, -0.0f}); + CHECK(vertices[22].Normal == irr::core::vector3df{0.0f, 0.0f, 1.0f}); + + + vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(2)->getVertices()); + + CHECK(vertices[3].Normal == irr::core::vector3df{1.0f, 0.0f, -0.0f}); + CHECK(vertices[4].Normal == irr::core::vector3df{-1.0f, 0.0f, -0.0f}); + CHECK(vertices[5].Normal == irr::core::vector3df{-1.0f, 0.0f, -0.0f}); + CHECK(vertices[10].Normal == irr::core::vector3df{0.0f, 1.0f, -0.0f}); + CHECK(vertices[11].Normal == irr::core::vector3df{0.0f, 1.0f, -0.0f}); + CHECK(vertices[19].Normal == irr::core::vector3df{0.0f, 0.0f, -1.0f}); + + } + + + SECTION("texture coords are correct for all buffers") { + REQUIRE(sm.getMesh()->getMeshBuffer(0)->getVertexCount() == 24); + const auto* vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(0)->getVertices()); + + CHECK(vertices[0].TCoords == irr::core::vector2df{0.583333, 0.791667}); + CHECK(vertices[1].TCoords == irr::core::vector2df{0.583333, 0.666667}); + CHECK(vertices[2].TCoords == irr::core::vector2df{0.708333, 0.791667}); + CHECK(vertices[5].TCoords == irr::core::vector2df{0.375, 0.416667}); + CHECK(vertices[6].TCoords == irr::core::vector2df{0.5, 0.291667}); + CHECK(vertices[19].TCoords == irr::core::vector2df{0.708333, 0.75}); + + vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(1)->getVertices()); + + CHECK(vertices[1].TCoords == irr::core::vector2df{0, 0.791667}); + CHECK(vertices[4].TCoords == irr::core::vector2df{0.208333, 0.791667}); + CHECK(vertices[5].TCoords == irr::core::vector2df{0, 0.791667}); + CHECK(vertices[6].TCoords == irr::core::vector2df{0.208333, 0.583333}); + CHECK(vertices[12].TCoords == irr::core::vector2df{0.416667, 0.791667}); + CHECK(vertices[15].TCoords == irr::core::vector2df{0.208333, 0.583333}); + + vertices = reinterpret_cast( + sm.getMesh()->getMeshBuffer(2)->getVertices()); + + CHECK(vertices[10].TCoords == irr::core::vector2df{0.375, 0.416667}); + CHECK(vertices[11].TCoords == irr::core::vector2df{0.375, 0.583333}); + CHECK(vertices[12].TCoords == irr::core::vector2df{0.708333, 0.625}); + CHECK(vertices[17].TCoords == irr::core::vector2df{0.541667, 0.458333}); + CHECK(vertices[20].TCoords == irr::core::vector2df{0.208333, 0.416667}); + CHECK(vertices[22].TCoords == irr::core::vector2df{0.375, 0.416667}); + } +} \ No newline at end of file