diff --git a/ParticleGenerator/CMakeLists.txt b/ParticleGenerator/CMakeLists.txt index 45a8953599b8ae2927ceb638ffa6dd824a8131ba..113b5a7fc604a8f23800a8777bce26e04e2916fb 100644 --- a/ParticleGenerator/CMakeLists.txt +++ b/ParticleGenerator/CMakeLists.txt @@ -85,4 +85,7 @@ find_package(assimp CONFIG REQUIRED) target_link_libraries(${CURRENT_TARGET} PRIVATE assimp::assimp) find_package(tinyfiledialogs CONFIG REQUIRED) -target_link_libraries(${CURRENT_TARGET} PRIVATE tinyfiledialogs::tinyfiledialogs) \ No newline at end of file +target_link_libraries(${CURRENT_TARGET} PRIVATE tinyfiledialogs::tinyfiledialogs) + +find_package(implot CONFIG REQUIRED) +target_link_libraries(${CURRENT_TARGET} PRIVATE implot::implot) \ No newline at end of file diff --git a/ParticleGenerator/res/config/imgui.ini b/ParticleGenerator/res/config/imgui.ini index 62657f2e7e6fe50d4eed339567fb17e0a5a0835c..c470b92e2f94199bc9bc548f02d398d333414d02 100644 --- a/ParticleGenerator/res/config/imgui.ini +++ b/ParticleGenerator/res/config/imgui.ini @@ -4,10 +4,5 @@ Size=400,400 [Window][Particle Generator] Pos=60,60 -Size=704,561 - -[Window][Dear ImGui Demo] -Pos=971,50 -Size=550,680 -Collapsed=1 +Size=848,714 diff --git a/ParticleGenerator/res/shaders/scene/Phong.frag b/ParticleGenerator/res/shaders/scene/Phong.frag index 6c061a83d3f8dbbf962b39fc3bccc43d2ece251e..1e211fc0717b01c1a819a679fe1b838840183097 100644 --- a/ParticleGenerator/res/shaders/scene/Phong.frag +++ b/ParticleGenerator/res/shaders/scene/Phong.frag @@ -7,24 +7,24 @@ in vec2 zTexture; uniform vec3 uLightPosition; uniform vec3 uViewPosition; -uniform vec3 uColor; +uniform vec4 uColor; uniform sampler2D uSlot; void main() { - float ambientStrength = 0.1; - vec3 ambient = ambientStrength * uColor; + float ambientStrength = 0.25; + vec4 ambient = ambientStrength * uColor; vec3 norm = normalize(zNormal); vec3 lightDir = normalize(uLightPosition - zFramPosition); - vec3 diffuse = max(dot(norm, lightDir), 0.0) * uColor; + vec4 diffuse = max(dot(norm, lightDir), 0.0) * uColor; - float specularStrength = 0.5; + float specularStrength = 0.85; vec3 viewDir = normalize(uViewPosition - zFramPosition); vec3 reflectDir = reflect(-lightDir, norm); - float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32); - vec3 specular = specularStrength * spec * uColor; + float spec = pow(max(dot(viewDir, reflectDir), 0.0), 128); + vec4 specular = specularStrength * spec * uColor; - vec3 result = (ambient + diffuse + specular); - FragColor = vec4(result, 1.0) * texture(uSlot, zTexture); + vec4 result = (ambient + diffuse + specular); + FragColor = result * texture(uSlot, zTexture); } \ No newline at end of file diff --git a/ParticleGenerator/res/textures/cyan.png b/ParticleGenerator/res/textures/cyan.png new file mode 100644 index 0000000000000000000000000000000000000000..0f46c637688731d869da425c83b05427e4c3ba03 Binary files /dev/null and b/ParticleGenerator/res/textures/cyan.png differ diff --git a/ParticleGenerator/res/textures/orange.png b/ParticleGenerator/res/textures/orange.png new file mode 100644 index 0000000000000000000000000000000000000000..bd98687855092b175218e174552833bf94602840 Binary files /dev/null and b/ParticleGenerator/res/textures/orange.png differ diff --git a/ParticleGenerator/res/textures/red.png b/ParticleGenerator/res/textures/red.png new file mode 100644 index 0000000000000000000000000000000000000000..a1253124f46fc7e0dbee29acab4545c2a5be47e6 Binary files /dev/null and b/ParticleGenerator/res/textures/red.png differ diff --git a/ParticleGenerator/src/Interface/Generator/PathGenerator.cpp b/ParticleGenerator/src/Interface/Generator/PathGenerator.cpp index 887f7a097a5247927e268f1010374d4cd87c8cf0..5cfe9135db426c0df3d6cce627c53948a93f4bfc 100644 --- a/ParticleGenerator/src/Interface/Generator/PathGenerator.cpp +++ b/ParticleGenerator/src/Interface/Generator/PathGenerator.cpp @@ -28,7 +28,7 @@ namespace pg::interface { if(ImGui::CollapsingHeader("Parameter")) { ImGui::InputFloat("Parameter Default Value", &this->parent()->m_u, 0.1f, 0.5f); - ImGui::DragFloat("Parameter Increment Value", &this->parent()->m_increment, 0.01f); + ImGui::DragFloat("Parameter Increment Value", &this->parent()->m_increment, 0.01f, 0.0f, 0.0f, "%.5f"); ImGui::DragFloat("Spacing", &this->parent()->m_spacing, 0.001f); ImGui::InputFloat("Life Limitor", &this->parent()->m_limitor, 1.0f, 2.0f); } diff --git a/ParticleGenerator/src/Interface/Manager.cpp b/ParticleGenerator/src/Interface/Manager.cpp index bdb1403fef97fcf9e45ff363b773049b301b414e..eeb4eee4c6e6d3dd78f4440081a79abc9c083bea 100644 --- a/ParticleGenerator/src/Interface/Manager.cpp +++ b/ParticleGenerator/src/Interface/Manager.cpp @@ -6,11 +6,13 @@ #include <imgui.h> #include <imgui_impl_glfw.h> #include <imgui_impl_opengl3.h> +#include <implot.h> namespace pg::interface { Manager::Manager(const Window & window, pg::Manager & manager) : _window(window), _manager(manager), _title(window.title()) { ImGui::CreateContext(); + ImPlot::CreateContext(); ImGui::GetIO().IniFilename = "config/imgui.ini"; ImGui_ImplGlfw_InitForOpenGL(window.address(), true); @@ -26,6 +28,7 @@ namespace pg::interface { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); + ImPlot::DestroyContext(); ImGui::DestroyContext(); } @@ -34,8 +37,6 @@ namespace pg::interface { ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); - ImGui::ShowDemoWindow(); - this->_historical.count(current_time); if(ImGui::Begin(this->_title.c_str())) { diff --git a/ParticleGenerator/src/Interface/Scene/PathAnimated.cpp b/ParticleGenerator/src/Interface/Scene/PathAnimated.cpp new file mode 100644 index 0000000000000000000000000000000000000000..67964d3b00e3ccc45b1102228c1fe85993887832 --- /dev/null +++ b/ParticleGenerator/src/Interface/Scene/PathAnimated.cpp @@ -0,0 +1,97 @@ +#include "PathAnimated.hpp" + +#include <imgui.h> +#include <implot.h> + +#include "../../Scene/Scenes/Path.hpp" +#include "../../tfd/tinyfiledialogs.h" + +#include "../../Scene/Scenes/PathAnimated.hpp" + +namespace pg::interface { + PathAnimated::PathAnimated(scene::PathAnimated * parent, particle::PathGenerator * generator, scene::Trajectory * trajectory) + : Scene(parent), SceneParticle(parent), _interface(generator, trajectory), _next(1.f), _index(0) { + this->_animeCurvePreset = {{0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}, {3.0, -1.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.5, 0.0}}; + } + + void PathAnimated::draw(double current_time) { + SceneParticle::draw(current_time); + + ImGui::SeparatorText("Mesh"); + + ImGui::Image((void*)(intptr_t)this->parent()->getTexture().identifier(), ImVec2(128, 128), ImVec2(0, 1), ImVec2(1, 0)); + if(ImGui::Button("Change Texture", ImVec2(128, 25))) { + char const * imagePatterns[1] = {"*.png"}; + std::string path = tinyfd_openFileDialog("Image Browser", "", 1, imagePatterns, "Image File", false); + this->parent()->changeTexture(path); + } + + ImGui::SameLine(); + if(ImGui::Button("Change Model", ImVec2(128, 25))) { + char const * imagePatterns[1] = {"*.obj"}; + std::string path = tinyfd_openFileDialog("Model Browser", "", 1, imagePatterns, "Model File", false); + this->parent()->changeMesh(path); + } + + ImGui::SameLine(); + ImGui::ColorEdit4("Color", &this->parent()->_color[0]); + + ImGui::SeparatorText("Generator"); + + this->_interface.draw(current_time); + + ImGui::SeparatorText("Trajectory"); + + auto tinterface = this->parent()->_trajectory.interface(); + if(tinterface.has_value()) { + (*tinterface)->draw(current_time); + } + + ImGui::SeparatorText("Animation Curve"); + + ImGui::PushID(1); + if(ImGui::CollapsingHeader("Control Points")) { + for(size_t i = 0; i < this->_animeCurvePreset.size(); ++i) { + glm::vec3 current = static_cast<glm::vec3>(this->_animeCurvePreset[i]); + ImGui::Text("%i : %f / %f / %f.", i, current.x, current.y, current.z); + } + + ImGui::InputFloat3("", &this->_next[0]); + ImGui::InputInt("Index", &this->_index, 1, 2); + + if(this->_index < 0) { + ImGui::TextColored(ImVec4(0.75f, 0.f, 0.f, 1.f), "Negative index !"); + } + else { + if(this->_index > this->_animeCurvePreset.size()) { + ImGui::TextColored(ImVec4(1.f, 1.f, 0.f, 1.f), "Index out of range, new point will be at the back !"); + } + + if(ImGui::Button("Push Point")) { + if(this->_index > this->_animeCurvePreset.size()) { + this->_animeCurvePreset.push_back(static_cast<ct::Point>(this->_next)); + } + else { + this->_animeCurvePreset.insert(this->_animeCurvePreset.begin() + this->_index, static_cast<ct::Point>(this->_next)); + } + + this->parent()->changeAnimeCurve(this->_animeCurvePreset, 0.01, 1.f); + } + + ImGui::SameLine(); + + if(ImGui::Button("Pop Point")) { + if(this->_index > this->_animeCurvePreset.size()) { + this->_animeCurvePreset.pop_back(); + } + else { + this->_animeCurvePreset.erase(this->_animeCurvePreset.begin() + this->_index); + } + + this->parent()->changeAnimeCurve(this->_animeCurvePreset, 0.01, 1.f); + } + } + } + ImGui::PopID(); + } +} \ No newline at end of file diff --git a/ParticleGenerator/src/Interface/Scene/PathAnimated.hpp b/ParticleGenerator/src/Interface/Scene/PathAnimated.hpp new file mode 100644 index 0000000000000000000000000000000000000000..799c8aac309e24f66311ce1797d93a64e03aec60 --- /dev/null +++ b/ParticleGenerator/src/Interface/Scene/PathAnimated.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "../Interface.hpp" +#include "SceneParticle.hpp" +#include "../Generator/PathGenerator.hpp" +#include "../../Scene/Scenes/Trajectory.hpp" + +#include <glm/vec4.hpp> + + +namespace pg::scene { + class PathAnimated; +} + +namespace pg::interface { + class PathAnimated : public Scene<scene::PathAnimated>, public SceneParticle { + private: + PathGenerator _interface; + ct::Curve _animeCurvePreset; + glm::vec3 _next; + int _index; + + public: + PathAnimated(scene::PathAnimated *, particle::PathGenerator *, pg::scene::Trajectory * = nullptr); + virtual ~PathAnimated() = default; + + virtual void draw(double); + inline std::string title() const override final {return "Path 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 649122b7d5af7f4ca743dea6d1c2edf47de23a82..4f8228b67c53d65f4d7b17f53c25f92ba2e8b17e 100644 --- a/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp +++ b/ParticleGenerator/src/Scene/Scenes/MeshGenerator.cpp @@ -198,7 +198,6 @@ namespace pg::scene { std::vector<std::unique_ptr<particle::Physics>> 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())); } - } } diff --git a/ParticleGenerator/src/Scene/Scenes/PathAnimated.cpp b/ParticleGenerator/src/Scene/Scenes/PathAnimated.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a4d599684bfe2226a366bdd9fb36d45024ad76b --- /dev/null +++ b/ParticleGenerator/src/Scene/Scenes/PathAnimated.cpp @@ -0,0 +1,179 @@ +#include "PathAnimated.hpp" + +#include "../../Mesh/Model.hpp" + +#include <chrono> +#include <glm/gtc/matrix_transform.hpp> + +namespace pg::scene { + PathAnimated::PathAnimated(ct::CurveGenerator * generator) + : SceneParticle(1024), + _ubo(0), + _program(), + _texture(), + _generator(generator, {{-10.0, 15.0, -5.0}, {2.5, 20.0, -2.5}, {1.0, -10.0, 0.0}, {-1.0, -10.0, 0.0}, {-2.5, 15.0, 2.5}, {5.0, 10.0, 5.0}}), + _trajectory(&this->_generator, 0.01), + _color(1.f), + _interface(this, &this->_generator, &this->_trajectory) { + + } + + void PathAnimated::initialize() { + if(!this->_mesh.isGenerated()) { + this->changeMesh("res/models/sphere.obj"); + } + + this->_trajectory.initialize(); + if(!this->_program.usable()) { + pg::Source vertices("res/shaders/scene/Phong-Fat.vert", pg::Source::Categorie::VERTEX); + pg::Source fragment("res/shaders/scene/Phong.frag", pg::Source::Categorie::FRAGMENT); + + this->_program << vertices; + this->_program << fragment; + + this->_program.link(); + + vertices.release(); + fragment.release(); + } + + //this->changeAnimeCurve({{0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}, {0.25, -1.0, 0.0}, {0.0, 1.5, 0.0}, {1.0, 1.5, 0.0}}, 0.01); + this->changeAnimeCurve({{0.0, 1.0, 0.0}, {2.0, 1.0, 0.0}, {3.0, -1.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 1.5, 0.0}}, 0.01); + + pg::error::OpenGLError::check(); + + glCreateBuffers(1, &this->_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, this->_ubo); + glBufferData(GL_UNIFORM_BUFFER, 1024 * sizeof(glm::mat4), nullptr, GL_DYNAMIC_DRAW); + + GLuint uniforme_index = glGetUniformBlockIndex(this->_program.id(), "uModels_t"); + glBindBufferBase(GL_UNIFORM_BUFFER, uniforme_index, this->_ubo); + + pg::error::OpenGLError::check(); + + this->_texture.load("res/textures/cyan.png"); + + pg::error::OpenGLError::check(); + + this->_generator.setPosition({0.f, 0.f, 0.f}); + this->_generator.setPositionVariation(0.5f); + this->_generator.setParameterIncrement(0.005f); + this->_generator.setParameterLifeLimitor(1.0f); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClearColor(0.25f, 0.f, 0.15f, 1.0f); + } + + void PathAnimated::update(double current_time) { + static auto start = std::chrono::high_resolution_clock::now(); + auto end = std::chrono::high_resolution_clock::now(); + + if(!this->isFreezeEnable()) { + pg::particle::Particle::purge(this->_particles, static_cast<size_t>(current_time), this->getLifetime()); + if(duration_cast<std::chrono::milliseconds>(end - start).count() >= 500) { + start = std::chrono::high_resolution_clock::now(); + if(this->isSpawnEnable()) { + this->spawn(this->getSpawnCount(), current_time); + } + } + + if(duration_cast<std::chrono::milliseconds>(end - start).count() >= 10) { + for(auto& particle : this->_particles) { + particle->update(0.0); + } + } + } + } + + void PathAnimated::render(const Camera & camera, double current_time) { + glEnable(GL_DEPTH_TEST); + const glm::mat4 VIEW_MATRIX = camera.getViewMatrix(); + const glm::mat4 PROJECTION_MATRIX = camera.getViewFrustum().getProjectionMatrix(); + + this->_trajectory.render(camera, current_time); + + std::vector<glm::mat4> models; + + for(size_t i = 0; i < this->_particles.size(); i++) { + particle::Path * particle = dynamic_cast<particle::Path *>(this->_particles.at(i).get()); + glm::mat4 model = particle->getModel(); + + double p = particle->getParameterValue(); + size_t animePos = static_cast<size_t>(std::lerp(0.0, this->_animate_Y.size()-1, p)); + + if(animePos >= this->_animate_Y.size()) { + animePos = this->_animate_Y.size()-1; + } + + float scale_y = static_cast<float>(this->_animate_Y.at(animePos).y); + + model = glm::scale(model, {1.f, scale_y, 1.f}); + models.push_back(model); + } + + pg::error::OpenGLError::check(); + + glBindBuffer(GL_UNIFORM_BUFFER, this->_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, models.size() * sizeof(glm::mat4), models.data()); + + pg::error::OpenGLError::check(); + + this->_program.use(); + + this->_program.setUniform("uView", VIEW_MATRIX); + this->_program.setUniform("uProj", PROJECTION_MATRIX); + this->_program.setUniform("uSlot", 0); + this->_program.setUniform("uColor", this->_color); + this->_program.setUniform("uViewPos", camera.getPosition()); + this->_program.setUniform("uLightPosition", glm::vec3(0.f, 10.f, 0.f)); + + pg::error::OpenGLError::check(); + + this->_texture.bind(); + if(this->isRenderEnable()) { + this->_mesh.draw(this->_particles.size()); + } + + pg::error::OpenGLError::check(); + glDisable(GL_DEPTH_TEST); + } + + void PathAnimated::destroy() { + glDeleteBuffers(1, &this->_ubo); + this->_particles.clear(); + + pg::error::OpenGLError::check(); + } + + void PathAnimated::changeParticletexture(const std::string & path) { + this->_texture.load(path); + } + + void PathAnimated::spawn(int count, double current_time) { + this->_generator.setModel(glm::mat4(1.f)); + this->_generator.rotate(this->_generator.getRotation()); + this->_generator.translate(this->_generator.getPosition()); + + if((count + this->_particles.size()) <= this->getMaxParticles()) { + std::vector<std::unique_ptr<pg::particle::Path>> newParticles = this->_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 PathAnimated::changeMesh(const std::string & path) { + Model model(path); + MeshGeometry geometry = model.getMeshGeometry(); + this->_mesh.generate(geometry.vertices, geometry.indices); + } + + void PathAnimated::changeTexture(const std::string & path) { + this->_texture.load(path); + } + + void PathAnimated::changeAnimeCurve(const ct::Curve & curve, double precision, double max) { + for(double i = 0; i < max; i+= precision) { + this->_animate_Y.push_back(this->_generator.getGenerator()->generate(curve, i)); + } + } +} \ No newline at end of file diff --git a/ParticleGenerator/src/Scene/Scenes/PathAnimated.hpp b/ParticleGenerator/src/Scene/Scenes/PathAnimated.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cbbb82ab4192f60926d084c55db8c762f38d3248 --- /dev/null +++ b/ParticleGenerator/src/Scene/Scenes/PathAnimated.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "../Scene.hpp" +#include "Trajectory.hpp" + +#include "../../Renderer/Renderer.hpp" +#include "../../Particle/generator/PathUniqueGenerator.hpp" +#include "../../Interface/Scene/Path.hpp" +#include "../../Mesh/Mesh.hpp" +#include "../../System/Window.hpp" +#include "../../Interface/Scene/PathAnimated.hpp" + +namespace pg::interface { + class PathAnimated; +} + +namespace pg::scene { + class PathAnimated : public SceneParticle { + private: + GLuint _ubo; + + Program _program; + Mesh _mesh; + Trajectory _trajectory; + Material _texture; + particle::PathUniqueGenerator _generator; + glm::vec4 _color; + ct::Curve _animate_Y; + interface::PathAnimated _interface; + + public: + PathAnimated(ct::CurveGenerator *); + virtual ~PathAnimated() = default; + + virtual void initialize(); + virtual void render(const Camera &, double); + virtual void update(double); + virtual void destroy(); + + inline const Program & getProgram() const {return this->_program;} + inline const Material & getTexture() const {return this->_texture;} + inline const particle::PathUniqueGenerator & getGenerator() const {return this->_generator;} + + void changeParticletexture(const std::string &); + + virtual std::string name() const {return "Path Animated Scene";} + virtual std::optional<interface::Interface *> interface() {return std::optional<interface::Interface *>(&this->_interface);} + + virtual void spawn(int, double); + void changeMesh(const std::string &); + void changeTexture(const std::string &); + void changeAnimeCurve(const ct::Curve &, double, double = 1.0); + + friend class pg::interface::PathAnimated; + }; +} \ No newline at end of file diff --git a/ParticleGenerator/src/main.cpp b/ParticleGenerator/src/main.cpp index 73ca2cb174541f8a4fb23fedc3b50aa523409a40..55817466b87f13462e940da70efe20a10bb78dec 100644 --- a/ParticleGenerator/src/main.cpp +++ b/ParticleGenerator/src/main.cpp @@ -15,6 +15,7 @@ #include "Scene/Scenes/MultyPath.hpp" #include "Scene/Scenes/MeshGeneratorModel.hpp" #include "Scene/Scenes/PathPregenerated.hpp" +#include "Scene/Scenes/PathAnimated.hpp" #include "Interface/Manager.hpp" @@ -86,6 +87,7 @@ int main(int argc, const char * argv[]) { pg::scene::MultyPath multyPath(ctrlPoints); pg::scene::MeshGeneratorModel meshGeneratorModel; pg::scene::PathPregenerated pathPregenerated(&bezier, ctrlPoints); + pg::scene::PathAnimated pathAnimated(&bezier); pg::Manager manager(window); pg::interface::Manager imanager(window, manager); @@ -97,6 +99,7 @@ int main(int argc, const char * argv[]) { manager.add(&multyPath); manager.add(&meshGeneratorModel); manager.add(&pathPregenerated); + manager.add(&pathAnimated); while(window.isOpen()) { double current_time = glfwGetTime();