Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f0986b8
feat(object): add the declaration of the Vertex structure to represen…
MasterLaplace Dec 6, 2024
0e8a84f
feat(object): add the declaration of the Mesh structure to represent …
MasterLaplace Dec 6, 2024
cda8f50
feat(object): implement OBJLoader for loading .obj files and managing…
MasterLaplace Dec 6, 2024
b372439
feat(object): add inclusions for OBJLoader, Vertex, and Mesh in Objec…
MasterLaplace Dec 9, 2024
d50f517
feat(object): add validation for model loading path in OBJLoader
MasterLaplace Dec 9, 2024
6b6612f
feat(object): reorder includes in Object.hpp and add unit tests for O…
MasterLaplace Dec 9, 2024
054a214
style: apply linter
github-actions[bot] Dec 9, 2024
eed6e74
feat(tests): add .obj files for model loading tests
MasterLaplace Dec 9, 2024
edbba8a
fix(object): move TINYOBJLOADER_IMPLEMENTATION to OBJLoader.cpp and u…
MasterLaplace Dec 9, 2024
da879eb
fix(tests): update OBJLoader tests to use a defined file path for assets
MasterLaplace Dec 9, 2024
5a04226
style: apply linter
github-actions[bot] Dec 9, 2024
d0f16f1
fix(object): refactor OBJLoader to include Logger and change target k…
MasterLaplace Dec 9, 2024
e22afdd
fix(tests): update OBJLoader tests to use a new asset path and adjust…
MasterLaplace Dec 9, 2024
b3c22c4
fix(build): update asset handling in xmake.lua for improved build pro…
MasterLaplace Dec 9, 2024
727892a
fix(tests): remove obsolete loadModel_fail test and associated asset
MasterLaplace Dec 9, 2024
de8e13a
fix(build): remove obsolete test target configuration from xmake.lua
MasterLaplace Dec 9, 2024
0e6d7ca
fix(tests): add assertions to verify vertices and indices are not emp…
MasterLaplace Dec 9, 2024
d85e575
refactor(mesh): update MeshLoader to use a functor for loading meshes
MasterLaplace Dec 9, 2024
f26bf0c
test(mesh): add unit test for loading mesh from entt resource cache
MasterLaplace Dec 9, 2024
36b6fb0
test(vertex): add unit tests for the Vertex structure
MasterLaplace Dec 9, 2024
8ba35a6
style: apply linter
github-actions[bot] Dec 9, 2024
d711469
refactor(vertex): simplify equality operator and add unit test for fa…
MasterLaplace Dec 9, 2024
ae32655
refactor(tests): rename test files and update test case names for con…
MasterLaplace Dec 9, 2024
41de6fd
refactor(xmake): restructure build and clean functions for asset mana…
MasterLaplace Dec 10, 2024
4e64c62
fix: update dependency management and change build hook to after_build
MasterLaplace Dec 15, 2024
b225040
refactor(OBJLoader): replace push_back with emplace_back for performa…
MasterLaplace Dec 15, 2024
00bd96b
test(OBJLoader): update test case to use non-OBJ file and add corresp…
MasterLaplace Dec 15, 2024
f1392ff
Merge branch 'main' into 40-obj-loader
ripel2 Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/plugin/object/src/Object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@

#include "AssetID.hpp"
#include "AssetsManager.hpp"
#include "Mesh.hpp"
#include "MeshID.hpp"
#include "OBJLoader.hpp"
#include "Transform.hpp"
#include "Vertex.hpp"
59 changes: 59 additions & 0 deletions src/plugin/object/src/component/Mesh.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**************************************************************************
* EngineSquared v0.0.0
*
* EngineSquared is a software package, part of the Engine².
*
* This file is part of the EngineSquared project that is under GPL-3.0 License.
* Copyright © 2024 by @EngineSquared, All rights reserved.
*
* EngineSquared is a free software: you can redistribute it and/or modify
* it under the terms of the GPL-3.0 License as published by the
* Free Software Foundation. See the GPL-3.0 License for more details.
*
* @file Mesh.hpp
* @brief Mesh struct declaration.
*
* This struct is used to represent a mesh.
*
* @author @MasterLaplace
* @version 0.0.0
* @date 2024-12-06
**************************************************************************/

#ifndef MESH_HPP_
#define MESH_HPP_

#include "OBJLoader.hpp"

