From f322c5fc3cb8c6fb74b536fa56dfec6771b56cb9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Th=C3=A9au?= <theau.baton@etu.univ-amu.fr>
Date: Mon, 20 May 2024 16:54:24 +0200
Subject: [PATCH] Start interface for MesgGenerator Scene

---
 .../Scene/MeshGeneratorInterface.cpp          |  53 ++++++++
 .../Scene/MeshGeneratorInterface.hpp          |  37 ++++++
 .../src/Scene/Scenes/MeshGenerator.cpp        | 121 +++++++++++-------
 .../src/Scene/Scenes/MeshGenerator.hpp        |  12 +-
 4 files changed, 176 insertions(+), 47 deletions(-)
 create mode 100644 ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.cpp
 create mode 100644 ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.hpp

diff --git a/ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.cpp b/ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.cpp
new file mode 100644
index 0000000..19c74a6
--- /dev/null
+++ b/ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.cpp
@@ -0,0 +1,53 @@
+#include "MeshGeneratorInterface.hpp"
+
+#include <imgui.h>
+#include "../../Scene/Scenes/MeshGenerator.hpp"
+#include "../../tfd/tinyfiledialogs.h"
+
+namespace pg {
+    MeshGeneratorInterface::MeshGeneratorInterface(scene::MeshGenerator * scene, size_t max) 
+    : _scene(scene),
+      _max(max),
+      _spawnFrequence(2500),
+      _spawnCount(1),
+      _lifetime(2),
+      _enableRender(true),
+      _enableSpawn(true) {
+
+    }
+
+    void MeshGeneratorInterface::render(double current_time) {
+        ImGui::Text("Particles Number : %i / %i.", this->_scene->_particles.size(), this->_max);
+        ImGui::SameLine();
+        if(ImGui::Button("Spawn")) {
+            this->_scene->spawn(1, current_time);
+        }
+
+        ImGui::SameLine();
+        if(ImGui::Button("Clear")) {
+            this->_scene->_particles.clear();
+        }
+
+        ImGui::Text("Particles Batchs : %i", static_cast<int>(this->_scene->_particles.size() / 1024) + 1);
+        ImGui::Separator();
+        ImGui::Checkbox("Enable Rendering", &this->_enableRender);
+        ImGui::Checkbox("Enable Spawning", &this->_enableSpawn);
+        ImGui::Separator();
+        ImGui::InputInt("Lifetime (s)", &this->_lifetime, 1, 2);
+        ImGui::InputInt("Spawn Frequence (ms)", &this->_spawnFrequence, 100, 500);
+        ImGui::SliderInt("Spawning Number", &this->_spawnCount, 1, static_cast<int>(this->_max));
+
+        ImGui::SeparatorText("Model");
+        if(ImGui::Button("Change Model")) {
+            char const * imagePatterns[1] = {"*.obj"};
+            std::string path = tinyfd_openFileDialog("Model Browser", "", 1, imagePatterns, "Model File", false);
+            this->_scene->changeMesh(path);
+        }
+
+        if(ImGui::CollapsingHeader("Global Genrator Parameter")) {
+            if(ImGui::Button("Apply")) {
+                
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.hpp b/ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.hpp
new file mode 100644
index 0000000..8c584af
--- /dev/null
+++ b/ParticleGenerator/src/Interface/Scene/MeshGeneratorInterface.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "../Interface.hpp"
+
+namespace pg {
+    namespace scene {
+        class MeshGenerator;
+    }
+
+    class MeshGeneratorInterface : public Interface {
+        private:
+            scene::MeshGenerator * _scene;
+
+            size_t _max;
+			int _spawnFrequence;
+			int _spawnCount;
+			int _lifetime;
+
+			bool _enableRender;
+            bool _enableSpawn;
+        
+        public:
+            MeshGeneratorInterface(scene::MeshGenerator *, size_t max = 1024);
+
+            inline size_t getMaxParticle() const {return this->_max;}
+
+			inline int getSpawnFrequence() const {return this->_spawnFrequence;}
+			inline int getSpawnCount() const {return this->_spawnCount;}
+			inline int getLifeTime() const {return this->_lifetime;}
+
+			inline bool isRenderEnable() {return this->_enableRender;}
+            inline bool isSpawnEnable() {return this->_enableSpawn;}
+
+            virtual void render(double);
+            inline std::string title() const {return "Mesh Generator Scene Interface";}
+    };
+}
\ No newline at end of file
diff --git a/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp
index 48065d5..0f49055 100644
--- a/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp
+++ b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp
@@ -17,30 +17,12 @@ namespace pg::scene {
       _billboard(),
       _billboardTexture(),
       _billboardProgram(),
-      _ubo(0) {}
+      _ubo(0),
+      _interface(this, 8192) {}
 
     void MeshGenerator::initialize() {
         if(!this->_mesh.isGenerated()) {
-            Model model("res/models/sphere.obj");
-
-            MeshGeometry geometry = model.getMeshGeometry();
-            this->_mesh.generate(geometry.vertices, geometry.indices);
-
-            auto & vertices = geometry.vertices;
-            auto & indices = geometry.indices;
-
-            for(size_t i = 0; i < geometry.indices.size(); i+= 3) {
-                PhysicsParticleGenerator generator;
-                glm::vec3 & p1 = vertices[indices[i]].position, p2 = vertices[indices[i+1]].position, p3 =  vertices[indices[i+2]].position;
-
-                glm::vec3 baricenter = (p1 + p2 + p3) / 3.f;
-                generator.setPosition(baricenter);
-
-                glm::vec3 normal = glm::triangleNormal(p1, p2, p3);
-                generator.setVelocity(glm::normalize(normal) / 50.f);
-
-                this->_generators.push_back(generator);
-            }
+            this->changeMesh("res/models/sphere.obj");
         }
 
         if(!this->_meshProgram.usable()) {
@@ -81,20 +63,19 @@ namespace pg::scene {
 			glBindBufferBase(GL_UNIFORM_BUFFER, uniforme_index, this->_ubo);
 			glBindBuffer(GL_UNIFORM_BUFFER, 0);
 		}
+
+        this->_particles.reserve(this->_interface.getMaxParticle());
     }
 
     void MeshGenerator::update(double current_time) {
         static auto start = std::chrono::high_resolution_clock::now();
         auto end = std::chrono::high_resolution_clock::now();
 
-        pg::Particle::purge(this->_particles, static_cast<size_t>(current_time), 2);
-        if(duration_cast<std::chrono::milliseconds>(end - start).count() >= 2500) {
+        pg::Particle::purge(this->_particles, static_cast<size_t>(current_time), this->_interface.getLifeTime());
+        if(duration_cast<std::chrono::milliseconds>(end - start).count() >= this->_interface.getSpawnFrequence()) {
             start = std::chrono::high_resolution_clock::now();
-            for(auto & generator : this->_generators) {
-                if((1 + this->_particles.size()) <= 1024) {
-                    std::vector<std::unique_ptr<pg::Particle>> newParticles = generator.generate(1, static_cast<size_t>(current_time));
-                    this->_particles.insert(this->_particles.begin(), std::make_move_iterator(newParticles.begin()), std::make_move_iterator(newParticles.end()));
-                }
+            if(this->_interface.isSpawnEnable()) {
+                this->spawn(this->_interface.getSpawnCount(), current_time);
             }
         }
 
@@ -127,31 +108,40 @@ namespace pg::scene {
 
         // --------
 
-        std::vector<glm::mat4> models;
-        for(auto & particle : this->_particles) {
-            glm::mat4 model = glm::mat4(1.0);
-            model = glm::translate(model, glm::vec3(particle->getPosition()));
-            models.push_back(model);
-        }
+        size_t particle_accumulator = 0;
+        while(particle_accumulator < this->_particles.size()) {
+            std::vector<glm::mat4> models;
+            for(size_t i = 0; i < this->_particles.size() && i < 1024; i++) {
+                glm::mat4 model = glm::mat4(1.0);
+                if(i + particle_accumulator < this->_particles.size()) {
+                    model = glm::translate(model, glm::vec3(this->_particles[particle_accumulator + i]->getPosition()));
+                    models.push_back(model);
+                }
+            }
 
-        glBindBuffer(GL_UNIFORM_BUFFER, this->_ubo);
-        glBufferSubData(GL_UNIFORM_BUFFER, 0, models.size() * sizeof(glm::mat4), models.data());
+            glBindBuffer(GL_UNIFORM_BUFFER, this->_ubo);
+            glBufferSubData(GL_UNIFORM_BUFFER, 0, models.size() * sizeof(glm::mat4), models.data());
 
-        pg::error::OpenGLError::check();
+            pg::error::OpenGLError::check();
 
-        this->_billboardTexture.bind(0);
-        this->_billboardProgram.use();
+            this->_billboardTexture.bind(0);
+            this->_billboardProgram.use();
 
-        this->_billboardProgram.setUniform("uView", VIEW_MATRIX);
-        this->_billboardProgram.setUniform("uProj", PROJECTION_MATRIX);   
-        this->_billboardProgram.setUniform("uSlot", 0);
-        this->_billboardProgram.setUniform("uColor", glm::vec4(1.f, 1.f, 1.f, 1.f));
+            this->_billboardProgram.setUniform("uView", VIEW_MATRIX);
+            this->_billboardProgram.setUniform("uProj", PROJECTION_MATRIX);   
+            this->_billboardProgram.setUniform("uSlot", 0);
+            this->_billboardProgram.setUniform("uColor", glm::vec4(1.f, 1.f, 1.f, 1.f));
 
-        pg::error::OpenGLError::check();
+            pg::error::OpenGLError::check();
 
-        this->_billboard.draw(this->_particles.size());
+            if(this->_interface.isRenderEnable()) {
+                this->_billboard.draw(this->_particles.size());
+            }
 
-        pg::error::OpenGLError::check();
+            pg::error::OpenGLError::check();
+
+            particle_accumulator += 1024;
+        }
 
         // --------
     }
@@ -161,4 +151,43 @@ namespace pg::scene {
         this->_billboard.destroy();
         this->_particles.clear();
     }
+
+    void MeshGenerator::changeMesh(const std::string & path) {
+        this->_particles.clear();
+        this->_generators.clear();
+		Model model(path);
+
+        MeshGeometry geometry = model.getMeshGeometry();
+        this->_mesh.generate(geometry.vertices, geometry.indices);
+
+        auto & vertices = geometry.vertices;
+        auto & indices = geometry.indices;
+
+        for(size_t i = 0; i < geometry.indices.size(); i+= 3) {
+            PhysicsParticleGenerator generator;
+            glm::vec3 & p1 = vertices[indices[i]].position, p2 = vertices[indices[i+1]].position, p3 =  vertices[indices[i+2]].position;
+
+            glm::vec3 baricenter = (p1 + p2 + p3) / 3.f;
+            generator.setPosition(baricenter);
+
+            glm::vec3 normal = glm::triangleNormal(p1, p2, p3);
+            generator.setVelocity(glm::normalize(normal) / 50.f);
+
+            generator.setPositionVariation(0.5f);
+            this->_generators.push_back(generator);
+        }
+	}
+
+    void MeshGenerator::spawn(size_t count, double current_time) {
+        for(auto & generator : this->_generators) {
+            if((count + this->_particles.size()) <= this->_interface.getMaxParticle()) {
+                std::vector<std::unique_ptr<pg::Particle>> newParticles = generator.generate(count, static_cast<size_t>(current_time));
+                this->_particles.insert(this->_particles.begin(), std::make_move_iterator(newParticles.begin()), std::make_move_iterator(newParticles.end()));
+            }
+        }
+    }
+
+	void MeshGenerator::changeTexture(const std::string & path) {
+		this->_billboardTexture.load(path);
+	}
 }
\ No newline at end of file
diff --git a/ParticleGenerator/src/Scene/Scenes/MeshGenerator.hpp b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.hpp
index dae803e..77e980c 100644
--- a/ParticleGenerator/src/Scene/Scenes/MeshGenerator.hpp
+++ b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.hpp
@@ -9,6 +9,7 @@
 #include "../../Mesh/Billboard.hpp"
 #include "../../Renderer/Renderer.hpp"
 #include "../../Particle/generator/PhysicsParticleGenerator.hpp"
+#include "../../Interface/Scene/MeshGeneratorInterface.hpp"
 
 namespace pg::scene {
     class MeshGenerator : public Scene {
@@ -25,6 +26,8 @@ namespace pg::scene {
             Program _billboardProgram;
             GLuint _ubo;
 
+            MeshGeneratorInterface _interface;
+
         public:
             MeshGenerator();
 
@@ -34,7 +37,14 @@ namespace pg::scene {
             virtual void destroy();
 
             virtual std::string name() const {return "Mesh Generator Scene";};
-            virtual Interface * interface() {return nullptr;};
+            virtual Interface * interface() {return &this->_interface;}
+
+            void changeMesh(const std::string &);
+			void changeTexture(const std::string &);
+
+            void spawn(size_t count, double current_time);
+
+            friend class pg::MeshGeneratorInterface;
 
     };
 }
\ No newline at end of file
-- 
GitLab