Update code with requested changes

Fix mistake on github

Comply with changes 1

Comply with requested changes 2

Comply with requested changed 3

Comply with requested changed 4

Requested changed 5

Requested changed 6

Requested changed 7

Requested changed 8

Requested changed 9

Requested changed 10

Requested changes 11

Requested changes 12

This one wasn't even requested

I just turned on my vertical ruler and I'm going to go nuts

Line 81 doesn't exist anymore

Requested changes 13

Requested changes 14

Begin snow man test

Write a lot of tests for snow man

Add to git ignore

Now unignore it

Alphabetical order

Pass by reference

Pass by reference

vertexBuffer is now handled on stack

Preallocate indicesBuffer then reverse it when complete

Undo vertexBuffer stack change causing mac builds to fail

Use direct initialization on the vertexBuffer
This commit is contained in:
jordan4ibanez 2023-01-29 18:36:41 -05:00 committed by Josiah VanderZee
parent ee5f89ce56
commit 5bad6e8a76
4 changed files with 237 additions and 57 deletions

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"files.associations": {
"*.tcc": "cpp",
"iomanip": "cpp"
}
}

View File

@ -10,8 +10,6 @@
#include "SColor.h" #include "SColor.h"
#include "SMesh.h" #include "SMesh.h"
#include "vector3d.h" #include "vector3d.h"
#include <vector>
#include <tuple>
#define TINYGLTF_IMPLEMENTATION #define TINYGLTF_IMPLEMENTATION
#include <tiny_gltf.h> #include <tiny_gltf.h>
@ -20,6 +18,8 @@
#include <cstring> #include <cstring>
#include <memory> #include <memory>
#include <string> #include <string>
#include <tuple>
#include <vector>
template <class T> template <class T>
struct Span struct Span
@ -55,8 +55,9 @@ private:
}; };
// A helper function to disable tinygltf embedded image loading // A helper function to disable tinygltf embedded image loading
bool turn_off_textures_hack(tinygltf::Image *a, const int b, std::string *c, 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) std::string *d, int e, int f, const unsigned char * g,
int h, void *user_pointer)
{ {
return false; return false;
}; };
@ -72,8 +73,7 @@ static bool tryParseGLTF(io::IReadFile* file, tinygltf::Model& model)
tinygltf::TinyGLTF loader {}; tinygltf::TinyGLTF loader {};
// Stop embedded textures from making model fail to load // Stop embedded textures from making model fail to load
void *the_void = 0; loader.SetImageLoader(dummyImageLoader, nullptr);
loader.SetImageLoader(turn_off_textures_hack, the_void);
std::string err {}; std::string err {};
std::string warn {}; std::string warn {};
@ -81,7 +81,12 @@ static bool tryParseGLTF(io::IReadFile* file, tinygltf::Model& model)
auto buf = std::make_unique<char[]>(file->getSize()); auto buf = std::make_unique<char[]>(file->getSize());
file->read(buf.get(), 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 <class T> template <class T>
@ -98,7 +103,8 @@ static T readPrimitive(const BufferOffset& readFrom)
static core::vector2df readVec2DF(const BufferOffset& readFrom) static core::vector2df readVec2DF(const BufferOffset& readFrom)
{ {
return core::vector2df( readPrimitive<float>(readFrom), readPrimitive<float>( BufferOffset( readFrom, sizeof(float) ) ) ); return core::vector2df(readPrimitive<float>(readFrom),
readPrimitive<float>(BufferOffset( readFrom, sizeof(float))));
} }
@ -110,7 +116,8 @@ static core::vector3df readVec3DF(const BufferOffset& readFrom,
return core::vector3df( return core::vector3df(
scale * readPrimitive<float>(readFrom), scale * readPrimitive<float>(readFrom),
scale * readPrimitive<float>(BufferOffset(readFrom, sizeof(float))), scale * readPrimitive<float>(BufferOffset(readFrom, sizeof(float))),
-scale * readPrimitive<float>(BufferOffset(readFrom, 2 * sizeof(float)))); -scale * readPrimitive<float>(BufferOffset(readFrom, 2 *
sizeof(float))));
} }
float getScale(const tinygltf::Model& model) float getScale(const tinygltf::Model& model)
@ -121,81 +128,93 @@ float getScale(const tinygltf::Model& model)
return 1.0f; return 1.0f;
} }
static void copyPositions(const tinygltf::Model& model,
const Span<video::S3DVertex> vertices, const std::size_t accessorId)
static void copyPositions(const tinygltf::Model& model, const Span<video::S3DVertex> 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& buffer = model.buffers[view.buffer];
const auto count = model.accessors[accessorId].count; const auto count = model.accessors[accessorId].count;
float scale = getScale(model); float scale = getScale(model);
for (std::size_t i = 0; i < count; i++) { 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; vertices.buffer[i].Pos = v;
} }
} }
static void copyNormals(const tinygltf::Model& model, const Span<video::S3DVertex> vertices, const std::size_t accessorId) static void copyNormals(const tinygltf::Model& model,
const Span<video::S3DVertex> 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& buffer = model.buffers[view.buffer];
const auto count = model.accessors[accessorId].count; const auto count = model.accessors[accessorId].count;
for (std::size_t i = 0; i < count; ++i) { for (std::size_t i = 0; i < count; i++) {
const auto n = readVec3DF(BufferOffset( buffer.data, view.byteOffset + 3 * sizeof(float) * i )); const auto n = readVec3DF(BufferOffset( buffer.data,
view.byteOffset + 3 * sizeof(float) * i ));
vertices.buffer[i].Normal = n; vertices.buffer[i].Normal = n;
} }
} }
static void copyTCoords(const tinygltf::Model& model, const Span<video::S3DVertex> vertices, const std::size_t accessorId) static void copyTCoords(const tinygltf::Model& model,
const Span<video::S3DVertex> 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& buffer = model.buffers[view.buffer];
const auto count = model.accessors[accessorId].count; const auto count = model.accessors[accessorId].count;
for (std::size_t i = 0; i < count; ++i) { 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; vertices.buffer[i].TCoords = t;
} }
} }
static void getIndices(const tinygltf::Model& model, const std::size_t accessorId, std::vector<u16> *indicesBuffer) static void getIndices(const tinygltf::Model& model,
const std::size_t accessorId, std::vector<u16>& 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]; 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; auto count = model.accessors[accessorId].count;
for (std::size_t i = 0; i < count; i++) { for (std::size_t i = 0; i < count; i++) {
auto current = readPrimitive<u16>(BufferOffset(bufferobject, i * sizeof(u16))); indicesBuffer[i] = readPrimitive<u16>(BufferOffset(
// Inverse the order of indices buffOffset, i * sizeof(u16)));
indicesBuffer->insert(indicesBuffer->begin(), current);
} }
} }
// 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 static void getVertices
( const tinygltf::Model& model, const std::size_t accessorId, Span<video::S3DVertex> *verticesBuffer, ( const tinygltf::Model& model, const std::size_t accessorId,
std::size_t mesh_index, std::size_t primitive_index ) Span<video::S3DVertex>& 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()) { if (normalsField != model.meshes[mesh_index]
copyNormals(model, *verticesBuffer, normalsField->second); .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()) { if (tCoordsField != model.meshes[mesh_index]
copyTCoords(model, *verticesBuffer, tCoordsField->second); .primitives[primitive_index].attributes.end()) {
copyTCoords(model, verticesBuffer, tCoordsField->second);
} }
} }
@ -221,30 +240,42 @@ IAnimatedMesh* CGLTFMeshFileLoader::createMesh(io::IReadFile* file)
SMesh* mesh { new SMesh {} }; SMesh* mesh { new SMesh {} };
// Iterate models // 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 // 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 positionAccessorId = model.meshes[mesh_index]
const auto indicesAccessorId = model.meshes[mesh_index].primitives[primitive_index].indices; .primitives[primitive_index].attributes["POSITION"];
const auto indicesAccessorId = model.meshes[mesh_index]
.primitives[primitive_index].indices;
// Creates counts for preallocation // Creates counts for preallocation
std::size_t vertices_count = model.accessors[positionAccessorId].count; std::size_t vertices_count = model.accessors[positionAccessorId].count;
// We must count to create containers for the data // We must count to create containers for the data
// Create new buffer for vertices, positions, and normals. Will loop through this soon // Create new buffer for vertices, positions, and normals
auto* vertexBuffer = new video::S3DVertex[vertices_count]{}; auto* vertexBuffer = new video::S3DVertex[vertices_count]();
// This is used to copy data into the vertexBuffer // This is used to copy data into the vertexBuffer
Span<video::S3DVertex> verticesBuffer{ vertexBuffer, vertices_count }; Span<video::S3DVertex> verticesBuffer{vertexBuffer,vertices_count};
// Create dynamic indices buffer so it's easier to work with // Create dynamic indices buffer so it's easier to work with.
std::vector<u16> indicesBuffer; // Preallocate needed resources to boost game startup speed
std::vector<u16> indicesBuffer(model.accessors[
indicesAccessorId].count);
getIndices(model, indicesAccessorId, &indicesBuffer); getIndices(model, indicesAccessorId, indicesBuffer);
getVertices(model, positionAccessorId, &verticesBuffer, mesh_index, primitive_index); 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 // Create the mesh buffer
SMeshBuffer* meshbuf { new SMeshBuffer {} }; 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); mesh->addMeshBuffer(meshbuf);

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,9 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include <catch.hpp> #include <catch.hpp>
#include <irrlicht.h> #include <irrlicht.h>
#include <iostream>
using namespace std;
class ScopedMesh class ScopedMesh
{ {
@ -60,9 +63,9 @@ TEST_CASE("minimal triangle") {
REQUIRE(sm.getMesh()->getMeshBuffer(0)->getIndexCount() == 3); REQUIRE(sm.getMesh()->getMeshBuffer(0)->getIndexCount() == 3);
const auto* indices = reinterpret_cast<irr::u16*>( const auto* indices = reinterpret_cast<irr::u16*>(
sm.getMesh()->getMeshBuffer(0)->getIndices()); sm.getMesh()->getMeshBuffer(0)->getIndices());
CHECK(indices[0] == 0); CHECK(indices[0] == 2);
CHECK(indices[1] == 1); 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); REQUIRE(sm.getMesh()->getMeshBuffer(0)->getIndexCount() == 36);
const auto* indices = reinterpret_cast<irr::u16*>( const auto* indices = reinterpret_cast<irr::u16*>(
sm.getMesh()->getMeshBuffer(0)->getIndices()); sm.getMesh()->getMeshBuffer(0)->getIndices());
CHECK(indices[0] == 0); CHECK(indices[0] == 16);
CHECK(indices[1] == 3); CHECK(indices[1] == 5);
CHECK(indices[2] == 9); CHECK(indices[2] == 22);
CHECK(indices[35] == 16); CHECK(indices[35] == 0);
} }
SECTION("vertex normals are correct") { SECTION("vertex normals are correct") {
@ -129,3 +132,142 @@ TEST_CASE("invalid JSON returns nullptr") {
CHECK(sm.getMesh() == 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<irr::video::S3DVertex*>(
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<irr::video::S3DVertex*>(
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<irr::video::S3DVertex*>(
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<irr::u16*>(
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<irr::u16*>(
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<irr::u16*>(
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<irr::video::S3DVertex*>(
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<irr::video::S3DVertex*>(
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<irr::video::S3DVertex*>(
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<irr::video::S3DVertex*>(
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<irr::video::S3DVertex*>(
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<irr::video::S3DVertex*>(
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});
}
}