#include <entt/resource/loader.hpp>

namespace ES::Plugin::Object::Component {

/**
* @brief Mesh structure.
*
* This structure is used to represent a mesh.
* It contains the vertices and indices of the mesh.
*/
struct Mesh {
std::vector<Component::Vertex> vertices;
std::vector<uint32_t> indices;

explicit Mesh(const std::string &file) { Resource::OBJLoader::loadModel(file, vertices, indices); }
};

/**
* @brief MeshLoader structure.
*
* This structure is used to load a mesh from a file.
* @note This structure is used by the entt resource cache.
*/
struct MeshLoader final {
using result_type = std::shared_ptr<Mesh>;
Comment thread
ripel2 marked this conversation as resolved.

result_type operator()(const std::string &file) const { return std::make_shared<Mesh>(file); }
};

} // namespace ES::Plugin::Object::Component

#endif /* !MESH_HPP_ */
70 changes: 70 additions & 0 deletions src/plugin/object/src/component/Vertex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**************************************************************************
* EngineSquared v0.0.0
*
* EngineSquared is a software package, part of the Engine².
*
* This file is part of the EngineSquared project that is under GPL-3.0 License.
* Copyright © 2024 by @EngineSquared, All rights reserved.
*
* EngineSquared is a free software: you can redistribute it and/or modify
* it under the terms of the GPL-3.0 License as published by the
* Free Software Foundation. See the GPL-3.0 License for more details.
*
* @file Vertex.hpp
* @brief Vertex struct declaration.
*
* This struct is used to represent a vertex in a mesh.
*
* @author @MasterLaplace
* @version 0.0.0
* @date 2024-12-06
**************************************************************************/

#ifndef VERTEX_HPP_
#define VERTEX_HPP_

#include <glm/glm.hpp>

#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>

namespace ES::Plugin::Object::Component {

/**
* @brief Vertex structure.
*
* This structure is used to represent a vertex in a mesh.
* It contains the position, color, and texture coordinates of the vertex.
*/
struct Vertex {
glm::vec3 pos;
glm::vec3 color;
glm::vec2 texCoord;

bool operator==(const Vertex &other) const = default;
};

} // namespace ES::Plugin::Object::Component

namespace std {

/**
* @brief Hash function for the Vertex structure.
*/
template <> struct hash<ES::Plugin::Object::Component::Vertex> {
/**
* @brief Hash function for the Vertex structure.
*
* @param vertex Vertex to hash.
* @return std::size_t Hash value.
*/
size_t operator()(ES::Plugin::Object::Component::Vertex const &vertex) const
{
return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.color) << 1)) >> 1) ^
(hash<glm::vec2>()(vertex.texCoord) << 1);
}
};

} // namespace std

#endif /* !VERTEX_HPP_ */
69 changes: 69 additions & 0 deletions src/plugin/object/src/resource/OBJLoader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "OBJLoader.hpp"

#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"

#include "Logger.hpp"

namespace ES::Plugin::Object::Resource {

bool OBJLoader::loadModel(const std::string &path, std::vector<Component::Vertex> &vertices,
std::vector<uint32_t> &indices)
{
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warn;
std::string err;

if (path.empty())
{
ES::Utils::Log::Warn("The path is empty.");
return false;
}

else if (path.ends_with(".obj") == false)
{
ES::Utils::Log::Warn("The file is not a .obj file.");
return false;
}

else if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, path.c_str()))
{
ES::Utils::Log::Warn(warn + err);
return false;
}

vertices.reserve(attrib.vertices.size() / 3);
indices.reserve(attrib.vertices.size());

std::unordered_map<Component::Vertex, uint32_t> uniqueVertices{};

for (const auto &shape : shapes)
{
for (const auto &index : shape.mesh.indices)
{
Component::Vertex vertex{};

vertex.pos = {attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1],
attrib.vertices[3 * index.vertex_index + 2]};

vertex.texCoord = {attrib.texcoords[2 * index.texcoord_index + 0],
1.0f - attrib.texcoords[2 * index.texcoord_index + 1]};

vertex.color = {1.0f, 1.0f, 1.0f};

if (uniqueVertices.count(vertex) == 0)
{
uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
vertices.emplace_back(vertex);
}

indices.emplace_back(uniqueVertices[vertex]);
}
}

