From 7e36811c91d5ee0bb7ff88da5a33734568988eb2 Mon Sep 17 00:00:00 2001 From: Djalim Simaila Date: Sat, 25 Oct 2025 19:46:49 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor=20engine=20to=20u?= =?UTF-8?q?se=20Mesh3D=20with=20transform=20support?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add position, rotation and scale fields to `Mesh3D` and expose them publicly. - Remove the old `Object3D` struct; `Objects3D` now stores `unique_ptr`. - Implement a new `createObject(name,textures,filepath,position,rotation,scale)` overload that sets transforms after loading the mesh. - Add a `draw(Mesh3D*)` helper that binds the texture, builds a model matrix and issues `glDrawArrays`. - Update the rendering loop to use `draw()` instead of the old cube routine. - Simplify `onCreate`: enable depth test, flip textures, create two objects with proper transforms, set clear color. - Enable window resizing (`GLFW_RESIZABLE`), change default size to 800×600 in `main.cpp`. - Clean up includes and remove unused `cube.cpp`; refactor OBJ parsing for robustness. These changes unify object handling, allow per‑object transformations, simplify the rendering pipeline, improve maintainability, and make the window resizable. --- include/Mesh3D.h | 11 ++- include/engine.h | 16 ++-- src/core/Mesh3D.cpp | 177 ++++++++++++++++++++++---------------------- src/core/engine.cpp | 42 +++++++++-- src/core/hints.cpp | 2 +- src/loops/cube.cpp | 43 ----------- src/main.cpp | 2 +- src/onCreate.cpp | 36 +++------ src/onUpdate.cpp | 18 ++++- 9 files changed, 170 insertions(+), 177 deletions(-) diff --git a/include/Mesh3D.h b/include/Mesh3D.h index c4f4abd..bde7940 100644 --- a/include/Mesh3D.h +++ b/include/Mesh3D.h @@ -2,6 +2,7 @@ #define _MESH3D #include "Texture2D.h" +#include #include #include @@ -9,13 +10,19 @@ namespace djalim { class Mesh3D { public: + Mesh3D(); Mesh3D(const std::string& filepath); + void loadOBJFile(const std::string& filepath); + public: + Texture2D texture; + glm::vec3 position = {0.0f, 0.0f, 0.0f}; + glm::vec3 rotation = {0.0f, 0.0f, 0.0f}; + glm::vec3 scale = {1.0f, 1.0f, 1.0f}; + std::vector meshVertices; int numMeshVertices = 0; int numFaces = 0; - void loadOBJFile(const std::string& filepath); - Texture2D texture; GLuint VBO; GLuint VAO; }; diff --git a/include/engine.h b/include/engine.h index 0b5918f..e96017d 100644 --- a/include/engine.h +++ b/include/engine.h @@ -4,24 +4,20 @@ #include #include #include "ShaderProgram.h" -#include "Texture2D.h" #include #include -#include #include -#include #include "Mesh3D.h" +#include +#include +#include +#include +#include #define NBCALLBACKS 1 typedef void (*KeyCallback)(GLFWwindow* window, int key, int scancode, int action, int mods); -struct Object3D { - Texture2D texture; - GLuint VBO; - GLuint VAO; -}; - typedef std::map> Objects3D; static bool gWireframe = false; @@ -52,10 +48,12 @@ namespace djalim { void onUpdate(); void loadHints(); void createObject(std::string name, std::string textures, std::string filepath); + void createObject(std::string name, std::string textures, std::string filepath, glm::vec3 position, glm::vec3 rotation, glm::vec3 scale); void loadCallbacks(); void showFps(); void onCreate(); void onDestroy(); + void draw(Mesh3D* object); }; } diff --git a/src/core/Mesh3D.cpp b/src/core/Mesh3D.cpp index 9a037ae..5248d34 100644 --- a/src/core/Mesh3D.cpp +++ b/src/core/Mesh3D.cpp @@ -31,97 +31,96 @@ djalim::Mesh3D::Mesh3D(const std::string& filepath) { loadOBJFile(filepath); } - -void djalim::Mesh3D::loadOBJFile(const std::string& filepath){ - - std::ifstream file(filepath); - if (!file.is_open()) { - std::cerr << "Failed to open OBJ file: " << filepath << std::endl; - exit(1); - } - std::string line; - std::vector vertices; - std::vector vertexNormal; - std::vector vertexTexture; - std::vector faces; - - while (std::getline(file, line)) { - std::stringstream ss(line); - std::string type; - ss >> type; - - if (type == "v"){ - float x, y, z; - ss >> x >> y >> z; - //std::cout << "found vertice: (" << x << ", " << y << ", " << z << ")" << std::endl; - objVertex v = {x, y, z}; - vertices.push_back(v); - numMeshVertices++; +void djalim::Mesh3D::loadOBJFile(const std::string& filepath) { + std::ifstream file(filepath); + if (!file.is_open()) { + std::cerr << "Failed to open OBJ file: " << filepath << std::endl; + exit(1); } - else if (type == "vn"){ - float x, y, z; - ss >> x >> y >> z; - //std::cout << "found normal: (" << x << ", " << y << ", " << z << ")" << std::endl; - objVertex v = {x, y, z}; - vertexNormal.push_back(v); + + std::string line; + std::vector vertices; + std::vector vertexNormal; + std::vector vertexTexture; + std::vector faces; + + while (std::getline(file, line)) { + std::stringstream ss(line); + std::string type; + ss >> type; + + if (type == "v") { + float x, y, z; + ss >> x >> y >> z; + vertices.push_back({x, y, z}); + numMeshVertices++; + } + else if (type == "vn") { + float x, y, z; + ss >> x >> y >> z; + vertexNormal.push_back({x, y, z}); + } + else if (type == "vt") { + float u, v; + ss >> u >> v; + vertexTexture.push_back({u, v}); + } + else if (type == "f") { + objFace face; + for (int i = 0; i < 3; i++) { + std::string token; + ss >> token; + + objFaceIndice f = {-1, -1, -1}; + std::stringstream tokenStream(token); + std::string part; + int partIndex = 0; + + // Split sur les '/' + while (std::getline(tokenStream, part, '/')) { + if (!part.empty()) { + int index = std::stoi(part); + if (partIndex == 0) f.v = index - 1; // vertex + else if (partIndex == 1) f.vt = index - 1; // texture + else if (partIndex == 2) f.vn = index - 1; // normal + } + partIndex++; + } + + face.vertices[i] = f; + } + faces.push_back(face); + numFaces++; + } } - else if (type == "vt"){ - float u, v; - ss >> u >> v; - //std::cout << "found texture: (" << u << ", " << v << ")" << std::endl; - objVertexTexture vt = {u, v}; - vertexTexture.push_back(vt); + + // Construction du mesh + for (const auto& face : faces) { + for (int j = 0; j < 3; j++) { + int verticeIndex = face.vertices[j].v; + + if (verticeIndex < 0 || verticeIndex >= (int)vertices.size()) { + std::cerr << "Error: Vertex index out of range" << std::endl; + exit(1); + } + + const objVertex& v = vertices[verticeIndex]; + meshVertices.push_back(v.x); + meshVertices.push_back(v.y); + meshVertices.push_back(v.z); + + // Si le fichier ne contient pas de vt, on met des coordonnées par défaut (0,0) + int vtIndex = face.vertices[j].vt; + if (vtIndex >= 0 && vtIndex < (int)vertexTexture.size()) { + const objVertexTexture& tex = vertexTexture[vtIndex]; + meshVertices.push_back(tex.u); + meshVertices.push_back(tex.v); + } else { + meshVertices.push_back(0.0f); + meshVertices.push_back(0.0f); + } + } } - else if (type == "f"){ - // std::cout << "found face" << std::endl; - // std::cout << ss.str() << std::endl; - objFace face; - // TODO Find a more elegant way to do this - for (int i = 0; i < 3; i++){ - int a, b, c; - char slash; - ss >> a >> slash >> b >> slash >> c; - //std::cout << "vertex " << i << " :(" << a << ", " << b << ", " << c << ")" << std::endl; - objFaceIndice f = {a-1, b-1, c-1}; - face.vertices[i] = f; - } - faces.push_back(face); - numFaces++; - } - } - // Pour chaque face - for(int i = 0; i < faces.size() ; i++ ){ - objFace currentFace = faces[i]; - // pour chaque vertex de cette face - for (int j = 0; j < 3; j++){ - - int verticeIndex = currentFace.vertices[j].v; - - if(verticeIndex >= vertices.size()){ - std::cerr << "Error: Vertex index out of range" << std::endl; - exit(1); - } - - objVertex currentVertice = vertices[verticeIndex]; - - meshVertices.push_back(currentVertice.x); - meshVertices.push_back(currentVertice.y); - meshVertices.push_back(currentVertice.z); - - //uv - - int verticeTextureIndex = currentFace.vertices[j].vt; - - if(verticeTextureIndex >= vertexTexture.size()){ - std::cerr << "Error: Texture index out of range" << std::endl; - exit(1); - } - - objVertexTexture currentTexture = vertexTexture[verticeTextureIndex]; - - meshVertices.push_back(currentTexture.u); - meshVertices.push_back(currentTexture.v); - } - } } + diff --git a/src/core/engine.cpp b/src/core/engine.cpp index 70a393b..d820bef 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -1,10 +1,13 @@ #include "engine.h" #include "Mesh3D.h" #include +#include #include -#include #include #include +#include +#include +#include djalim::OpenGlEngine::OpenGlEngine(const char* title, int width, int height) { // initialize GLFW @@ -43,16 +46,24 @@ djalim::OpenGlEngine::OpenGlEngine(const char* title, int width, int height) { } +void djalim::OpenGlEngine::createObject(std::string name, std::string textures, std::string filepath, glm::vec3 position, glm::vec3 rotation, glm::vec3 scale){ + createObject(name,textures,filepath); + (objects[name])->position = position; + (objects[name])->rotation = rotation; + (objects[name])->scale = scale; +} + + void djalim::OpenGlEngine::createObject(std::string name, std::string textures, std::string filepath){ - + // Load the mesh from the file objects[name] = std::make_unique(Mesh3D(filepath)); bool textureLoaded = objects[name]->texture.loadTexture(textures); - + std::cout << &(objects[name]) << std::endl; - + if (!textureLoaded) { std::cerr << "Failed to load " << name << " texture!" << std::endl; exit(1); @@ -64,16 +75,16 @@ void djalim::OpenGlEngine::createObject(std::string name, std::string textures, //glGenBuffers(1, &VBO); glGenBuffers(1, &((objects[name])->VBO)); - + //glBindVertexArray(VAO); glBindVertexArray((objects[name])->VAO); //glBindBuffer(GL_ARRAY_BUFFER, VBO); glBindBuffer(GL_ARRAY_BUFFER, (objects[name])->VBO); - + glBufferData(GL_ARRAY_BUFFER, sizeof(float)*(objects[name])->meshVertices.size(), (objects[name])->meshVertices.data(), GL_STATIC_DRAW); - + // Attribut de position glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); @@ -108,3 +119,20 @@ void djalim::OpenGlEngine::start(){ } } + + +void djalim::OpenGlEngine::draw(djalim::Mesh3D* object){ + object->texture.bind(); + glm::mat4 model = glm::mat4(1.0f); + + if (object->rotation != glm::vec3(.0,.0,.0)){ + model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), object->rotation); + } + model = glm::translate(model, object->position); + model = glm::scale(model, object->scale); + + shaderProgram.setUniform("model", model); + + glBindVertexArray(object->VAO); + glDrawArrays(GL_TRIANGLES, 0, object->numFaces * 3); +} diff --git a/src/core/hints.cpp b/src/core/hints.cpp index 35abe3d..313e41b 100644 --- a/src/core/hints.cpp +++ b/src/core/hints.cpp @@ -5,5 +5,5 @@ void djalim::OpenGlEngine::loadHints(){ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); + glfwWindowHint(GLFW_RESIZABLE, GL_TRUE); } diff --git a/src/loops/cube.cpp b/src/loops/cube.cpp index aed3eeb..8b13789 100644 --- a/src/loops/cube.cpp +++ b/src/loops/cube.cpp @@ -1,44 +1 @@ -#include "ShaderProgram.h" -#include "Texture2D.h" -#include "engine.h" -#include "loops.h" -#include -#include -#include -#include -#include -#include - -void djalim::cube(GLFWwindow* window, djalim::ShaderProgram shader, Objects3D& objects){ - - shader.use(); - shader.setUniform("ourTexture", 0); - - (objects["cube"])->texture.bind(); - - //std::cout << &(objects["cube"].texture) << std::endl; - //textures["cube"].bind(); - - // Matrice de Projection - glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); - shader.setUniform("projection", projection); // Assurez-vous que setUniform pour mat4 est implémenté - - // Matrice de Vue - glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 11.0f), // Position caméra - glm::vec3(0.0f, 2.0f, 0.0f), // Cible - glm::vec3(0.0f, 1.0f, 0.0f)); // Axe Haut - shader.setUniform("view", view); - - // Matrice Modèle - glm::mat4 model = glm::mat4(1.0f); - ///model = glm::rotate(model, (float)glfwGetTime() * glm::radians(50.0f), glm::vec3(0.5f, 1.0f, 0.0f)); - shader.setUniform("model", model); - - // Dessiner le cube - glBindVertexArray((objects["cube"])->VAO); - glDrawArrays(GL_TRIANGLES, 0, (objects["cube"])->numFaces * 3); - - //std::cout << objects["cube"].VAO << std::endl; - -} diff --git a/src/main.cpp b/src/main.cpp index 428f29e..a1ec38f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,7 @@ #include "engine.h" int main() { - djalim::OpenGlEngine engine = djalim::OpenGlEngine("Mon app", 1000, 1000); + djalim::OpenGlEngine engine = djalim::OpenGlEngine("Mon app", 800, 600); engine.start(); return 0; } diff --git a/src/onCreate.cpp b/src/onCreate.cpp index b3a6109..6bf639e 100644 --- a/src/onCreate.cpp +++ b/src/onCreate.cpp @@ -2,30 +2,18 @@ #include "Texture2D.h" void djalim::OpenGlEngine::onCreate(){ - glEnable(GL_DEPTH_TEST); + glEnable(GL_DEPTH_TEST); - stbi_set_flip_vertically_on_load(true); - createObject("cube", "../assets/textures/robot_diffuse.jpg", "../assets/models/robot.obj"); - - // textures["cube"] = Texture2D(); - // bool textureLoaded = textures["cube"].loadTexture("../assets/textures/prof.png"); - // if (!textureLoaded) { - // std::cerr << "Failed to load cube texture!" << std::endl; - // return; - // } - // - // glGenVertexArrays(1, &VAO); - // glGenBuffers(1, &VBO); - // glBindVertexArray(VAO); - // glBindBuffer(GL_ARRAY_BUFFER, VBO); - // glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - // // Attribut de position - // glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0); - // glEnableVertexAttribArray(0); - // // Attribut de coordonnée de texture - // glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float))); - // glEnableVertexAttribArray(1); + stbi_set_flip_vertically_on_load(true); - // juste pour voir le cube - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + createObject("cube", "../assets/textures/prof.png", "../assets/models/L.obj"); + createObject("mimikyu", + "../assets/textures/crate.jpg", + "../assets/models/crate.obj", + glm::vec3(1.0,1.0,1.0), + glm::vec3(0.0,1.0,0.0), + glm::vec3(1.0,1.0,1.0) + ); + + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); } diff --git a/src/onUpdate.cpp b/src/onUpdate.cpp index 6d4b1af..199b497 100644 --- a/src/onUpdate.cpp +++ b/src/onUpdate.cpp @@ -5,6 +5,22 @@ void djalim::OpenGlEngine::onUpdate(){ showFps(); - cube(window,shaderProgram,objects); + + shaderProgram.use(); + shaderProgram.setUniform("ourTexture", 0); + + // Matrice de Projection + glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); + shaderProgram.setUniform("projection", projection); + + // Matrice de Vue + glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 10.0f), // Position caméra + glm::vec3(0.0f, 0.0f, 0.0f), // Cible + glm::vec3(0.0f, 1.0f, 0.0f)); // Axe Haut + shaderProgram.setUniform("view", view); + + draw((objects["cube"]).get()); + draw((objects["mimikyu"]).get()); + }