From 0163373a9e24d836844d6f3f02e2567271911b47 Mon Sep 17 00:00:00 2001 From: sebastian Date: Sat, 7 Feb 2026 19:15:40 +0100 Subject: [PATCH] ADD: Load OBJ Models --- .gitmodules | 3 ++ CMakeLists.txt | 5 ++- assets/stall/stallTexture.png | Bin 0 -> 50242 bytes lib/tinyobjloader | 1 + src/engine/layer/GameLayer.cpp | 8 ++-- src/engine/renderer/loader/Loader.cpp | 4 ++ src/engine/renderer/loader/Loader.h | 4 +- src/engine/renderer/loader/OBJLoader.cpp | 54 +++++++++++++++++++++++ src/engine/renderer/loader/OBJLoader.h | 21 +++++++++ 9 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 assets/stall/stallTexture.png create mode 160000 lib/tinyobjloader create mode 100644 src/engine/renderer/loader/OBJLoader.cpp create mode 100644 src/engine/renderer/loader/OBJLoader.h diff --git a/.gitmodules b/.gitmodules index f965af7..d94eda4 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "lib/glm"] path = lib/glm url = https://github.com/g-truc/glm.git +[submodule "lib/tinyobjloader"] + path = lib/tinyobjloader + url = https://github.com/tinyobjloader/tinyobjloader.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 30758f9..26f5b89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,12 +51,15 @@ add_executable(Dicewars_Siedler src/main.cpp src/engine/layer/entities/Camera.cpp src/engine/layer/entities/Camera.h src/engine/platform/glfw/InputManager.cpp - src/engine/platform/glfw/InputManager.h) + src/engine/platform/glfw/InputManager.h + src/engine/renderer/loader/OBJLoader.cpp + src/engine/renderer/loader/OBJLoader.h) target_include_directories(Dicewars_Siedler PRIVATE lib/glfw/include lib/glm lib/stb_image + lib/tinyobjloader ) target_link_libraries(Dicewars_Siedler diff --git a/assets/stall/stallTexture.png b/assets/stall/stallTexture.png new file mode 100644 index 0000000000000000000000000000000000000000..d4d6f6ebe7340d37d6b10b8fb53cf420428c3113 GIT binary patch literal 50242 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 literal 0 HcmV?d00001 diff --git a/lib/tinyobjloader b/lib/tinyobjloader new file mode 160000 index 0000000..d56555b --- /dev/null +++ b/lib/tinyobjloader @@ -0,0 +1 @@ +Subproject commit d56555b026c1c7cec0f93f3ec7f1de2ff005c5ad diff --git a/src/engine/layer/GameLayer.cpp b/src/engine/layer/GameLayer.cpp index e010361..db137bf 100644 --- a/src/engine/layer/GameLayer.cpp +++ b/src/engine/layer/GameLayer.cpp @@ -6,6 +6,7 @@ #include "../platform/glfw/InputManager.h" #include "../renderer/Renderer.h" +#include "../renderer/loader/OBJLoader.h" #include "../renderer/model/TexturedModel.h" #include "../renderer/textures/ModelTexture.h" @@ -34,10 +35,8 @@ void GameLayer::onAttach() 1,0 //v3 }; - RawModel model = loader.loadToVAO(vertices, textureCoords, indices); - ModelTexture texture = ModelTexture(loader.loadTexture("assets/textures/texture.png")); - texturedModel = TexturedModel(std::make_shared(model), std::make_shared(texture)); - entity = std::make_unique(Entity(std::make_shared(texturedModel), glm::vec3(0,0,-1), 0,0,0, 1.f)); + texturedModel = *OBJLoader::loadModel("assets/stall/stall.obj", "assets/stall/stallTexture.png", loader); + entity = std::make_unique(Entity(std::make_shared(texturedModel), glm::vec3(0,0,-50), 0,0,0, 1.f)); camera = std::make_unique(); } @@ -54,6 +53,7 @@ void GameLayer::onUpdate() if (InputManager::isKeyPressed(GLFW_KEY_A)) moveDir.x -= 1.0f; if (InputManager::isKeyPressed(GLFW_KEY_D)) moveDir.x += 1.0f; + entity->increaseRotation(0,1,0); camera->move(moveDir, 0.02f); renderer.renderFrame(*entity, *camera); } diff --git a/src/engine/renderer/loader/Loader.cpp b/src/engine/renderer/loader/Loader.cpp index 9e984dc..620ff75 100644 --- a/src/engine/renderer/loader/Loader.cpp +++ b/src/engine/renderer/loader/Loader.cpp @@ -34,6 +34,10 @@ void Loader::cleanUp() { } } +ModelTexture Loader::loadTextureFromFile(const std::string &path) { + return ModelTexture(loadTexture(path)); +} + GLuint Loader::loadTexture(const std::string &path) { Texture2D texture = TextureLoader::loadTexture(path); textureIDs.push_back(texture.id); diff --git a/src/engine/renderer/loader/Loader.h b/src/engine/renderer/loader/Loader.h index 460be3e..e58a9a7 100644 --- a/src/engine/renderer/loader/Loader.h +++ b/src/engine/renderer/loader/Loader.h @@ -8,6 +8,7 @@ #include #include "../model/RawModel.h" +#include "../textures/ModelTexture.h" #include "glad/glad.h" @@ -18,9 +19,10 @@ public: ~Loader(); void cleanUp(); - GLuint loadTexture(const std::string &path); + ModelTexture loadTextureFromFile(const std::string& path); private: GLuint createVAO(); + GLuint loadTexture(const std::string &path); void storeDataInAttributeList(int attributeNumber, int coordinateSize, const std::vector &data); void bindIndicesBuffer(const std::vector &indices); void unbindVAO(); diff --git a/src/engine/renderer/loader/OBJLoader.cpp b/src/engine/renderer/loader/OBJLoader.cpp new file mode 100644 index 0000000..5fbbd13 --- /dev/null +++ b/src/engine/renderer/loader/OBJLoader.cpp @@ -0,0 +1,54 @@ +// +// Created by sebastian on 07.02.26. +// + +#include "OBJLoader.h" + +#define TINYOBJLOADER_IMPLEMENTATION +#include "tiny_obj_loader.h" + +std::shared_ptr OBJLoader::loadModel(const std::string &modelPath, const std::string& texturePath, Loader &loader) { + tinyobj::attrib_t attrib; + std::vector shapes; + std::vector materials; + std::string warn, err; + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, modelPath.c_str())) { + throw std::runtime_error(warn + err); + } + + if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, modelPath.c_str())) { + throw std::runtime_error("Failed to load OBJ: " + warn + err); + } + + std::vector vertices; + std::vector uvs; + std::vector indices; + + int indexOffset = 0; + for (const auto& shape : shapes) { + for (const auto& index : shape.mesh.indices) { + // Vertex-Position + vertices.push_back(attrib.vertices[3*index.vertex_index + 0]); + vertices.push_back(attrib.vertices[3*index.vertex_index + 1]); + vertices.push_back(attrib.vertices[3*index.vertex_index + 2]); + + // UV-Koordinaten + if (!attrib.texcoords.empty()) { + uvs.push_back(attrib.texcoords[2*index.texcoord_index + 0]); + uvs.push_back(attrib.texcoords[2*index.texcoord_index + 1]); + } else { + uvs.push_back(0.0f); + uvs.push_back(0.0f); + } + + // Index + indices.push_back(indexOffset); + indexOffset++; + } + } + + RawModel rawModel = loader.loadToVAO(vertices, uvs, indices); + ModelTexture modelTexture = loader.loadTextureFromFile(texturePath); + TexturedModel texturedModel = TexturedModel(std::make_shared(rawModel), std::make_shared(modelTexture)); + return std::make_shared(texturedModel); +} diff --git a/src/engine/renderer/loader/OBJLoader.h b/src/engine/renderer/loader/OBJLoader.h new file mode 100644 index 0000000..5f0d4c2 --- /dev/null +++ b/src/engine/renderer/loader/OBJLoader.h @@ -0,0 +1,21 @@ +// +// Created by sebastian on 07.02.26. +// + +#ifndef OBJLOADER_H +#define OBJLOADER_H +#include + +#include "Loader.h" +#include "../model/TexturedModel.h" + + +class OBJLoader { +public: + static std::shared_ptr loadModel(const std::string &modelPath, const std::string &texturePath, Loader &loader); + +}; + + + +#endif //OBJLOADER_H