return true;
}

} // namespace ES::Plugin::Object::Resource
56 changes: 56 additions & 0 deletions src/plugin/object/src/resource/OBJLoader.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**************************************************************************
* EngineSquared v0.0.0
*
* EngineSquared is a software package, part of the Engine².
*
* This file is part of the EngineSquared project that is under GPL-3.0 License.
* Copyright © 2024 by @EngineSquared, All rights reserved.
*
* EngineSquared is a free software: you can redistribute it and/or modify
* it under the terms of the GPL-3.0 License as published by the
* Free Software Foundation. See the GPL-3.0 License for more details.
*
* @file OBJLoader.hpp
* @brief OBJLoader class declaration.
*
* This class is used to load .obj files and create a model from them.
*
* @author @MasterLaplace
* @version 0.0.0
* @date 2024-12-06
**************************************************************************/

#ifndef OBJLOADER_HPP_
#define OBJLOADER_HPP_

#include <memory>
#include <stdexcept>
#include <string>
#include <vector>

#include "Vertex.hpp"

namespace ES::Plugin::Object::Resource {

/**
* @brief OBJLoader class.
*
* This class is used to load .obj files.
*/
class OBJLoader {
public:
/**
* Load a model from a .obj file.
*
* @param path path to the .obj file
* @param vertices vector to store the vertices
* @param indices vector to store the indices
* @return true if the model was loaded successfully, false otherwise
*/
static bool loadModel(const std::string &path, std::vector<Component::Vertex> &vertices,
std::vector<uint32_t> &indices);
Comment thread
ripel2 marked this conversation as resolved.
};

} // namespace ES::Plugin::Object::Resource

#endif /* !OBJLOADER_HPP_ */
32 changes: 32 additions & 0 deletions src/plugin/object/tests/MeshTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <gtest/gtest.h>

#include "Mesh.hpp"

#include <entt/core/hashed_string.hpp>
#include <entt/resource/cache.hpp>

#include "export.h"

#define OBJ_FILE_PATH PROJECT_SOURCE_DIR "assets/"

using namespace ES::Plugin::Object;

/**
* @brief Load a mesh from a file using the entt resource cache.
* The mesh is loaded from a file and stored in the cache.
* The mesh is then retrieved from the cache and its vertices are checked.
*/
TEST(MeshTest, component_mesh_entt_cache_loader)
{
entt::resource_cache<Component::Mesh, Component::MeshLoader> cache{};

std::string something_else("mesh_id");
auto ret = cache.load(entt::hashed_string{something_else.c_str()}, std::string(OBJ_FILE_PATH "cube.obj"));

EXPECT_EQ(ret.second, true);

entt::resource<Component::Mesh> res = ret.first->second;

EXPECT_EQ(res->vertices.empty(), false);
EXPECT_EQ(res->indices.empty(), false);
}
44 changes: 44 additions & 0 deletions src/plugin/object/tests/OBJLoaderTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <gtest/gtest.h>

#include "OBJLoader.hpp"

#include "export.h"

#define OBJ_FILE_PATH PROJECT_SOURCE_DIR "assets/"

using namespace ES::Plugin::Object;

TEST(OBJLoaderTest, loadModel)
{
std::vector<Component::Vertex> vertices;
std::vector<uint32_t> indices;

EXPECT_EQ(Resource::OBJLoader::loadModel(OBJ_FILE_PATH "cube.obj", vertices, indices), true);

EXPECT_EQ(vertices.empty(), false);
EXPECT_EQ(indices.empty(), false);
}

TEST(OBJLoaderTest, loadModel_empty_path)
{
std::vector<Component::Vertex> vertices;
std::vector<uint32_t> indices;

EXPECT_EQ(Resource::OBJLoader::loadModel("", vertices, indices), false);
}

TEST(OBJLoaderTest, loadModel_not_obj_file)
{
std::vector<Component::Vertex> vertices;
std::vector<uint32_t> indices;

EXPECT_EQ(Resource::OBJLoader::loadModel(OBJ_FILE_PATH "not_obj.txt", vertices, indices), false);
}

TEST(OBJLoaderTest, loadModel_wrong_path)
{
std::vector<Component::Vertex> vertices;
std::vector<uint32_t> indices;

EXPECT_EQ(Resource::OBJLoader::loadModel("wrong_path", vertices, indices), false);
}
Loading