♻️ refactor engine to use Mesh3D with transform support
- Add position, rotation and scale fields to `Mesh3D` and expose them publicly. - Remove the old `Object3D` struct; `Objects3D` now stores `unique_ptr<Mesh3D>`. - 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.
This commit is contained in:
		
							parent
							
								
									ab7539aed5
								
							
						
					
					
						commit
						7e36811c91
					
				| @ -2,6 +2,7 @@ | ||||
| #define _MESH3D | ||||
| 
 | ||||
| #include "Texture2D.h" | ||||
| #include <glm/ext/vector_float3.hpp> | ||||
| #include <vector> | ||||
| #include <string> | ||||
| 
 | ||||
| @ -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<float> meshVertices; | ||||
|       int numMeshVertices = 0; | ||||
|       int numFaces = 0; | ||||
|       void loadOBJFile(const std::string& filepath); | ||||
|       Texture2D texture; | ||||
|       GLuint VBO; | ||||
|       GLuint VAO; | ||||
|   }; | ||||
|  | ||||
| @ -4,24 +4,20 @@ | ||||
| #include <GL/glew.h> | ||||
| #include <GLFW/glfw3.h> | ||||
| #include "ShaderProgram.h" | ||||
| #include "Texture2D.h" | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <sstream> | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include "Mesh3D.h" | ||||
| #include <GL/glew.h> | ||||
| #include <GLFW/glfw3.h> | ||||
| #include <glm/glm.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| 
 | ||||
| #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<std::string,std::unique_ptr<djalim::Mesh3D>> 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); | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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<objVertex> vertices; | ||||
|   std::vector<objVertex> vertexNormal; | ||||
|   std::vector<objVertexTexture> vertexTexture; | ||||
|   std::vector<objFace> 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++; | ||||
|     } | ||||
|     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);  | ||||
|     } | ||||
|     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); | ||||
|     } | ||||
|     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; | ||||
| 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); | ||||
|       } | ||||
| 
 | ||||
|       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); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|     std::string line; | ||||
|     std::vector<objVertex> vertices; | ||||
|     std::vector<objVertex> vertexNormal; | ||||
|     std::vector<objVertexTexture> vertexTexture; | ||||
|     std::vector<objFace> 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++; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,10 +1,13 @@ | ||||
| #include "engine.h" | ||||
| #include "Mesh3D.h" | ||||
| #include <cstdlib> | ||||
| #include <glm/ext/vector_float3.hpp> | ||||
| #include <iostream> | ||||
| #include <iterator> | ||||
| #include <memory> | ||||
| #include <vector> | ||||
| #include <glm/glm.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| 
 | ||||
| djalim::OpenGlEngine::OpenGlEngine(const char* title, int width, int height) { | ||||
|   // initialize GLFW
 | ||||
| @ -43,6 +46,14 @@ 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){ | ||||
| 
 | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -1,44 +1 @@ | ||||
| #include "ShaderProgram.h" | ||||
| #include "Texture2D.h" | ||||
| #include "engine.h" | ||||
| #include "loops.h" | ||||
| #include <GL/glew.h> | ||||
| #include <GLFW/glfw3.h> | ||||
| #include <glm/glm.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| #include <iostream> | ||||
| 
 | ||||
| 
 | ||||
| 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;
 | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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"); | ||||
|   stbi_set_flip_vertically_on_load(true); | ||||
| 
 | ||||
|     // 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);
 | ||||
|   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) | ||||
|       ); | ||||
| 
 | ||||
|     // juste pour voir le cube
 | ||||
|     glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | ||||
|   glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | ||||
| } | ||||
|  | ||||
| @ -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()); | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user