From bc6626336dae27c9a5ab02605bb24ce841bea6e3 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sat, 31 Aug 2024 18:29:21 +0200 Subject: [PATCH 01/31] =?UTF-8?q?=F0=9F=8E=89=20[FeedbackLoop]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cool | 2 +- src/App.cpp | 33 ++--- src/App.h | 2 +- src/Module/Module.h | 36 +++-- src/Module_Compositing/Module_Compositing.cpp | 28 +--- src/Module_Compositing/Module_Compositing.h | 8 +- .../Module_FeedbackLoop.cpp | 23 ++++ .../Module_FeedbackLoop.hpp | 40 ++++++ src/Module_Particles/Module_Particles.cpp | 54 ++++---- src/Module_Particles/Module_Particles.h | 13 +- src/ModulesGraph/ModulesGraph.cpp | 129 ++++++++++-------- src/ModulesGraph/ModulesGraph.h | 21 +-- 12 files changed, 232 insertions(+), 157 deletions(-) create mode 100644 src/Module_FeedbackLoop/Module_FeedbackLoop.cpp create mode 100644 src/Module_FeedbackLoop/Module_FeedbackLoop.hpp diff --git a/Cool b/Cool index 4b7fe0d6..cf936cbf 160000 --- a/Cool +++ b/Cool @@ -1 +1 @@ -Subproject commit 4b7fe0d6e3df9c70ed00f7cd660f8db2091c2e5d +Subproject commit cf936cbf64cf3fea4f1690e34c0938f39ba92e2c diff --git a/src/App.cpp b/src/App.cpp index 7693d10f..854416f0 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -149,8 +149,8 @@ void App::update() if (!_project.exporter.is_exporting()) { _project.clock.update(); - render_view().update_size(_project.view_constraint); // TODO(JF) Integrate the notion of View Constraint inside the RenderView ? But that's maybe too much coupling - polaroid().render(_project.clock.time(), _project.clock.delta_time()); + auto const render_size = render_view().desired_image_size(_project.view_constraint); // TODO(JF) Integrate the notion of View Constraint inside the RenderView ? But that's maybe too much coupling + polaroid().render(render_size, _project.clock.time(), _project.clock.delta_time()); } else { @@ -206,14 +206,9 @@ auto App::render_view() -> Cool::RenderView& Cool::Polaroid App::polaroid() { return { - .render_target = render_view().render_target(), // TODO(Modules) Each module should have its own render target that it renders on. The views shouldn't have a render target, but receive the one of the top-most module by reference. - .render_fn = [this](Cool::RenderTarget& render_target, Cool::Time time, Cool::Time delta_time) { - if (_last_time != time) - { - _last_time = time; - on_time_changed(); - } - render(render_target, time, delta_time); + .texture = _project.modules_graph->final_texture(), + .render = [this](img::Size size, Cool::Time time, Cool::Time delta_time) { + render(size, time, delta_time); } }; } @@ -236,11 +231,15 @@ static void imgui_window_console() #endif } -void App::render(Cool::RenderTarget& render_target, Cool::Time time, Cool::Time delta_time) +void App::render(img::Size size, Cool::Time time, Cool::Time delta_time) { + if (_last_time != time) + { + _last_time = time; + on_time_changed(); + } _project.modules_graph->render( - render_target, - data_to_pass_to_shader(render_target.desired_size(), time, delta_time), + data_to_pass_to_shader(size, time, delta_time), data_to_generate_shader_code() ); } @@ -280,10 +279,12 @@ void App::imgui_window_view() } _project.modules_graph->submit_gizmos(_preview_view.gizmos_manager(), command_executor(), _project.camera_2D_manager.camera()); + _output_view.set_texture(_project.modules_graph->final_texture()); _output_view.imgui_window({ .on_open = [&]() { request_rerender(); }, // When we switch between using the _output_view and the _nodes_view .on_close = [&]() { request_rerender(); }, // as our render target, we need to rerender. }); + _preview_view.set_texture(_project.modules_graph->final_texture()); _preview_view.imgui_window({ .fullscreen = view_in_fullscreen, .extra_widgets = [&]() { @@ -354,7 +355,7 @@ void App::imgui_window_meshing() { _meshing_gui.imgui_window( _mesh_export_settings, - data_to_pass_to_shader(render_view().render_target().current_size(), _project.clock.time(), _project.clock.delta_time()), + data_to_pass_to_shader(render_view().desired_image_size(_project.view_constraint), _project.clock.time(), _project.clock.delta_time()), data_to_generate_shader_code() ); } @@ -405,8 +406,8 @@ void App::imgui_windows_only_when_inputs_are_allowed() // Share online _gallery_poster.imgui_window([&](img::Size size) { auto the_polaroid = polaroid(); - the_polaroid.render(_project.clock.time(), _project.clock.delta_time(), size); - auto const image = the_polaroid.render_target.download_pixels(); + the_polaroid.render(size, _project.clock.time(), _project.clock.delta_time()); + auto const image = the_polaroid.texture.download_pixels(); return img::save_png_to_string(image); }); // Recently opened projects diff --git a/src/App.h b/src/App.h index b83fedd9..aad67c69 100644 --- a/src/App.h +++ b/src/App.h @@ -78,7 +78,7 @@ class App : public Cool::IApp { auto nodes_library() const -> Cool::NodesLibrary const& { return _nodes_library_manager.library(); } private: - void render(Cool::RenderTarget& render_target, Cool::Time time, Cool::Time delta_time); + void render(img::Size size, Cool::Time time, Cool::Time delta_time); void on_time_changed(); void on_time_reset(); auto render_view() -> Cool::RenderView&; diff --git a/src/Module/Module.h b/src/Module/Module.h index fb14ed22..6930ca8d 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -1,6 +1,8 @@ #pragma once #include #include +#include "Cool/Gpu/OpenGL/TextureRef.hpp" +#include "Cool/Gpu/RenderTarget.h" #include "Dependencies/Ui.h" #include "ShaderBased/DataToPassToShader.hpp" @@ -13,21 +15,19 @@ namespace Lab { class Module { public: - Module() = default; - Module(Module const&) = delete; - auto operator=(Module const&) -> Module& = delete; - -protected: + Module() = default; // TODO(FeedbackLoop) remove? + Module(Module const&) = delete; + auto operator=(Module const&) -> Module& = delete; Module(Module&&) noexcept = default; auto operator=(Module&&) noexcept -> Module& = default; - -public: - virtual ~Module() = default; + virtual ~Module() = default; explicit Module(std::string_view name) : _name{name} - { - } + {} + + Cool::NodesGraph const* _nodes_graph{}; // TODO(Particles) Remove + Cool::DoubleBufferedRenderTarget const* _feedback_double_buffer{}; // TODO(Particles) Remove [[nodiscard]] auto name() const -> const std::string& { return _name; } @@ -36,8 +36,11 @@ class Module { render(data); _needs_to_rerender_flag.set_clean(); } - virtual void imgui_windows(Ui_Ref) const = 0; /// The ui() method should be const, because it should only trigger commands, not modify internal values (allows us to handle history / re-rendering at a higher level). If you really need to mutate one of your member variables, mark it as `mutable`. + virtual void imgui_windows(Ui_Ref) const {}; /// The ui() method should be const, because it should only trigger commands, not modify internal values (allows us to handle history / re-rendering at a higher level). If you really need to mutate one of your member variables, mark it as `mutable`. virtual void update() {}; + virtual void on_time_changed() {}; + virtual void on_time_reset() {}; + virtual void update_dependencies_from_nodes_graph(Cool::NodesGraph const&) {}; [[nodiscard]] virtual auto needs_to_rerender() const -> bool { @@ -46,15 +49,20 @@ class Module { [[nodiscard]] auto needs_to_rerender_flag() const -> Cool::DirtyFlag const& { return _needs_to_rerender_flag; } -protected: void log_module_error(Cool::OptionalErrorMessage const&, Cool::MessageSender&) const; + virtual auto texture() const -> Cool::TextureRef { return _render_target.texture_ref(); } + +protected: + virtual auto render_target() -> Cool::RenderTarget& { return _render_target; } + private: virtual void render(DataToPassToShader const&) = 0; private: - std::string _name; - Cool::DirtyFlag _needs_to_rerender_flag; + std::string _name; + Cool::DirtyFlag _needs_to_rerender_flag; + Cool::RenderTarget _render_target{}; private: friend class ser20::access; diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index 2e531a27..f2ba15f6 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -46,10 +46,6 @@ void Module_Compositing::log_shader_error(Cool::OptionalErrorMessage const& mayb log_module_error(maybe_err, _shader_error_sender); } -void Module_Compositing::imgui_windows(Ui_Ref) const -{ -} - void Module_Compositing::imgui_show_generated_shader_code() { if (Cool::ImGuiExtras::input_text_multiline("##Compositing shader code", &_shader_code, ImVec2{-1.f, -1.f})) @@ -65,26 +61,16 @@ void Module_Compositing::set_render_target_size(img::Size const& size) } void Module_Compositing::render(DataToPassToShader const& data) -{ - // TODO(Performance) Render only once and then copy to the _feedback_double_buffer ? - // TODO(Performance) Only render on the _feedback_double_buffer when someone depends on it - // Render on the normal render target - render_impl(data); - - // Render on the feedback texture - _feedback_double_buffer.write_target().render([&]() { - render_impl(data); - }); - _feedback_double_buffer.swap_buffers(); -} - -void Module_Compositing::render_impl(DataToPassToShader const& data) { if (!_pipeline.shader()) return; - - set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data); - _pipeline.draw(); + render_target().set_size(data.system_values.render_target_size); + render_target().render([&]() { + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data); + _pipeline.draw(); + }); } } // namespace Lab diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index 9f38431a..d2ccfc2a 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -17,17 +17,16 @@ class Module_Compositing : public Module { // auto operator=(Module_Compositing&&) noexcept -> Module_Compositing& = default; // TODO(Modules) void update() override; - void imgui_windows(Ui_Ref) const override; void imgui_show_generated_shader_code(); void reset_shader(); - void on_time_reset(); + void on_time_reset() override; void set_render_target_size(img::Size const& size); void set_shader_code(tl::expected const& shader_code); [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } + void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } auto shader_is_valid() const -> bool { return _pipeline.shader().has_value(); } // TODO(Modules) Remove auto shader() -> auto const& { return *_pipeline.shader(); } // TODO(Modules) Remove @@ -35,14 +34,13 @@ class Module_Compositing : public Module { private: void render(DataToPassToShader const&) override; - void render_impl(DataToPassToShader const&); void log_shader_error(Cool::OptionalErrorMessage const&) const; private: mutable std::string _shader_code{}; mutable Cool::FullscreenPipeline _pipeline{}; mutable Cool::MessageSender _shader_error_sender{}; - Cool::DoubleBufferedRenderTarget _feedback_double_buffer{}; + Cool::DoubleBufferedRenderTarget _feedback_double_buffer{}; // TODO(FeedbackLoop) Remvoe mutable ModuleDependencies _depends_on{}; private: diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp new file mode 100644 index 00000000..ab9ce5c6 --- /dev/null +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -0,0 +1,23 @@ +#include "Module_FeedbackLoop.hpp" + +namespace Lab { + +Module_FeedbackLoop::Module_FeedbackLoop() + : Module{"Feedback Loop"} +{ +} + +// TODO(FeedbackLoop) each time the module before you renders, you need to request a rerender for the next frame + +void Module_FeedbackLoop::on_time_reset() +{ + // TODO(FeedbackLoop) Reset the textures +} + +void Module_FeedbackLoop::render(DataToPassToShader const& data) +{ + // store the texture from the predecessor module + // return the texture of the previous frame +} + +} // namespace Lab diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp new file mode 100644 index 00000000..20fde8d6 --- /dev/null +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -0,0 +1,40 @@ +#pragma once +#include "Module/Module.h" +#include "Module/ModuleDependencies.h" +#include "Module_Compositing/Module_Compositing.h" + +namespace Lab { +class Module_FeedbackLoop : public Module { +public: + Module_FeedbackLoop(); + Module_FeedbackLoop(Module_FeedbackLoop const&) = delete; + auto operator=(Module_FeedbackLoop const&) -> Module_FeedbackLoop& = delete; + Module_FeedbackLoop(Module_FeedbackLoop&&) noexcept = default; + auto operator=(Module_FeedbackLoop&&) noexcept -> Module_FeedbackLoop& = default; + ~Module_FeedbackLoop() override = default; + + void on_time_reset() override; + + [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } + void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } + +private: + void render(DataToPassToShader const&) override; + +private: + // Module_Compositing _compositing_module{}; + ModuleDependencies _depends_on{}; + +private: + // Serialization + friend class ser20::access; + template + void serialize(Archive& archive) + { + archive( + ser20::make_nvp("Base Module", ser20::base_class(this)) + ); + } +}; + +} // namespace Lab diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index 03dafd10..2a2fb798 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -111,6 +111,11 @@ void Module_Particles::update() update_particles_count_ifn(); } +void Module_Particles::on_time_changed() +{ + request_particles_to_update(); +} + void Module_Particles::update_particles(DataToPassToShader const& data) { if (!_particle_system) @@ -131,10 +136,6 @@ void Module_Particles::update_particles(DataToPassToShader const& data) #endif } -void Module_Particles::imgui_windows(Ui_Ref) const -{ -} - void Module_Particles::imgui_show_generated_shader_code() { if (Cool::ImGuiExtras::input_text_multiline("##Particles simulation", &_shader_code, ImVec2{-1.f, -1.f})) @@ -150,26 +151,31 @@ void Module_Particles::render(DataToPassToShader const& data) update_particles(data); #if !defined(COOL_PARTICLES_DISABLED_REASON) - set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data); - - auto const view_proj_matrix_2D_mat3 = data.system_values.camera_2D_view_projection_matrix(); - auto const view_proj_matrix_2D_mat4 = glm::mat4{ - glm::vec4{view_proj_matrix_2D_mat3[0], 0.f}, - glm::vec4{view_proj_matrix_2D_mat3[1], 0.f}, - glm::vec4{0.f}, - glm::vec4{view_proj_matrix_2D_mat3[2][0], view_proj_matrix_2D_mat3[2][1], 0.f, view_proj_matrix_2D_mat3[2][2]} - }; - - if (_particle_system->dimension() == 2) - { - _particle_system->render_shader().set_uniform("view_proj_matrix", view_proj_matrix_2D_mat4); - } - else if (_particle_system->dimension() == 3) - { - _particle_system->render_shader().set_uniform("view_proj_matrix", view_proj_matrix_2D_mat4 * data.system_values.camera_3D.view_projection_matrix(1.f /* The aspect ratio is already taken into account in the camera 2D matrix */)); - _particle_system->render_shader().set_uniform("cool_camera_view", data.system_values.camera_3D.view_matrix()); - } - _particle_system->render(); + render_target().set_size(data.system_values.render_target_size); + render_target().render([&]() { + glClearColor(0.f, 0.f, 0.f, 0.f); + glClear(GL_COLOR_BUFFER_BIT); + set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data); + + auto const view_proj_matrix_2D_mat3 = data.system_values.camera_2D_view_projection_matrix(); + auto const view_proj_matrix_2D_mat4 = glm::mat4{ + glm::vec4{view_proj_matrix_2D_mat3[0], 0.f}, + glm::vec4{view_proj_matrix_2D_mat3[1], 0.f}, + glm::vec4{0.f}, + glm::vec4{view_proj_matrix_2D_mat3[2][0], view_proj_matrix_2D_mat3[2][1], 0.f, view_proj_matrix_2D_mat3[2][2]} + }; + + if (_particle_system->dimension() == 2) + { + _particle_system->render_shader().set_uniform("view_proj_matrix", view_proj_matrix_2D_mat4); + } + else if (_particle_system->dimension() == 3) + { + _particle_system->render_shader().set_uniform("view_proj_matrix", view_proj_matrix_2D_mat4 * data.system_values.camera_3D.view_projection_matrix(1.f /* The aspect ratio is already taken into account in the camera 2D matrix */)); + _particle_system->render_shader().set_uniform("cool_camera_view", data.system_values.camera_3D.view_matrix()); + } + _particle_system->render(); + }); #endif } diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index 261fb00a..8d87b3d2 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -10,7 +10,7 @@ namespace Lab { class Module_Particles : public Module { public: - Module_Particles() = default; + Module_Particles() = default; // TODO(FeedbackLoop) remove? explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count); Module_Particles(Module_Particles const&) = delete; auto operator=(Module_Particles const&) -> Module_Particles& = delete; @@ -18,12 +18,8 @@ class Module_Particles : public Module { auto operator=(Module_Particles&&) noexcept -> Module_Particles& = default; ~Module_Particles() override = default; - Cool::NodesGraph const* _nodes_graph{}; // TODO(Particles) Remove - Cool::DoubleBufferedRenderTarget const* _feedback_double_buffer{}; // TODO(Particles) Remove - void update() override; - void request_particles_to_update() { _needs_to_update_particles = true; } - void imgui_windows(Ui_Ref) const override; + void on_time_changed() override; void imgui_show_generated_shader_code(); [[nodiscard]] auto needs_to_rerender() const -> bool override @@ -32,10 +28,10 @@ class Module_Particles : public Module { }; void set_simulation_shader_code(tl::expected const& shader_code, bool for_testing_nodes, int dimension); - void on_time_reset(); + void on_time_reset() override; [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } + void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: void render(DataToPassToShader const&) override; @@ -45,6 +41,7 @@ class Module_Particles : public Module { auto desired_particles_count() const -> size_t; void log_simulation_shader_error(Cool::OptionalErrorMessage const&) const; void request_particles_to_reset(); + void request_particles_to_update() { _needs_to_update_particles = true; } private: mutable std::optional _particle_system{}; diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 94b7cffd..9cdaa91b 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -21,20 +21,22 @@ void ModulesGraph::update() _compositing_module.update(); for (auto& module_node : _particles_module_nodes) { - module_node->module._nodes_graph = &_nodes_editor.graph(); - module_node->module.update(); + module_node->module->_nodes_graph = &_nodes_editor.graph(); + module_node->module->update(); } } -void ModulesGraph::render(Cool::RenderTarget& render_target, DataToPassToShader const& data_to_pass_to_shader, DataToGenerateShaderCode const& data_to_generate_shader_code) +void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, DataToGenerateShaderCode const& data_to_generate_shader_code) { - if (_compositing_module.depends_on().time_since_last_midi_button_pressed - || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().time_since_last_midi_button_pressed; })) - { - request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this - } - if (render_target.needs_resizing()) - request_rerender_all(); + // TODO(FeedbackLoop) reintroduce it + // if (_compositing_module.depends_on().time_since_last_midi_button_pressed + // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().time_since_last_midi_button_pressed; })) + // { + // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this + // } + + // if (render_target.needs_resizing()) // TODO(FeedbackLoop) handle rerender when size changes + // request_rerender_all(); if (rerender_all_flag().is_dirty()) { request_rerender_all(); @@ -50,46 +52,43 @@ void ModulesGraph::render(Cool::RenderTarget& render_target, DataToPassToShader regenerate_code_flag().set_clean(); } - for (auto& module_node : _particles_module_nodes) - module_node->render_target.set_size(render_target.desired_size()); - _compositing_module.set_render_target_size(render_target.desired_size()); // Must be done before rendering, otherwise we might read a target that is too small. (e.g. 1 pixel on app startup) + // TODO(FeedbackLoop) Is this still necessary ? + // for (auto& module_node : _particles_module_nodes) + // module_node->render_target.set_size(render_target.desired_size()); + // _compositing_module.set_render_target_size(render_target.desired_size()); // Must be done before rendering, otherwise we might read a target that is too small. (e.g. 1 pixel on app startup) // TODO(Particles) Remove those _nodes_graph for (auto& module_node : _particles_module_nodes) { - module_node->module._nodes_graph = &_nodes_editor.graph(); - module_node->module._feedback_double_buffer = &_compositing_module.feedback_double_buffer(); - if (module_node->module.needs_to_rerender()) + module_node->module->_nodes_graph = &_nodes_editor.graph(); + module_node->module->_feedback_double_buffer = &_compositing_module.feedback_double_buffer(); + if (module_node->module->needs_to_rerender()) _compositing_module.needs_to_rerender_flag().set_dirty(); // Because compositing module depends on particles module } // TODO(Modules) Render in the order of dependency between the modules for (auto& node : _particles_module_nodes) - render_particle_module(node->module, node->render_target, data_to_pass_to_shader); - render_compositing_module(render_target, data_to_pass_to_shader); + render_particle_module(*node->module, data_to_pass_to_shader); + render_compositing_module(data_to_pass_to_shader); } -void ModulesGraph::render_one_module(Module& some_module, Cool::RenderTarget& render_target, DataToPassToShader const& data) +void ModulesGraph::render_one_module(Module& some_module, DataToPassToShader const& data) { if (!some_module.needs_to_rerender()) return; + // Cool::Log::Debug::info("bob", fmt::format("{} x {}", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); some_module.needs_to_rerender_flag().set_clean(); - - render_target.render([&]() { - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT); - some_module.do_rendering(data); - }); + some_module.do_rendering(data); if (DebugOptions::log_when_rendering()) Cool::Log::ToUser::info(some_module.name() + " Module", "Rendered"); } -void ModulesGraph::render_particle_module(Module_Particles& module, Cool::RenderTarget& render_target, DataToPassToShader const& data) +void ModulesGraph::render_particle_module(Module& module, DataToPassToShader const& data) { - render_one_module(module, render_target, data); + render_one_module(module, data); } -void ModulesGraph::render_compositing_module(Cool::RenderTarget& render_target, DataToPassToShader const& data) +void ModulesGraph::render_compositing_module(DataToPassToShader const& data) { if (_compositing_module.shader_is_valid()) { @@ -98,7 +97,7 @@ void ModulesGraph::render_compositing_module(Cool::RenderTarget& render_target, { _compositing_module.shader().set_uniform_texture( module_node->texture_name_in_shader, - module_node->render_target.get().texture_id(), + module_node->module->texture().id, Cool::TextureSamplerDescriptor{ .repeat_mode = Cool::TextureRepeatMode::None, .interpolation_mode = glpp::Interpolation::Linear, @@ -107,21 +106,21 @@ void ModulesGraph::render_compositing_module(Cool::RenderTarget& render_target, } } - render_one_module(_compositing_module, render_target, data); + render_one_module(_compositing_module, data); } void ModulesGraph::request_rerender_all() { _compositing_module.needs_to_rerender_flag().set_dirty(); for (auto& node : _particles_module_nodes) - node->module.needs_to_rerender_flag().set_dirty(); + node->module->needs_to_rerender_flag().set_dirty(); } void ModulesGraph::on_time_reset() { _compositing_module.on_time_reset(); for (auto& node : _particles_module_nodes) - node->module.on_time_reset(); + node->module->on_time_reset(); } static auto texture_name_for_module(NodeDefinition const& definition, Cool::NodeId const& id) -> std::string @@ -171,10 +170,10 @@ void ModulesGraph::create_and_compile_all_modules(Cool::NodeId const& root_node_ ); _particles_module_nodes.push_back(std::make_unique( - /* .module = */ Module_Particles(id_of_node_storing_particles_count), + /* .module = */ std::make_unique(id_of_node_storing_particles_count), /* .texture_name_in_shader = */ texture_name_in_shader )); - _particles_module_nodes.back()->module.set_simulation_shader_code(simulation_shader_code, false, dimension); + static_cast(_particles_module_nodes.back()->module.get())->set_simulation_shader_code(simulation_shader_code, false, dimension); } return texture_name_in_shader; @@ -197,7 +196,7 @@ void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, C { for (auto const& _particles_module : _particles_module_nodes) { - _particles_module->module.imgui_windows(ui); + _particles_module->module->imgui_windows(ui); } _compositing_module.imgui_windows(ui); @@ -219,7 +218,7 @@ void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, C ImGui::PushID(&_particles_module); if (ImGui::BeginTabItem("Particle Simulation")) { - _particles_module->module.imgui_show_generated_shader_code(); + static_cast(_particles_module->module.get())->imgui_show_generated_shader_code(); ImGui::EndTabItem(); } ImGui::PopID(); @@ -258,6 +257,16 @@ void ModulesGraph::submit_gizmos(Cool::GizmoManager& gizmos, CommandExecutor con }); } +auto ModulesGraph::root_module() const -> Module const& +{ + return _compositing_module; +} + +auto ModulesGraph::final_texture() const -> Cool::TextureRef +{ + return root_module().texture(); +} + auto ModulesGraph::nodes_config(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const -> NodesConfig { return NodesConfig{ @@ -276,7 +285,7 @@ void ModulesGraph::on_time_changed() { for (auto& node : _particles_module_nodes) { - node->module.request_particles_to_update(); + node->module->on_time_changed(); } if (_compositing_module.depends_on().time || !_particles_module_nodes.empty()) @@ -287,45 +296,49 @@ void ModulesGraph::on_time_changed() void ModulesGraph::on_audio_changed() { - if (_compositing_module.depends_on().audio() - || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [](auto const& module_node) { return module_node->module.depends_on().audio(); })) - { - request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on audio - } + // TODO(FeedbackLoop) Reintroduce this + // if (_compositing_module.depends_on().audio() + // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [](auto const& module_node) { return module_node->module.depends_on().audio(); })) + // { + // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on audio + // } } void ModulesGraph::on_osc_channel_changed(Cool::OSCChannel const& osc_channel) { - if (_compositing_module.depends_on().osc_channel(osc_channel) - || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().osc_channel(osc_channel); })) - { - request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this OSC channel - } + // TODO(FeedbackLoop) Reintroduce this + // if (_compositing_module.depends_on().osc_channel(osc_channel) + // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().osc_channel(osc_channel); })) + // { + // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this OSC channel + // } } void ModulesGraph::on_midi_channel_changed(Cool::MidiChannel const& midi_channel) { - if (_compositing_module.depends_on().midi_channel(midi_channel) - || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().midi_channel(midi_channel); })) - { - request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this Midi channel - } + // TODO(FeedbackLoop) Reintroduce this + // if (_compositing_module.depends_on().midi_channel(midi_channel) + // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().midi_channel(midi_channel); })) + // { + // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this Midi channel + // } } void ModulesGraph::on_last_midi_button_pressed_changed() { - if (_compositing_module.depends_on().last_midi_button_pressed - || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().last_midi_button_pressed; })) - { - request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this last_midi_button_pressed - } + // TODO(FeedbackLoop) Reintroduce this + // if (_compositing_module.depends_on().last_midi_button_pressed + // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().last_midi_button_pressed; })) + // { + // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this last_midi_button_pressed + // } } void ModulesGraph::update_dependencies_from_nodes_graph() { _compositing_module.update_dependencies_from_nodes_graph(_nodes_editor.graph()); for (auto const& module_node : _particles_module_nodes) - module_node->module.update_dependencies_from_nodes_graph(_nodes_editor.graph()); + module_node->module->update_dependencies_from_nodes_graph(_nodes_editor.graph()); } void ModulesGraph::debug_show_nodes_and_links_registries_windows(Ui_Ref ui) const diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index 56ae8203..8485ddfc 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -19,15 +19,15 @@ struct ModulesGraphNode { // ModulesGraphNode(ModulesGraphNode&& other) noexcept = default; // ModulesGraphNode& operator=(ModulesGraphNode&& other) noexcept = default; - ModulesGraphNode(Module_Particles module, std::string texture_name_in_shader) + ModulesGraphNode(std::unique_ptr module, std::string texture_name_in_shader) : module{std::move(module)} , texture_name_in_shader{std::move(texture_name_in_shader)} { } - Module_Particles module{}; - std::string texture_name_in_shader{}; - Cool::RenderTarget render_target{}; + std::unique_ptr module; + std::string texture_name_in_shader{}; + // Cool::RenderTarget render_target{}; private: friend class ser20::access; @@ -47,7 +47,7 @@ class ModulesGraph { ModulesGraph() = default; void update(); - void render(Cool::RenderTarget&, DataToPassToShader const&, DataToGenerateShaderCode const&); + void render(DataToPassToShader const&, DataToGenerateShaderCode const&); void request_rerender_all(); @@ -75,6 +75,8 @@ class ModulesGraph { void imgui_windows(Ui_Ref, Cool::AudioManager&, Cool::NodesLibrary const&) const; void submit_gizmos(Cool::GizmoManager&, CommandExecutor const&, Cool::Camera2D const&); + auto final_texture() const -> Cool::TextureRef; + //---- // These functions are mostly here so that Commands can do their job easily //---- @@ -90,9 +92,10 @@ class ModulesGraph { private: void create_and_compile_all_modules(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const&); - void render_one_module(Module&, Cool::RenderTarget&, DataToPassToShader const&); - void render_compositing_module(Cool::RenderTarget&, DataToPassToShader const&); - void render_particle_module(Module_Particles&, Cool::RenderTarget&, DataToPassToShader const&); + void render_one_module(Module&, DataToPassToShader const&); + void render_compositing_module(DataToPassToShader const&); + void render_particle_module(Module&, DataToPassToShader const&); + auto root_module() const -> Module const&; private: mutable Cool::NodesEditor _nodes_editor{}; @@ -100,7 +103,7 @@ class ModulesGraph { DirtyFlags _dirty_flags{}; mutable Module_Compositing _compositing_module{}; - std::vector> _particles_module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) + std::vector> _particles_module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) // TODO(FeedbackLoop) No need for the unique_ptr private: // Serialization From 0647570bd5d70e89515fc66107772ad9cafbc521 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sat, 31 Aug 2024 21:12:22 +0200 Subject: [PATCH 02/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Handle=20all?= =?UTF-8?q?=20modules=20generically?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cool | 2 +- src/App.cpp | 4 +- src/App.h | 2 +- src/Module/Module.h | 3 +- src/Module/ShaderBased/DataToPassToShader.hpp | 6 +- .../set_uniforms_for_shader_based_module.cpp | 8 - src/Module_Compositing/Module_Compositing.cpp | 11 - src/Module_Compositing/Module_Compositing.h | 4 - src/Module_Particles/Module_Particles.cpp | 3 +- src/ModulesGraph/ModulesGraph.cpp | 204 +++++++++--------- src/ModulesGraph/ModulesGraph.h | 18 +- 11 files changed, 116 insertions(+), 149 deletions(-) diff --git a/Cool b/Cool index cf936cbf..eff4b783 160000 --- a/Cool +++ b/Cool @@ -1 +1 @@ -Subproject commit cf936cbf64cf3fea4f1690e34c0938f39ba92e2c +Subproject commit eff4b783d754fdfe9fe82710df2e8e8bcdb0e4ee diff --git a/src/App.cpp b/src/App.cpp index 854416f0..452092b8 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -206,7 +206,7 @@ auto App::render_view() -> Cool::RenderView& Cool::Polaroid App::polaroid() { return { - .texture = _project.modules_graph->final_texture(), + .texture = [this]() { return _project.modules_graph->final_texture(); }, .render = [this](img::Size size, Cool::Time time, Cool::Time delta_time) { render(size, time, delta_time); } @@ -407,7 +407,7 @@ void App::imgui_windows_only_when_inputs_are_allowed() _gallery_poster.imgui_window([&](img::Size size) { auto the_polaroid = polaroid(); the_polaroid.render(size, _project.clock.time(), _project.clock.delta_time()); - auto const image = the_polaroid.texture.download_pixels(); + auto const image = the_polaroid.texture().download_pixels(); return img::save_png_to_string(image); }); // Recently opened projects diff --git a/src/App.h b/src/App.h index aad67c69..c33f688b 100644 --- a/src/App.h +++ b/src/App.h @@ -97,7 +97,7 @@ class App : public Cool::IApp { auto command_executor () { return CommandExecutor{command_execution_context()}; } auto system_values (img::Size render_target_size, Cool::Time time, Cool::Time delta_time) const { return SystemValues{render_target_size, time, delta_time, _project.camera_2D_manager.camera(), _project.camera_3D_manager.camera(), _project.audio}; } auto ui () { return Ui_Ref{command_executor()}; } - auto data_to_pass_to_shader (img::Size render_target_size, Cool::Time time, Cool::Time delta_time) const { return DataToPassToShader{system_values(render_target_size, time, delta_time), _project.modules_graph->graph(), _project.modules_graph->compositing_module().feedback_double_buffer() }; } + auto data_to_pass_to_shader (img::Size render_target_size, Cool::Time time, Cool::Time delta_time) const { return DataToPassToShader{system_values(render_target_size, time, delta_time), _project.modules_graph->graph() }; } auto data_to_generate_shader_code () const { return DataToGenerateShaderCode{_project.modules_graph->graph(), Cool::GetNodeDefinition_Ref{_nodes_library_manager.library()} }; } // clang-format on diff --git a/src/Module/Module.h b/src/Module/Module.h index 6930ca8d..81465c01 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -26,8 +26,7 @@ class Module { : _name{name} {} - Cool::NodesGraph const* _nodes_graph{}; // TODO(Particles) Remove - Cool::DoubleBufferedRenderTarget const* _feedback_double_buffer{}; // TODO(Particles) Remove + Cool::NodesGraph const* _nodes_graph{}; // TODO(Particles) Remove [[nodiscard]] auto name() const -> const std::string& { return _name; } diff --git a/src/Module/ShaderBased/DataToPassToShader.hpp b/src/Module/ShaderBased/DataToPassToShader.hpp index 5a669333..6a56cd17 100644 --- a/src/Module/ShaderBased/DataToPassToShader.hpp +++ b/src/Module/ShaderBased/DataToPassToShader.hpp @@ -1,14 +1,12 @@ #pragma once -#include "Cool/Gpu/DoubleBufferedRenderTarget.h" #include "Cool/Nodes/NodesGraph.h" #include "Dependencies/SystemValues.h" namespace Lab { struct DataToPassToShader { - SystemValues system_values; - Cool::NodesGraph const& nodes_graph; // NOLINT(*avoid-const-or-ref-data-members) - Cool::DoubleBufferedRenderTarget const& feedback_double_buffer; // NOLINT(*avoid-const-or-ref-data-members) + SystemValues system_values; + Cool::NodesGraph const& nodes_graph; // NOLINT(*avoid-const-or-ref-data-members) }; } // namespace Lab \ No newline at end of file diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp index f272e39d..b97aab8d 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp @@ -113,14 +113,6 @@ void set_uniforms_for_shader_based_module( if (depends_on.audio_spectrum) shader.set_uniform_texture1D("_audio_spectrum", data.system_values.audio_manager.get().spectrum_texture().id()); - shader.set_uniform_texture( - "_previous_frame_texture", - data.feedback_double_buffer.read_target().get().texture_id(), - Cool::TextureSamplerDescriptor{ - .repeat_mode = Cool::TextureRepeatMode::None, - .interpolation_mode = glpp::Interpolation::NearestNeighbour, // Very important. If set to linear, artifacts can appear over time (very visible with the Slit Scan effect). - } - ); Cool::CameraShaderU::set_uniform(shader, data.system_values.camera_3D, data.system_values.aspect_ratio()); data.nodes_graph.for_each_node([&](Node const& node) { // TODO(Modules) Only set it for nodes that are actually compiled in the graph. Otherwise causes problems, e.g. if a webcam node is here but unused, we still request webcam capture every frame, which forces us to rerender every frame for no reason + it does extra work. // TODO(Modules) Each module should store a list of its inputs, so that we can set them there diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index f2ba15f6..c754000f 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -20,11 +20,6 @@ void Module_Compositing::reset_shader() _depends_on = {}; } -void Module_Compositing::on_time_reset() -{ - _feedback_double_buffer.clear_render_targets(); -} - void Module_Compositing::set_shader_code(tl::expected const& shader_code) { if (!shader_code) @@ -54,12 +49,6 @@ void Module_Compositing::imgui_show_generated_shader_code() } } -void Module_Compositing::set_render_target_size(img::Size const& size) -{ - _feedback_double_buffer.write_target().set_size(size); - _feedback_double_buffer.set_read_target_size_immediately(size); -} - void Module_Compositing::render(DataToPassToShader const& data) { if (!_pipeline.shader()) diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index d2ccfc2a..3721f87b 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -20,9 +20,7 @@ class Module_Compositing : public Module { void imgui_show_generated_shader_code(); void reset_shader(); - void on_time_reset() override; - void set_render_target_size(img::Size const& size); void set_shader_code(tl::expected const& shader_code); [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } @@ -30,7 +28,6 @@ class Module_Compositing : public Module { auto shader_is_valid() const -> bool { return _pipeline.shader().has_value(); } // TODO(Modules) Remove auto shader() -> auto const& { return *_pipeline.shader(); } // TODO(Modules) Remove - auto feedback_double_buffer() const -> Cool::DoubleBufferedRenderTarget const& { return _feedback_double_buffer; } private: void render(DataToPassToShader const&) override; @@ -40,7 +37,6 @@ class Module_Compositing : public Module { mutable std::string _shader_code{}; mutable Cool::FullscreenPipeline _pipeline{}; mutable Cool::MessageSender _shader_error_sender{}; - Cool::DoubleBufferedRenderTarget _feedback_double_buffer{}; // TODO(FeedbackLoop) Remvoe mutable ModuleDependencies _depends_on{}; private: diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index 2a2fb798..30425613 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -65,7 +65,8 @@ void Module_Particles::set_simulation_shader_code(tl::expectedmodule->_nodes_graph = &_nodes_editor.graph(); module_node->module->update(); @@ -58,68 +58,58 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data // _compositing_module.set_render_target_size(render_target.desired_size()); // Must be done before rendering, otherwise we might read a target that is too small. (e.g. 1 pixel on app startup) // TODO(Particles) Remove those _nodes_graph - for (auto& module_node : _particles_module_nodes) + for (auto& module_node : _module_nodes) { - module_node->module->_nodes_graph = &_nodes_editor.graph(); - module_node->module->_feedback_double_buffer = &_compositing_module.feedback_double_buffer(); - if (module_node->module->needs_to_rerender()) - _compositing_module.needs_to_rerender_flag().set_dirty(); // Because compositing module depends on particles module + module_node->module->_nodes_graph = &_nodes_editor.graph(); + // TODO(FeedbackLoop) Handle the fact that a node needs to rerender if one of its dependencies needs to rerender + // if (module_node->module->needs_to_rerender()) + // _compositing_module.needs_to_rerender_flag().set_dirty(); // Because compositing module depends on particles module } - // TODO(Modules) Render in the order of dependency between the modules - for (auto& node : _particles_module_nodes) - render_particle_module(*node->module, data_to_pass_to_shader); - render_compositing_module(data_to_pass_to_shader); + // TODO(Modules) TODO(FeedbackLoop) Render in the order of dependency between the modules + for (auto& node : _module_nodes) + render_one_module(*node->module, data_to_pass_to_shader); } void ModulesGraph::render_one_module(Module& some_module, DataToPassToShader const& data) { if (!some_module.needs_to_rerender()) return; + + // TODO(FeedbackLoop) + // if (_compositing_module.shader_is_valid()) + // { + // _compositing_module.shader().bind(); + // for (auto const& module_node : _particles_module_nodes) + // { + // _compositing_module.shader().set_uniform_texture( + // module_node->texture_name_in_shader, + // module_node->module->texture().id, + // Cool::TextureSamplerDescriptor{ + // .repeat_mode = Cool::TextureRepeatMode::None, + // .interpolation_mode = glpp::Interpolation::Linear, + // } + // ); + // } + // } + // TODO(FeedbackLoop) The feedback loop texture must use interpolation nearest neighbour (cf // Very important. If set to linear, artifacts can appear over time (very visible with the Slit Scan effect).) + // Cool::Log::Debug::info("bob", fmt::format("{} x {}", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); - some_module.needs_to_rerender_flag().set_clean(); some_module.do_rendering(data); + some_module.needs_to_rerender_flag().set_clean(); if (DebugOptions::log_when_rendering()) Cool::Log::ToUser::info(some_module.name() + " Module", "Rendered"); } -void ModulesGraph::render_particle_module(Module& module, DataToPassToShader const& data) -{ - render_one_module(module, data); -} - -void ModulesGraph::render_compositing_module(DataToPassToShader const& data) -{ - if (_compositing_module.shader_is_valid()) - { - _compositing_module.shader().bind(); - for (auto const& module_node : _particles_module_nodes) - { - _compositing_module.shader().set_uniform_texture( - module_node->texture_name_in_shader, - module_node->module->texture().id, - Cool::TextureSamplerDescriptor{ - .repeat_mode = Cool::TextureRepeatMode::None, - .interpolation_mode = glpp::Interpolation::Linear, - } - ); - } - } - - render_one_module(_compositing_module, data); -} - void ModulesGraph::request_rerender_all() { - _compositing_module.needs_to_rerender_flag().set_dirty(); - for (auto& node : _particles_module_nodes) + for (auto& node : _module_nodes) node->module->needs_to_rerender_flag().set_dirty(); } void ModulesGraph::on_time_reset() { - _compositing_module.on_time_reset(); - for (auto& node : _particles_module_nodes) + for (auto& node : _module_nodes) node->module->on_time_reset(); } @@ -138,8 +128,7 @@ static auto texture_name_for_module(NodeDefinition const& definition, Cool::Node void ModulesGraph::create_and_compile_all_modules(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data_to_generate_shader_code) { - _particles_module_nodes.clear(); - _compositing_module.reset_shader(); + _module_nodes.clear(); if (!data_to_generate_shader_code.nodes_graph.try_get_node(root_node_id)) return; @@ -147,41 +136,44 @@ void ModulesGraph::create_and_compile_all_modules(Cool::NodeId const& root_node_ auto const shader_code = generate_compositing_shader_code( root_node_id, [&](Cool::NodeId const& particles_root_node_id, NodeDefinition const& node_definition) -> std::optional { + return std::nullopt; if (!is_particle(node_definition.signature())) return std::nullopt; - int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; - auto const texture_name_in_shader = texture_name_for_module(node_definition, particles_root_node_id); - - if (std::none_of( - _particles_module_nodes.begin(), - _particles_module_nodes.end(), - [&](std::unique_ptr const& node) { - return node->texture_name_in_shader == texture_name_in_shader; - } - )) - { - auto id_of_node_storing_particles_count = Cool::NodeId{}; // Will be initialized by generate_simulation_shader_code() - auto const simulation_shader_code = generate_simulation_shader_code( - particles_root_node_id, - id_of_node_storing_particles_count, - dimension, - data_to_generate_shader_code - ); - - _particles_module_nodes.push_back(std::make_unique( - /* .module = */ std::make_unique(id_of_node_storing_particles_count), - /* .texture_name_in_shader = */ texture_name_in_shader - )); - static_cast(_particles_module_nodes.back()->module.get())->set_simulation_shader_code(simulation_shader_code, false, dimension); - } - - return texture_name_in_shader; + // TODO(FeedbackLoop) + return std::nullopt; + // int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; + // auto const texture_name_in_shader = texture_name_for_module(node_definition, particles_root_node_id); + + // if (std::none_of( + // _particles_module_nodes.begin(), + // _particles_module_nodes.end(), + // [&](std::unique_ptr const& node) { + // return node->texture_name_in_shader == texture_name_in_shader; + // } + // )) + // { + // auto id_of_node_storing_particles_count = Cool::NodeId{}; // Will be initialized by generate_simulation_shader_code() + // auto const simulation_shader_code = generate_simulation_shader_code( + // particles_root_node_id, + // id_of_node_storing_particles_count, + // dimension, + // data_to_generate_shader_code + // ); + + // _particles_module_nodes.push_back(std::make_unique( + // /* .module = */ std::make_unique(id_of_node_storing_particles_count), + // /* .texture_name_in_shader = */ texture_name_in_shader + // )); + // static_cast(_particles_module_nodes.back()->module.get())->set_simulation_shader_code(simulation_shader_code, false, dimension); + // } + + // return texture_name_in_shader; }, [&]() { std::vector tex_names; - tex_names.reserve(_particles_module_nodes.size()); - for (auto const& node : _particles_module_nodes) + tex_names.reserve(_module_nodes.size()); + for (auto const& node : _module_nodes) { tex_names.push_back(node->texture_name_in_shader); } @@ -189,16 +181,20 @@ void ModulesGraph::create_and_compile_all_modules(Cool::NodeId const& root_node_ }, data_to_generate_shader_code ); - _compositing_module.set_shader_code(shader_code); + // TODO(FeedbackLoop) + // auto const texture_name_in_shader = texture_name_for_module(node_definition, root_node_id); + _module_nodes.push_back(std::make_shared( + /* .module = */ std::make_shared(), + /* .texture_name_in_shader = */ "bob", + /* .dependencies = */ std::vector>{} + )); + static_cast(_module_nodes.back()->module.get())->set_shader_code(shader_code); } void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const { - for (auto const& _particles_module : _particles_module_nodes) - { - _particles_module->module->imgui_windows(ui); - } - _compositing_module.imgui_windows(ui); + for (auto const& node : _module_nodes) + node->module->imgui_windows(ui); { auto cfg = Cool::NodesConfig{nodes_config(ui, audio_manager, nodes_library)}; @@ -208,21 +204,22 @@ void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, C DebugOptions::show_generated_shader_code([&] { if (ImGui::BeginTabBar("Shaders Tabs", ImGuiTabBarFlags_None)) { - if (ImGui::BeginTabItem("Compositing")) - { - _compositing_module.imgui_show_generated_shader_code(); - ImGui::EndTabItem(); - } - for (auto const& _particles_module : _particles_module_nodes) - { - ImGui::PushID(&_particles_module); - if (ImGui::BeginTabItem("Particle Simulation")) - { - static_cast(_particles_module->module.get())->imgui_show_generated_shader_code(); - ImGui::EndTabItem(); - } - ImGui::PopID(); - } + // TODO(FeedbackLoop) + // if (ImGui::BeginTabItem("Compositing")) + // { + // _compositing_module.imgui_show_generated_shader_code(); + // ImGui::EndTabItem(); + // } + // for (auto const& _particles_module : _particles_module_nodes) + // { + // ImGui::PushID(&_particles_module); + // if (ImGui::BeginTabItem("Particle Simulation")) + // { + // static_cast(_particles_module->module.get())->imgui_show_generated_shader_code(); + // ImGui::EndTabItem(); + // } + // ImGui::PopID(); + // } ImGui::EndTabBar(); } }); @@ -259,12 +256,12 @@ void ModulesGraph::submit_gizmos(Cool::GizmoManager& gizmos, CommandExecutor con auto ModulesGraph::root_module() const -> Module const& { - return _compositing_module; + return *_module_nodes[0]->module; // TODO(FeedbackLoop) } auto ModulesGraph::final_texture() const -> Cool::TextureRef { - return root_module().texture(); + return _module_nodes.empty() ? Cool::TextureRef{} : root_module().texture(); } auto ModulesGraph::nodes_config(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const -> NodesConfig @@ -283,14 +280,14 @@ auto ModulesGraph::nodes_config(Ui_Ref ui, Cool::AudioManager& audio_manager, Co void ModulesGraph::on_time_changed() { - for (auto& node : _particles_module_nodes) + for (auto& node : _module_nodes) { node->module->on_time_changed(); - } - if (_compositing_module.depends_on().time - || !_particles_module_nodes.empty()) - { - request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on time + // TODO(FeedbackLoop) + // if (node->module->depends_on().time) + // { + // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on time + // } } } @@ -336,8 +333,7 @@ void ModulesGraph::on_last_midi_button_pressed_changed() void ModulesGraph::update_dependencies_from_nodes_graph() { - _compositing_module.update_dependencies_from_nodes_graph(_nodes_editor.graph()); - for (auto const& module_node : _particles_module_nodes) + for (auto const& module_node : _module_nodes) module_node->module->update_dependencies_from_nodes_graph(_nodes_editor.graph()); } diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index 8485ddfc..1032b34b 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -19,15 +19,16 @@ struct ModulesGraphNode { // ModulesGraphNode(ModulesGraphNode&& other) noexcept = default; // ModulesGraphNode& operator=(ModulesGraphNode&& other) noexcept = default; - ModulesGraphNode(std::unique_ptr module, std::string texture_name_in_shader) + ModulesGraphNode(std::shared_ptr module, std::string texture_name_in_shader, std::vector> dependencies) : module{std::move(module)} , texture_name_in_shader{std::move(texture_name_in_shader)} + , dependencies{std::move(dependencies)} { } - std::unique_ptr module; - std::string texture_name_in_shader{}; - // Cool::RenderTarget render_target{}; + std::shared_ptr module; + std::string texture_name_in_shader{}; + std::vector> dependencies{}; private: friend class ser20::access; @@ -88,13 +89,10 @@ class ModulesGraph { void remove_link(Cool::LinkId const&); auto try_get_node(Cool::NodeId const&) const -> Node const*; void set_node(Cool::NodeId const&, Node const&); - auto compositing_module() const -> Module_Compositing const& { return _compositing_module; } private: void create_and_compile_all_modules(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const&); void render_one_module(Module&, DataToPassToShader const&); - void render_compositing_module(DataToPassToShader const&); - void render_particle_module(Module&, DataToPassToShader const&); auto root_module() const -> Module const&; private: @@ -102,8 +100,7 @@ class ModulesGraph { mutable Cool::NodeId _main_node_id{}; // TODO(Modules) Rename as _root_node_id? Or _output_node_id? DirtyFlags _dirty_flags{}; - mutable Module_Compositing _compositing_module{}; - std::vector> _particles_module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) // TODO(FeedbackLoop) No need for the unique_ptr + std::vector> _module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) // TODO(FeedbackLoop) No need for the unique_ptr private: // Serialization @@ -112,8 +109,7 @@ class ModulesGraph { void serialize(Archive& archive) { archive( - ser20::make_nvp("Compositing module", _compositing_module), - ser20::make_nvp("Particles module", _particles_module_nodes), + ser20::make_nvp("Modules", _module_nodes), ser20::make_nvp("Dirty flags", _dirty_flags), ser20::make_nvp("Node editor", _nodes_editor), ser20::make_nvp("Main node ID", _main_node_id) From ab7339ac9b0ce9c7cf563e3ab6a16788145b817b Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sat, 31 Aug 2024 23:06:04 +0200 Subject: [PATCH 03/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Generate=20a?= =?UTF-8?q?ll=20the=20modules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Nodes/10 Image/FEEDBACK LOOP.clbnode | 8 ++ src/ModulesGraph/ModulesGraph.cpp | 182 +++++++++++++++++++-------- src/ModulesGraph/ModulesGraph.h | 10 +- 3 files changed, 147 insertions(+), 53 deletions(-) create mode 100644 Nodes/10 Image/FEEDBACK LOOP.clbnode diff --git a/Nodes/10 Image/FEEDBACK LOOP.clbnode b/Nodes/10 Image/FEEDBACK LOOP.clbnode new file mode 100644 index 00000000..6e970c3a --- /dev/null +++ b/Nodes/10 Image/FEEDBACK LOOP.clbnode @@ -0,0 +1,8 @@ +// To learn how to write nodes, see https://coollab-art.com/Tutorials/Writing%20Nodes/Intro + +INPUT UV->sRGB_StraightA 'Image'; + +sRGB_StraightA main(UV uv) +{ + return vec4(); // Doesn't matter, this node file is just a hack to have a node with the right input and output pins +} \ No newline at end of file diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 40fc4557..36185622 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -11,6 +11,7 @@ #include "Cool/StrongTypes/Camera2D.h" #include "Module_Compositing/Module_Compositing.h" #include "Module_Compositing/generate_compositing_shader_code.h" +#include "Module_FeedbackLoop/Module_FeedbackLoop.hpp" #include "Module_Particles/generate_simulation_shader_code.h" #include "Nodes/valid_glsl.h" #include "UI/imgui_show.h" @@ -47,7 +48,7 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data { if (DebugOptions::log_when_compiling_nodes()) Cool::Log::ToUser::info("Modules Graph", "Compiled"); - create_and_compile_all_modules(_main_node_id, data_to_generate_shader_code); + recreate_all_modules(_main_node_id, data_to_generate_shader_code); request_rerender_all(); regenerate_code_flag().set_clean(); } @@ -113,62 +114,86 @@ void ModulesGraph::on_time_reset() node->module->on_time_reset(); } -static auto texture_name_for_module(NodeDefinition const& definition, Cool::NodeId const& id) -> std::string +static auto texture_name_for_module(Cool::NodeId const& id) -> std::string { using fmt::literals::operator""_a; return valid_glsl(fmt::format( FMT_COMPILE( - R"STR(texture_{name}{id})STR" + R"STR(texture_{id})STR" ), - "name"_a = definition.name(), - "id"_a = to_string(id.underlying_uuid()) + "id"_a = to_string(id.underlying_uuid()) ) ); } -void ModulesGraph::create_and_compile_all_modules(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data_to_generate_shader_code) +enum class NodeModuleness { + Generic, + Particle, + FeedbackLoop, +}; + +static auto is_feedback_loop(NodeDefinition const& node_definition) +{ + return node_definition.name() == "FEEDBACK LOOP"; +} + +static auto node_moduleness(NodeDefinition const& node_definition) +{ + if (is_particle(node_definition.signature())) + return NodeModuleness::Particle; + if (is_feedback_loop(node_definition)) + return NodeModuleness::FeedbackLoop; + return NodeModuleness::Generic; +} + +void ModulesGraph::recreate_all_modules(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data_to_generate_shader_code) { _module_nodes.clear(); + _root_module_node = create_module(root_node_id, data_to_generate_shader_code); +} - if (!data_to_generate_shader_code.nodes_graph.try_get_node(root_node_id)) - return; +auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr +{ + auto const* node = data.nodes_graph.try_get_node(root_node_id); + if (!node) + return nullptr; // TODO(FeedbackLoop) Return an error message? + auto const* node_def = data.get_node_definition(node->id_names()); + if (!node_def) + return nullptr; // TODO(FeedbackLoop) Return an error message? + + switch (node_moduleness(*node_def)) + { + case NodeModuleness::Generic: + return create_compositing_module(root_node_id, data); + case NodeModuleness::Particle: + return create_particles_module(root_node_id, *node_def, data); + case NodeModuleness::FeedbackLoop: + return create_feedback_loop_module(root_node_id, data); + } +} + +auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr +{ + auto dependencies = std::vector>{}; auto const shader_code = generate_compositing_shader_code( root_node_id, - [&](Cool::NodeId const& particles_root_node_id, NodeDefinition const& node_definition) -> std::optional { - return std::nullopt; - if (!is_particle(node_definition.signature())) + [&](Cool::NodeId const& node_id, NodeDefinition const& node_definition) -> std::optional { + switch (node_moduleness(node_definition)) + { + case NodeModuleness::Generic: return std::nullopt; - - // TODO(FeedbackLoop) - return std::nullopt; - // int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; - // auto const texture_name_in_shader = texture_name_for_module(node_definition, particles_root_node_id); - - // if (std::none_of( - // _particles_module_nodes.begin(), - // _particles_module_nodes.end(), - // [&](std::unique_ptr const& node) { - // return node->texture_name_in_shader == texture_name_in_shader; - // } - // )) - // { - // auto id_of_node_storing_particles_count = Cool::NodeId{}; // Will be initialized by generate_simulation_shader_code() - // auto const simulation_shader_code = generate_simulation_shader_code( - // particles_root_node_id, - // id_of_node_storing_particles_count, - // dimension, - // data_to_generate_shader_code - // ); - - // _particles_module_nodes.push_back(std::make_unique( - // /* .module = */ std::make_unique(id_of_node_storing_particles_count), - // /* .texture_name_in_shader = */ texture_name_in_shader - // )); - // static_cast(_particles_module_nodes.back()->module.get())->set_simulation_shader_code(simulation_shader_code, false, dimension); - // } - - // return texture_name_in_shader; + case NodeModuleness::Particle: + { + dependencies.push_back(create_particles_module(node_id, node_definition, data)); + return dependencies.back()->texture_name_in_shader; + } + case NodeModuleness::FeedbackLoop: + { + dependencies.push_back(create_feedback_loop_module(node_id, data)); + return dependencies.back()->texture_name_in_shader; + } + } }, [&]() { std::vector tex_names; @@ -179,16 +204,71 @@ void ModulesGraph::create_and_compile_all_modules(Cool::NodeId const& root_node_ } return tex_names; }, - data_to_generate_shader_code + data ); - // TODO(FeedbackLoop) - // auto const texture_name_in_shader = texture_name_for_module(node_definition, root_node_id); + + auto module = std::make_shared(); + module->set_shader_code(shader_code); + + _module_nodes.push_back(std::make_shared( + /* .module = */ module, + /* .texture_name_in_shader = */ texture_name_for_module(root_node_id), + /* .dependencies = */ std::move(dependencies) + )); + return _module_nodes.back(); +} + +auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, NodeDefinition const& node_definition, DataToGenerateShaderCode const& data) -> std::shared_ptr +{ + int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; + auto const texture_name_in_shader = texture_name_for_module(root_node_id); + + // TODO(FeedbackLoop) if a module with the same texture_name_in_shader already exists, return it + // if (std::none_of( + // _particles_module_nodes.begin(), + // _particles_module_nodes.end(), + // [&](std::unique_ptr const& node) { + // return node->texture_name_in_shader == texture_name_in_shader; + // } + // )) + + auto id_of_node_storing_particles_count = Cool::NodeId{}; // Will be initialized by generate_simulation_shader_code() + auto const simulation_shader_code = generate_simulation_shader_code( + root_node_id, + id_of_node_storing_particles_count, + dimension, + data + ); + + auto module = std::make_shared(id_of_node_storing_particles_count); + module->set_simulation_shader_code(simulation_shader_code, false, dimension); + + _module_nodes.push_back(std::make_shared( + /* .module = */ module, + /* .texture_name_in_shader = */ texture_name_in_shader, + /* .dependencies = */ std::vector>{} // TODO(FeedbackLoop) Accumulate the dependencies while generating the shader code + )); + return _module_nodes.back(); +} + +auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr +{ + auto module = std::make_shared(); + + auto const* node = data.nodes_graph.try_get_node(root_node_id); + if (!node) + return nullptr; // TODO(FeedbackLoop) Return an error message? + + assert(node->input_pins().size() == 1); + auto const predecessor_node_id = data.nodes_graph.find_node_connected_to_input_pin(node->input_pins()[0].id()); + auto const dependency = create_module(predecessor_node_id, data); // TODO(FeedbackLoop) Handle the case where the input pin is not connected to anything (generate a dummy module that returns a default texture? we could reuse the same dummy module when there is no node at all in the graph) + _module_nodes.push_back(std::make_shared( - /* .module = */ std::make_shared(), - /* .texture_name_in_shader = */ "bob", - /* .dependencies = */ std::vector>{} + /* .module = */ module, + /* .texture_name_in_shader = */ texture_name_for_module(root_node_id), + /* .dependencies = */ std::vector>{dependency} )); - static_cast(_module_nodes.back()->module.get())->set_shader_code(shader_code); + return _module_nodes.back(); } void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const @@ -254,14 +334,14 @@ void ModulesGraph::submit_gizmos(Cool::GizmoManager& gizmos, CommandExecutor con }); } -auto ModulesGraph::root_module() const -> Module const& +auto ModulesGraph::root_module() const -> Module const* { - return *_module_nodes[0]->module; // TODO(FeedbackLoop) + return _root_module_node ? _root_module_node->module.get() : nullptr; } auto ModulesGraph::final_texture() const -> Cool::TextureRef { - return _module_nodes.empty() ? Cool::TextureRef{} : root_module().texture(); + return root_module() ? root_module()->texture() : Cool::TextureRef{}; } auto ModulesGraph::nodes_config(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const -> NodesConfig diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index 1032b34b..7b571795 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -91,9 +91,14 @@ class ModulesGraph { void set_node(Cool::NodeId const&, Node const&); private: - void create_and_compile_all_modules(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const&); + void recreate_all_modules(Cool::NodeId const& node_id, DataToGenerateShaderCode const&); + auto create_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_compositing_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_particles_module(Cool::NodeId const& node_id, NodeDefinition const&, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_feedback_loop_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + void render_one_module(Module&, DataToPassToShader const&); - auto root_module() const -> Module const&; + auto root_module() const -> Module const*; private: mutable Cool::NodesEditor _nodes_editor{}; @@ -101,6 +106,7 @@ class ModulesGraph { DirtyFlags _dirty_flags{}; std::vector> _module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) // TODO(FeedbackLoop) No need for the unique_ptr + std::shared_ptr _root_module_node{}; private: // Serialization From f0b1ce426933368a9e63bad4b3765a1055cc48ed Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sat, 31 Aug 2024 23:37:15 +0200 Subject: [PATCH 04/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Pass=20textu?= =?UTF-8?q?res=20of=20modules=20to=20the=20modules=20that=20depend=20on=20?= =?UTF-8?q?them?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Meshing/MeshingGui.cpp | 2 +- src/Meshing/gen_mesh_from_sdf.cpp | 11 +++--- src/Meshing/gen_mesh_from_sdf.hpp | 10 ++++- src/Module/Module.h | 8 ++-- .../set_uniforms_for_shader_based_module.cpp | 21 +++++++++-- .../set_uniforms_for_shader_based_module.hpp | 9 ++++- src/Module_Compositing/Module_Compositing.cpp | 5 ++- src/Module_Compositing/Module_Compositing.h | 5 +-- .../Module_FeedbackLoop.cpp | 3 +- .../Module_FeedbackLoop.hpp | 2 +- src/Module_Particles/Module_Particles.cpp | 6 +-- src/Module_Particles/Module_Particles.h | 2 +- src/ModulesGraph/ModulesGraph.cpp | 32 ++++------------ src/ModulesGraph/ModulesGraph.h | 36 +----------------- src/ModulesGraph/ModulesGraphNode.hpp | 37 +++++++++++++++++++ src/Serialization/impl.cpp | 3 ++ 16 files changed, 108 insertions(+), 84 deletions(-) create mode 100644 src/ModulesGraph/ModulesGraphNode.hpp diff --git a/src/Meshing/MeshingGui.cpp b/src/Meshing/MeshingGui.cpp index 450e180f..57e47f61 100644 --- a/src/Meshing/MeshingGui.cpp +++ b/src/Meshing/MeshingGui.cpp @@ -26,7 +26,7 @@ static void gen_and_export_mesh(Cool::NodeId const& main_node_id, MeshingSetting // auto const node_def = data_to_generate_shader_code.get_node_definition(maybe_node->id_names()); // is_shape_3D(node_def->signature()); - auto const maybe_mesh = gen_mesh_from_sdf(main_node_id, meshing_settings, data_to_pass_to_shader, data_to_generate_shader_code); + auto const maybe_mesh = gen_mesh_from_sdf(main_node_id, meshing_settings, data_to_pass_to_shader, data_to_generate_shader_code, {}); // TODO(Meshing) We need to generate an entire ModulesGraph, so that we can properly handle the fact that our module might depend on other modules if (!maybe_mesh) return; // TODO(Meshing) Error message should be handled here export_mesh(*maybe_mesh, mesh_export_settings); diff --git a/src/Meshing/gen_mesh_from_sdf.cpp b/src/Meshing/gen_mesh_from_sdf.cpp index 13c557e3..8fd1cb62 100644 --- a/src/Meshing/gen_mesh_from_sdf.cpp +++ b/src/Meshing/gen_mesh_from_sdf.cpp @@ -83,10 +83,11 @@ void cool_main() } auto gen_mesh_from_sdf( - Cool::NodeId const& main_node_id, - MeshingSettings const& meshing_settings, - DataToPassToShader const& data_to_pass_to_shader, - DataToGenerateShaderCode const& data_to_generate_shader_code + Cool::NodeId const& main_node_id, + MeshingSettings const& meshing_settings, + DataToPassToShader const& data_to_pass_to_shader, + DataToGenerateShaderCode const& data_to_generate_shader_code, + std::vector> const& module_dependencies ) -> std::optional { if constexpr (COOL_OPENGL_VERSION < 430) @@ -125,7 +126,7 @@ auto gen_mesh_from_sdf( auto dependencies = ModuleDependencies{}; update_dependencies_from_shader_code(dependencies, *shader_code); update_dependencies_from_nodes_graph(dependencies, data_to_pass_to_shader.nodes_graph); - set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader); + set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader, module_dependencies); } meshing_compute_shader->compute(meshing_settings.samples_count); diff --git a/src/Meshing/gen_mesh_from_sdf.hpp b/src/Meshing/gen_mesh_from_sdf.hpp index 0f32ff3a..8e5d0d5e 100644 --- a/src/Meshing/gen_mesh_from_sdf.hpp +++ b/src/Meshing/gen_mesh_from_sdf.hpp @@ -7,7 +7,15 @@ namespace Lab { +class ModulesGraphNode; + // TODO(Meshing) Return error message in case of failure (tl::expected) -auto gen_mesh_from_sdf(Cool::NodeId const& main_node_id, MeshingSettings const&, DataToPassToShader const&, DataToGenerateShaderCode const&) -> std::optional; +auto gen_mesh_from_sdf( + Cool::NodeId const& main_node_id, + MeshingSettings const&, + DataToPassToShader const&, + DataToGenerateShaderCode const&, + std::vector> const& module_dependencies +) -> std::optional; } // namespace Lab \ No newline at end of file diff --git a/src/Module/Module.h b/src/Module/Module.h index 81465c01..f3bd55a8 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -13,6 +13,8 @@ namespace Lab { /// Each module has a State struct, and that's what is serialized / modified through commands / stored in presets. /// Rendering only has const access to the registries: creating / updating values is done trough ui() +class ModulesGraphNode; + class Module { public: Module() = default; // TODO(FeedbackLoop) remove? @@ -30,9 +32,9 @@ class Module { [[nodiscard]] auto name() const -> const std::string& { return _name; } - void do_rendering(DataToPassToShader const& data) + void do_rendering(DataToPassToShader const& data, std::vector> const& module_dependencies) { - render(data); + render(data, module_dependencies); _needs_to_rerender_flag.set_clean(); } virtual void imgui_windows(Ui_Ref) const {}; /// The ui() method should be const, because it should only trigger commands, not modify internal values (allows us to handle history / re-rendering at a higher level). If you really need to mutate one of your member variables, mark it as `mutable`. @@ -56,7 +58,7 @@ class Module { virtual auto render_target() -> Cool::RenderTarget& { return _render_target; } private: - virtual void render(DataToPassToShader const&) = 0; + virtual void render(DataToPassToShader const&, std::vector> const& module_dependencies) = 0; private: std::string _name; diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp index b97aab8d..46044001 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp @@ -6,9 +6,11 @@ #include "Cool/Midi/MidiManager.h" #include "Cool/StrongTypes/set_uniform.h" #include "Cool/TextureSource/TextureLibrary_Image.h" +#include "ModulesGraph/ModulesGraphNode.hpp" #include "Nodes/Node.h" #include "Nodes/valid_input_name.h" + namespace Lab { template @@ -88,9 +90,10 @@ static void set_uniform(Cool::OpenGL::Shader const& shader, Cool::SharedVariable } void set_uniforms_for_shader_based_module( - Cool::OpenGL::Shader const& shader, - ModuleDependencies const& depends_on, - DataToPassToShader const& data + Cool::OpenGL::Shader const& shader, + ModuleDependencies const& depends_on, + DataToPassToShader const& data, + std::vector> const& module_dependencies ) { shader.bind(); @@ -124,6 +127,18 @@ void set_uniforms_for_shader_based_module( value_input); } }); + + for (auto const& module_node : module_dependencies) + { + shader.set_uniform_texture( + module_node->texture_name_in_shader, + module_node->module->texture().id, + Cool::TextureSamplerDescriptor{ + .repeat_mode = Cool::TextureRepeatMode::None, + .interpolation_mode = glpp::Interpolation::Linear, // TODO(FeedbackLoop) The texture coming from feedback loop module must use nearest neighbour interpolation (cf // Very important. If set to linear, artifacts can appear over time (very visible with the Slit Scan effect).) + } + ); + } } } // namespace Lab \ No newline at end of file diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp index b779206f..9833f97a 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp @@ -5,6 +5,13 @@ namespace Lab { -void set_uniforms_for_shader_based_module(Cool::OpenGL::Shader const&, ModuleDependencies const&, DataToPassToShader const&); +class ModulesGraphNode; + +void set_uniforms_for_shader_based_module( + Cool::OpenGL::Shader const&, + ModuleDependencies const&, + DataToPassToShader const&, + std::vector> const& module_dependencies +); } // namespace Lab \ No newline at end of file diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index c754000f..9512ff9b 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -49,15 +49,16 @@ void Module_Compositing::imgui_show_generated_shader_code() } } -void Module_Compositing::render(DataToPassToShader const& data) +void Module_Compositing::render(DataToPassToShader const& data, std::vector> const& module_dependencies) { if (!_pipeline.shader()) return; + render_target().set_size(data.system_values.render_target_size); render_target().render([&]() { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data); + set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data, module_dependencies); _pipeline.draw(); }); } diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index 3721f87b..7a5a20fb 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -26,11 +26,8 @@ class Module_Compositing : public Module { [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } - auto shader_is_valid() const -> bool { return _pipeline.shader().has_value(); } // TODO(Modules) Remove - auto shader() -> auto const& { return *_pipeline.shader(); } // TODO(Modules) Remove - private: - void render(DataToPassToShader const&) override; + void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; void log_shader_error(Cool::OptionalErrorMessage const&) const; private: diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index ab9ce5c6..49e76a11 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -14,8 +14,9 @@ void Module_FeedbackLoop::on_time_reset() // TODO(FeedbackLoop) Reset the textures } -void Module_FeedbackLoop::render(DataToPassToShader const& data) +void Module_FeedbackLoop::render(DataToPassToShader const& data, std::vector> const& module_dependencies) { + assert(module_dependencies.size() == 1); // store the texture from the predecessor module // return the texture of the previous frame } diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index 20fde8d6..387e9c26 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -19,7 +19,7 @@ class Module_FeedbackLoop : public Module { void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: - void render(DataToPassToShader const&) override; + void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; private: // Module_Compositing _compositing_module{}; diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index 30425613..885b36c0 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -128,7 +128,7 @@ void Module_Particles::update_particles(DataToPassToShader const& data) _particle_system->simulation_shader().bind(); _particle_system->simulation_shader().set_uniform("_force_init_particles", _force_init_particles); - set_uniforms_for_shader_based_module(_particle_system->simulation_shader(), _depends_on, data); + set_uniforms_for_shader_based_module(_particle_system->simulation_shader(), _depends_on, data, {}); // TODO(Module) We need to access the modules that this module depends on _particle_system->update(); _force_init_particles = false; _needs_to_update_particles = false; @@ -143,7 +143,7 @@ void Module_Particles::imgui_show_generated_shader_code() set_simulation_shader_code(_shader_code, false, _particle_system ? _particle_system->dimension() : _particle_system_dimension); } -void Module_Particles::render(DataToPassToShader const& data) +void Module_Particles::render(DataToPassToShader const& data, std::vector> const& module_dependencies) { if (!_particle_system) return; @@ -156,7 +156,7 @@ void Module_Particles::render(DataToPassToShader const& data) render_target().render([&]() { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data); + set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data, module_dependencies); auto const view_proj_matrix_2D_mat3 = data.system_values.camera_2D_view_projection_matrix(); auto const view_proj_matrix_2D_mat4 = glm::mat4{ diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index 8d87b3d2..4cde7d13 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -34,7 +34,7 @@ class Module_Particles : public Module { void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: - void render(DataToPassToShader const&) override; + void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; void update_particles(DataToPassToShader const&); auto create_particle_system() const -> std::optional; void update_particles_count_ifn(); diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 36185622..1cc3e188 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -12,7 +12,9 @@ #include "Module_Compositing/Module_Compositing.h" #include "Module_Compositing/generate_compositing_shader_code.h" #include "Module_FeedbackLoop/Module_FeedbackLoop.hpp" +#include "Module_Particles/Module_Particles.h" #include "Module_Particles/generate_simulation_shader_code.h" +#include "ModulesGraph/ModulesGraph.h" #include "Nodes/valid_glsl.h" #include "UI/imgui_show.h" @@ -68,38 +70,20 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data } // TODO(Modules) TODO(FeedbackLoop) Render in the order of dependency between the modules for (auto& node : _module_nodes) - render_one_module(*node->module, data_to_pass_to_shader); + render_one_module(*node, data_to_pass_to_shader); } -void ModulesGraph::render_one_module(Module& some_module, DataToPassToShader const& data) +void ModulesGraph::render_one_module(ModulesGraphNode& node, DataToPassToShader const& data) { - if (!some_module.needs_to_rerender()) + if (!node.module->needs_to_rerender()) return; - // TODO(FeedbackLoop) - // if (_compositing_module.shader_is_valid()) - // { - // _compositing_module.shader().bind(); - // for (auto const& module_node : _particles_module_nodes) - // { - // _compositing_module.shader().set_uniform_texture( - // module_node->texture_name_in_shader, - // module_node->module->texture().id, - // Cool::TextureSamplerDescriptor{ - // .repeat_mode = Cool::TextureRepeatMode::None, - // .interpolation_mode = glpp::Interpolation::Linear, - // } - // ); - // } - // } - // TODO(FeedbackLoop) The feedback loop texture must use interpolation nearest neighbour (cf // Very important. If set to linear, artifacts can appear over time (very visible with the Slit Scan effect).) - // Cool::Log::Debug::info("bob", fmt::format("{} x {}", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); - some_module.do_rendering(data); - some_module.needs_to_rerender_flag().set_clean(); + node.module->do_rendering(data, node.dependencies); + node.module->needs_to_rerender_flag().set_clean(); if (DebugOptions::log_when_rendering()) - Cool::Log::ToUser::info(some_module.name() + " Module", "Rendered"); + Cool::Log::ToUser::info(node.module->name() + " Module", "Rendered"); } void ModulesGraph::request_rerender_all() diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index 7b571795..eb5fe8d4 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -4,43 +4,11 @@ #include "Cool/View/GizmoManager.h" #include "DirtyFlags.h" #include "Module/ShaderBased/DataToGenerateShaderCode.hpp" -#include "Module_Compositing/Module_Compositing.h" -#include "Module_Particles/Module_Particles.h" +#include "ModulesGraphNode.hpp" #include "Nodes/NodesConfig.h" namespace Lab { -struct ModulesGraphNode { - ModulesGraphNode() = default; - // ~ModulesGraphNode() = default; - - // ModulesGraphNode(const ModulesGraphNode&) = delete; // We disable copying - // ModulesGraphNode& operator=(const ModulesGraphNode&) = delete; // We disable copying - // ModulesGraphNode(ModulesGraphNode&& other) noexcept = default; - // ModulesGraphNode& operator=(ModulesGraphNode&& other) noexcept = default; - - ModulesGraphNode(std::shared_ptr module, std::string texture_name_in_shader, std::vector> dependencies) - : module{std::move(module)} - , texture_name_in_shader{std::move(texture_name_in_shader)} - , dependencies{std::move(dependencies)} - { - } - - std::shared_ptr module; - std::string texture_name_in_shader{}; - std::vector> dependencies{}; - -private: - friend class ser20::access; - template - void serialize(Archive& archive) - { - archive( - ser20::make_nvp("Module", module) - ); - } -}; - /// The main class containing all the nodes of the project. /// It is responsible for spawning the various modules as required by the nodes, and knowing the dependencies between them. class ModulesGraph { @@ -97,7 +65,7 @@ class ModulesGraph { auto create_particles_module(Cool::NodeId const& node_id, NodeDefinition const&, DataToGenerateShaderCode const&) -> std::shared_ptr; auto create_feedback_loop_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; - void render_one_module(Module&, DataToPassToShader const&); + void render_one_module(ModulesGraphNode&, DataToPassToShader const&); auto root_module() const -> Module const*; private: diff --git a/src/ModulesGraph/ModulesGraphNode.hpp b/src/ModulesGraph/ModulesGraphNode.hpp new file mode 100644 index 00000000..0bbdd45b --- /dev/null +++ b/src/ModulesGraph/ModulesGraphNode.hpp @@ -0,0 +1,37 @@ +#pragma once +#include "Module/Module.h" + +namespace Lab { + +struct ModulesGraphNode { + ModulesGraphNode() = default; + // ~ModulesGraphNode() = default; + + // ModulesGraphNode(const ModulesGraphNode&) = delete; // We disable copying + // ModulesGraphNode& operator=(const ModulesGraphNode&) = delete; // We disable copying + // ModulesGraphNode(ModulesGraphNode&& other) noexcept = default; + // ModulesGraphNode& operator=(ModulesGraphNode&& other) noexcept = default; + + ModulesGraphNode(std::shared_ptr module, std::string texture_name_in_shader, std::vector> dependencies) + : module{std::move(module)} + , texture_name_in_shader{std::move(texture_name_in_shader)} + , dependencies{std::move(dependencies)} + { + } + + std::shared_ptr module; + std::string texture_name_in_shader{}; + std::vector> dependencies{}; + +private: + friend class ser20::access; + template + void serialize(Archive& archive) + { + archive( + ser20::make_nvp("Module", module) + ); + } +}; + +} // namespace Lab \ No newline at end of file diff --git a/src/Serialization/impl.cpp b/src/Serialization/impl.cpp index a9d9c248..bbacb1bc 100644 --- a/src/Serialization/impl.cpp +++ b/src/Serialization/impl.cpp @@ -7,9 +7,12 @@ #include #include "Cool/Serialization/Serialization.h" #include "Dump/coollab_version.h" +#include "Module_Compositing/Module_Compositing.h" +#include "Module_Particles/Module_Particles.h" #include "SNodesCategoryConfig.h" #include "SNodesClipboard.h" #include "SProject.h" + // #include "ser20/archives/json.hpp" From 833c912f9ee548e155412109d54fb50fafe73f77 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 11:10:08 +0200 Subject: [PATCH 05/31] =?UTF-8?q?=E2=9C=A8=20[FeebackLoop]=20Working=20mod?= =?UTF-8?q?ule!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module/Module.h | 4 +- .../Module_FeedbackLoop.cpp | 53 ++++++++++++++++++- .../Module_FeedbackLoop.hpp | 5 +- src/Module_Particles/Module_Particles.h | 1 - src/Serialization/impl.cpp | 6 ++- 5 files changed, 60 insertions(+), 9 deletions(-) diff --git a/src/Module/Module.h b/src/Module/Module.h index f3bd55a8..31d4d4e7 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -54,8 +54,8 @@ class Module { virtual auto texture() const -> Cool::TextureRef { return _render_target.texture_ref(); } -protected: - virtual auto render_target() -> Cool::RenderTarget& { return _render_target; } + auto render_target() -> Cool::RenderTarget& { return _render_target; } + auto render_target() const -> Cool::RenderTarget const& { return _render_target; } private: virtual void render(DataToPassToShader const&, std::vector> const& module_dependencies) = 0; diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index 49e76a11..16dd762e 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -1,4 +1,6 @@ #include "Module_FeedbackLoop.hpp" +#include "Cool/Gpu/OpenGL/FullscreenPipeline.h" +#include "ModulesGraph/ModulesGraphNode.hpp" namespace Lab { @@ -14,11 +16,58 @@ void Module_FeedbackLoop::on_time_reset() // TODO(FeedbackLoop) Reset the textures } +auto Module_FeedbackLoop::texture() const -> Cool::TextureRef +{ + return _bob ? _render_target.texture_ref() : render_target().texture_ref(); +} + +static auto make_copy_tex_pipeline() -> Cool::OpenGL::FullscreenPipeline +{ + auto instance = Cool::OpenGL::FullscreenPipeline{}; + auto const res = instance.compile(R"GLSL( +#version 410 +#include "_COOL_RES_/shaders/shader-utils.glsl" +out vec4 out_Color; +uniform sampler2D tex_to_copy; +void main() +{ + out_Color = texture(tex_to_copy, _uv); +} + )GLSL"); + res.send_error_if_any( + [&](std::string const& message) { + return Cool::Message{ + .category = "Internal", + .message = "Failed to create shader to copy texture:\n" + message, + .severity = Cool::MessageSeverity::Error, + }; + }, + Cool::Log::ToUser::console() + ); + + return instance; +} + +static auto copy_tex_pipeline() -> Cool::OpenGL::FullscreenPipeline& +{ + static auto instance = make_copy_tex_pipeline(); + return instance; +} + void Module_FeedbackLoop::render(DataToPassToShader const& data, std::vector> const& module_dependencies) { + _bob = !_bob; assert(module_dependencies.size() == 1); - // store the texture from the predecessor module - // return the texture of the previous frame + auto& rt = _bob ? render_target() : _render_target; + rt.set_size(data.system_values.render_target_size); + rt.render([&]() { + // TODO(WebGPU) use a texture copy operation instead, it will be more efficient + copy_tex_pipeline().shader()->bind(); + copy_tex_pipeline().shader()->set_uniform_texture("tex_to_copy", module_dependencies[0]->module->texture().id); + glDisable(GL_BLEND); + copy_tex_pipeline().draw(); + glEnable(GL_BLEND); + }); } } // namespace Lab diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index 387e9c26..68837a69 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -1,7 +1,6 @@ #pragma once #include "Module/Module.h" #include "Module/ModuleDependencies.h" -#include "Module_Compositing/Module_Compositing.h" namespace Lab { class Module_FeedbackLoop : public Module { @@ -14,6 +13,7 @@ class Module_FeedbackLoop : public Module { ~Module_FeedbackLoop() override = default; void on_time_reset() override; + auto texture() const -> Cool::TextureRef override; [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } @@ -22,8 +22,9 @@ class Module_FeedbackLoop : public Module { void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; private: - // Module_Compositing _compositing_module{}; + Cool::RenderTarget _render_target{}; ModuleDependencies _depends_on{}; + bool _bob{false}; private: // Serialization diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index 4cde7d13..c118e275 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -1,5 +1,4 @@ #pragma once -#include "Cool/Gpu/DoubleBufferedRenderTarget.h" #include "Cool/Log/OptionalErrorMessage.h" #include "Cool/Nodes/NodeId.h" #include "Cool/Nodes/NodesGraph.h" diff --git a/src/Serialization/impl.cpp b/src/Serialization/impl.cpp index bbacb1bc..75cb7dea 100644 --- a/src/Serialization/impl.cpp +++ b/src/Serialization/impl.cpp @@ -8,6 +8,7 @@ #include "Cool/Serialization/Serialization.h" #include "Dump/coollab_version.h" #include "Module_Compositing/Module_Compositing.h" +#include "Module_FeedbackLoop/Module_FeedbackLoop.hpp" #include "Module_Particles/Module_Particles.h" #include "SNodesCategoryConfig.h" #include "SNodesClipboard.h" @@ -58,5 +59,6 @@ auto string_to_nodes_clipboard(std::string const& string) -> NodesClipboard } // namespace Lab -SER20_REGISTER_TYPE(Lab::Module_Compositing); // NOLINT -SER20_REGISTER_TYPE(Lab::Module_Particles); // NOLINT \ No newline at end of file +SER20_REGISTER_TYPE(Lab::Module_Compositing); // NOLINT +SER20_REGISTER_TYPE(Lab::Module_Particles); // NOLINT +SER20_REGISTER_TYPE(Lab::Module_FeedbackLoop); // NOLINT \ No newline at end of file From cf69d21bf3f89fce51feebb35e02810d54a826dd Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 11:22:26 +0200 Subject: [PATCH 06/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Render=20mod?= =?UTF-8?q?ules=20in=20the=20right=20order?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ModulesGraph/ModulesGraph.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 1cc3e188..4a98c179 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -68,9 +68,8 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data // if (module_node->module->needs_to_rerender()) // _compositing_module.needs_to_rerender_flag().set_dirty(); // Because compositing module depends on particles module } - // TODO(Modules) TODO(FeedbackLoop) Render in the order of dependency between the modules - for (auto& node : _module_nodes) - render_one_module(*node, data_to_pass_to_shader); + + render_one_module(*_root_module_node, data_to_pass_to_shader); } void ModulesGraph::render_one_module(ModulesGraphNode& node, DataToPassToShader const& data) @@ -78,12 +77,15 @@ void ModulesGraph::render_one_module(ModulesGraphNode& node, DataToPassToShader if (!node.module->needs_to_rerender()) return; - // Cool::Log::Debug::info("bob", fmt::format("{} x {}", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); + // Render all the dependencies first, so that we can use their textures + for (auto const& prev : node.dependencies) + render_one_module(*prev, data); + node.module->do_rendering(data, node.dependencies); node.module->needs_to_rerender_flag().set_clean(); if (DebugOptions::log_when_rendering()) - Cool::Log::ToUser::info(node.module->name() + " Module", "Rendered"); + Cool::Log::ToUser::info(node.module->name() + " Module", fmt::format("Rendered ({}x{})", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); } void ModulesGraph::request_rerender_all() From cf273f1e906ddc835c84ed92b11748bf2f1a6181 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 11:33:39 +0200 Subject: [PATCH 07/31] =?UTF-8?q?=E2=9C=A8=20Added=20debug=20option=20to?= =?UTF-8?q?=20force=20rerender=20every=20frame?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.cpp | 3 +++ src/Debug/generate_debug_options.py | 5 +++++ src/Debug/generated/DebugOptions.inl | 16 ++++++++++++++++ 3 files changed, 24 insertions(+) diff --git a/src/App.cpp b/src/App.cpp index 452092b8..c8b12c3f 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -116,6 +116,9 @@ void App::update() initial_project_opening(command_execution_context()); } + if (DebugOptions::force_rerender_every_frame()) + _project.modules_graph->request_rerender_all(); + Cool::user_settings().color_themes.update(); _project.audio.set_force_mute(_project.exporter.is_exporting()); diff --git a/src/Debug/generate_debug_options.py b/src/Debug/generate_debug_options.py index 95ae8ae0..ca25ba5c 100644 --- a/src/Debug/generate_debug_options.py +++ b/src/Debug/generate_debug_options.py @@ -62,6 +62,11 @@ def all_debug_options(): name_in_ui="Show nodes and links registries", available_in_release=True, ), + DebugOption( + name_in_code="force_rerender_every_frame", + name_in_ui="Force rerender every frame", + available_in_release=True, + ), DebugOption( name_in_code="log_when_rendering", name_in_ui="Log when rendering", diff --git a/src/Debug/generated/DebugOptions.inl b/src/Debug/generated/DebugOptions.inl index 7bddab2d..2b45b20d 100644 --- a/src/Debug/generated/DebugOptions.inl +++ b/src/Debug/generated/DebugOptions.inl @@ -39,6 +39,7 @@ public: } } [[nodiscard]] static auto show_nodes_and_links_registries() -> bool& { return instance().show_nodes_and_links_registries; } + [[nodiscard]] static auto force_rerender_every_frame() -> bool& { return instance().force_rerender_every_frame; } [[nodiscard]] static auto log_when_rendering() -> bool& { return instance().log_when_rendering; } [[nodiscard]] static auto log_when_updating_particles() -> bool& { return instance().log_when_updating_particles; } [[nodiscard]] static auto log_when_compiling_nodes() -> bool& { return instance().log_when_compiling_nodes; } @@ -90,6 +91,7 @@ private: bool show_imgui_demo_window{false}; bool show_history_window{false}; bool show_nodes_and_links_registries{false}; + bool force_rerender_every_frame{false}; bool log_when_rendering{false}; bool log_when_updating_particles{false}; bool log_when_compiling_nodes{false}; @@ -113,6 +115,7 @@ private: ser20::make_nvp("ImGui Demo window", show_imgui_demo_window), ser20::make_nvp("Show history", show_history_window), ser20::make_nvp("Show nodes and links registries", show_nodes_and_links_registries), + ser20::make_nvp("Force rerender every frame", force_rerender_every_frame), ser20::make_nvp("Log when rendering", log_when_rendering), ser20::make_nvp("Log when updating particles", log_when_updating_particles), ser20::make_nvp("Log when compiling nodes", log_when_compiling_nodes), @@ -128,6 +131,7 @@ private: ser20::make_nvp("ImGui Demo window", show_imgui_demo_window), ser20::make_nvp("Show history", show_history_window), ser20::make_nvp("Show nodes and links registries", show_nodes_and_links_registries), + ser20::make_nvp("Force rerender every frame", force_rerender_every_frame), ser20::make_nvp("Log when rendering", log_when_rendering), ser20::make_nvp("Log when updating particles", log_when_updating_particles), ser20::make_nvp("Log when compiling nodes", log_when_compiling_nodes), @@ -150,6 +154,7 @@ private: instance().show_imgui_demo_window = false; instance().show_history_window = false; instance().show_nodes_and_links_registries = false; + instance().force_rerender_every_frame = false; instance().log_when_rendering = false; instance().log_when_updating_particles = false; instance().log_when_compiling_nodes = false; @@ -218,6 +223,11 @@ private: Cool::ImGuiExtras::toggle("Show nodes and links registries", &instance().show_nodes_and_links_registries); } + if (wafl::similarity_match({filter, "Force rerender every frame"}) >= wafl::Matches::Strongly) + { + Cool::ImGuiExtras::toggle("Force rerender every frame", &instance().force_rerender_every_frame); + } + if (wafl::similarity_match({filter, "Log when rendering"}) >= wafl::Matches::Strongly) { Cool::ImGuiExtras::toggle("Log when rendering", &instance().log_when_rendering); @@ -308,6 +318,12 @@ private: throw 0.f; // To understand why we need to throw, see `toggle_first_option()` in } + if (wafl::similarity_match({filter, "Force rerender every frame"}) >= wafl::Matches::Strongly) + { + instance().force_rerender_every_frame = !instance().force_rerender_every_frame; + throw 0.f; // To understand why we need to throw, see `toggle_first_option()` in + } + if (wafl::similarity_match({filter, "Log when rendering"}) >= wafl::Matches::Strongly) { instance().log_when_rendering = !instance().log_when_rendering; From 73319da85ba470f931621efd17086b5ff834464e Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 12:33:19 +0200 Subject: [PATCH 08/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Rerender=20w?= =?UTF-8?q?hen=20render=20target=20size=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.cpp | 2 +- src/Module_Compositing/Module_Compositing.cpp | 8 ++- .../Module_FeedbackLoop.cpp | 8 ++- src/Module_Particles/Module_Particles.cpp | 8 ++- src/ModulesGraph/DirtyFlags.cpp | 4 +- src/ModulesGraph/DirtyFlags.h | 4 +- src/ModulesGraph/ModulesGraph.cpp | 56 ++++++++++++------- src/ModulesGraph/ModulesGraph.h | 5 +- 8 files changed, 65 insertions(+), 30 deletions(-) diff --git a/src/App.cpp b/src/App.cpp index c8b12c3f..78afea82 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -144,7 +144,7 @@ void App::update() if (inputs_are_allowed()) // Must update() before we render() to make sure the modules are ready (e.g. Nodes need to parse the definitions of the nodes from files) { - _nodes_library_manager.update(_project.modules_graph->regenerate_code_flag(), _project.modules_graph->graph(), _project.modules_graph->nodes_config(ui(), _project.audio, _nodes_library_manager.library())); + _nodes_library_manager.update(_project.modules_graph->rebuild_modules_graph_flag(), _project.modules_graph->graph(), _project.modules_graph->nodes_config(ui(), _project.audio, _nodes_library_manager.library())); _project.modules_graph->update(); check_inputs(); } diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index 9512ff9b..4e867a0e 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -3,8 +3,14 @@ namespace Lab { +static auto module_id() +{ + static auto i{0}; + return ++i; +} + Module_Compositing::Module_Compositing() - : Module{"Compositing"} + : Module{fmt::format("Compositing {}", module_id())} { } diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index 16dd762e..3057e461 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -4,8 +4,14 @@ namespace Lab { +static auto module_id() +{ + static auto i{0}; + return i++; +} + Module_FeedbackLoop::Module_FeedbackLoop() - : Module{"Feedback Loop"} + : Module{fmt::format("Feedback Loop {}", module_id())} { } diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index 885b36c0..37d0755e 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -5,8 +5,14 @@ namespace Lab { +static auto module_id() +{ + static auto i{0}; + return i++; +} + Module_Particles::Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count) - : Module{"Particles"} + : Module{fmt::format("Particles {}", module_id())} , _id_of_node_storing_particles_count{id_of_node_storing_particles_count} { } diff --git a/src/ModulesGraph/DirtyFlags.cpp b/src/ModulesGraph/DirtyFlags.cpp index eeee530e..e9ba64d5 100644 --- a/src/ModulesGraph/DirtyFlags.cpp +++ b/src/ModulesGraph/DirtyFlags.cpp @@ -4,12 +4,12 @@ namespace Lab { auto DirtyFlags::primary(bool always_requires_shader_code_generation) const -> Cool::DirtyFlag const& { - return always_requires_shader_code_generation ? regenerate_code : rerender; + return always_requires_shader_code_generation ? rebuild : rerender; } auto DirtyFlags::secondary() const -> Cool::DirtyFlag const& { - return regenerate_code; // At the moment only used by Gradient variable when we detect that the number of marks has changed. See `set_value()` of Command_SetVariable.h + return rebuild; // At the moment only used by Gradient variable when we detect that the number of marks has changed. See `set_value()` of Command_SetVariable.h } } // namespace Lab \ No newline at end of file diff --git a/src/ModulesGraph/DirtyFlags.h b/src/ModulesGraph/DirtyFlags.h index f90fe19b..d5c17db7 100644 --- a/src/ModulesGraph/DirtyFlags.h +++ b/src/ModulesGraph/DirtyFlags.h @@ -5,7 +5,7 @@ namespace Lab { struct DirtyFlags { Cool::DirtyFlag rerender{}; - Cool::DirtyFlag regenerate_code{}; // TODO(Modules) Rename as graph_has_changed_flag + Cool::DirtyFlag rebuild{}; /// These two functions are used by variables to know which flag they should use auto primary(bool always_requires_shader_code_generation) const -> Cool::DirtyFlag const&; @@ -19,7 +19,7 @@ struct DirtyFlags { { archive( ser20::make_nvp("Rerender", rerender), - ser20::make_nvp("Regenerate code", regenerate_code) + ser20::make_nvp("Rebuild", rebuild) ); } }; diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 4a98c179..3997c98c 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -29,8 +29,18 @@ void ModulesGraph::update() } } -void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, DataToGenerateShaderCode const& data_to_generate_shader_code) +void ModulesGraph::check_for_rerender_and_rebuild(DataToPassToShader const& data_to_pass_to_shader, DataToGenerateShaderCode const& data_to_generate_shader_code) { + if (rebuild_modules_graph_flag().is_dirty()) + { + if (DebugOptions::log_when_compiling_nodes()) + Cool::Log::ToUser::info("Modules Graph", "Compiled"); + recreate_all_modules(_main_node_id, data_to_generate_shader_code); + request_rerender_all(); + rebuild_modules_graph_flag().set_clean(); + return; // We already requested to rerender all, no need to check if we need to rerender + } + // TODO(FeedbackLoop) reintroduce it // if (_compositing_module.depends_on().time_since_last_midi_button_pressed // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().time_since_last_midi_button_pressed; })) @@ -40,20 +50,26 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data // if (render_target.needs_resizing()) // TODO(FeedbackLoop) handle rerender when size changes // request_rerender_all(); - if (rerender_all_flag().is_dirty()) + + for (auto const& node : _module_nodes) { - request_rerender_all(); - rerender_all_flag().set_clean(); + if (data_to_pass_to_shader.system_values.render_target_size != node->module->texture().size) + node->module->needs_to_rerender_flag().set_dirty(); } - if (regenerate_code_flag().is_dirty()) + if (rerender_all_flag().is_dirty()) { - if (DebugOptions::log_when_compiling_nodes()) - Cool::Log::ToUser::info("Modules Graph", "Compiled"); - recreate_all_modules(_main_node_id, data_to_generate_shader_code); request_rerender_all(); - regenerate_code_flag().set_clean(); + rerender_all_flag().set_clean(); + return; } +} + +void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, DataToGenerateShaderCode const& data_to_generate_shader_code) +{ + check_for_rerender_and_rebuild(data_to_pass_to_shader, data_to_generate_shader_code); + if (!_root_module_node) + return; // TODO(FeedbackLoop) Is this still necessary ? // for (auto& module_node : _particles_module_nodes) @@ -69,23 +85,23 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data // _compositing_module.needs_to_rerender_flag().set_dirty(); // Because compositing module depends on particles module } - render_one_module(*_root_module_node, data_to_pass_to_shader); + render_module_ifn(*_root_module_node, data_to_pass_to_shader); } -void ModulesGraph::render_one_module(ModulesGraphNode& node, DataToPassToShader const& data) +void ModulesGraph::render_module_ifn(ModulesGraphNode& node, DataToPassToShader const& data) { if (!node.module->needs_to_rerender()) return; // Render all the dependencies first, so that we can use their textures for (auto const& prev : node.dependencies) - render_one_module(*prev, data); + render_module_ifn(*prev, data); node.module->do_rendering(data, node.dependencies); node.module->needs_to_rerender_flag().set_clean(); if (DebugOptions::log_when_rendering()) - Cool::Log::ToUser::info(node.module->name() + " Module", fmt::format("Rendered ({}x{})", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); + Cool::Log::ToUser::info(node.module->name(), fmt::format("Rendered ({}x{})", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); } void ModulesGraph::request_rerender_all() @@ -265,7 +281,7 @@ void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, C { auto cfg = Cool::NodesConfig{nodes_config(ui, audio_manager, nodes_library)}; if (_nodes_editor.imgui_windows(cfg, nodes_library)) - regenerate_code_flag().set_dirty(); + rebuild_modules_graph_flag().set_dirty(); } DebugOptions::show_generated_shader_code([&] { if (ImGui::BeginTabBar("Shaders Tabs", ImGuiTabBarFlags_None)) @@ -420,19 +436,19 @@ auto ModulesGraph::get_main_node_id() const -> Cool::NodeId const& void ModulesGraph::set_main_node_id(Cool::NodeId const& id) { _main_node_id = id; - regenerate_code_flag().set_dirty(); // Important when calling this function from a Command + rebuild_modules_graph_flag().set_dirty(); // Important when calling this function from a Command } void ModulesGraph::add_node(Cool::NodeId const& id, Node const& node) { _nodes_editor.graph().add_node(id, node); - regenerate_code_flag().set_dirty(); // Important when calling this function from a Command + rebuild_modules_graph_flag().set_dirty(); // Important when calling this function from a Command } void ModulesGraph::add_link(Cool::LinkId const& id, Cool::Link const& link) { _nodes_editor.graph().add_link(id, link); - regenerate_code_flag().set_dirty(); // Important when calling this function from a Command + rebuild_modules_graph_flag().set_dirty(); // Important when calling this function from a Command } void ModulesGraph::remove_node(Cool::NodeId const& id) @@ -441,13 +457,13 @@ void ModulesGraph::remove_node(Cool::NodeId const& id) node.downcast().clear_all_error_messages(); }); _nodes_editor.graph().remove_node(id); - regenerate_code_flag().set_dirty(); // Important when calling this function from a Command + rebuild_modules_graph_flag().set_dirty(); // Important when calling this function from a Command } void ModulesGraph::remove_link(Cool::LinkId const& id) { _nodes_editor.graph().remove_link(id); - regenerate_code_flag().set_dirty(); // Important when calling this function from a Command + rebuild_modules_graph_flag().set_dirty(); // Important when calling this function from a Command } auto ModulesGraph::try_get_node(Cool::NodeId const& id) const -> Node const* @@ -460,7 +476,7 @@ void ModulesGraph::set_node(Cool::NodeId const& id, Node const& value) graph().nodes().with_mutable_ref(id, [&](Cool::Node& node) { node.downcast() = value; }); - regenerate_code_flag().set_dirty(); // Important when calling this function from a Command + rebuild_modules_graph_flag().set_dirty(); // Important when calling this function from a Command } } // namespace Lab diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index eb5fe8d4..4cfa8eb1 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -23,7 +23,7 @@ class ModulesGraph { [[nodiscard]] auto is_empty() const -> bool { return _nodes_editor.is_empty(); } [[nodiscard]] auto graph() const -> Cool::NodesGraph const& { return _nodes_editor.graph(); } [[nodiscard]] auto graph() -> Cool::NodesGraph& { return _nodes_editor.graph(); } - [[nodiscard]] auto regenerate_code_flag() const -> Cool::DirtyFlag const& { return _dirty_flags.regenerate_code; } + [[nodiscard]] auto rebuild_modules_graph_flag() const -> Cool::DirtyFlag const& { return _dirty_flags.rebuild; } [[nodiscard]] auto rerender_all_flag() const -> Cool::DirtyFlag const& { return _dirty_flags.rerender; } [[nodiscard]] auto dirty_flags() const -> DirtyFlags const& { return _dirty_flags; } [[nodiscard]] auto nodes_config(Ui_Ref, Cool::AudioManager&, Cool::NodesLibrary const&) const -> NodesConfig; @@ -65,7 +65,8 @@ class ModulesGraph { auto create_particles_module(Cool::NodeId const& node_id, NodeDefinition const&, DataToGenerateShaderCode const&) -> std::shared_ptr; auto create_feedback_loop_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; - void render_one_module(ModulesGraphNode&, DataToPassToShader const&); + void render_module_ifn(ModulesGraphNode&, DataToPassToShader const&); + void check_for_rerender_and_rebuild(DataToPassToShader const&, DataToGenerateShaderCode const&); auto root_module() const -> Module const*; private: From 79610af171f4319b890989ce0c6b6e5f61750e2c Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 12:50:51 +0200 Subject: [PATCH 09/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20If=20a=20dep?= =?UTF-8?q?endency=20of=20a=20node=20needs=20to=20rerender,=20then=20the?= =?UTF-8?q?=20node=20also=20needs=20to=20rerender?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ModulesGraph/ModulesGraph.cpp | 12 +----------- src/ModulesGraph/ModulesGraphNode.cpp | 12 ++++++++++++ src/ModulesGraph/ModulesGraphNode.hpp | 2 ++ 3 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 src/ModulesGraph/ModulesGraphNode.cpp diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 3997c98c..4e7b4bd5 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -71,26 +71,16 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data if (!_root_module_node) return; - // TODO(FeedbackLoop) Is this still necessary ? - // for (auto& module_node : _particles_module_nodes) - // module_node->render_target.set_size(render_target.desired_size()); - // _compositing_module.set_render_target_size(render_target.desired_size()); // Must be done before rendering, otherwise we might read a target that is too small. (e.g. 1 pixel on app startup) - // TODO(Particles) Remove those _nodes_graph for (auto& module_node : _module_nodes) - { module_node->module->_nodes_graph = &_nodes_editor.graph(); - // TODO(FeedbackLoop) Handle the fact that a node needs to rerender if one of its dependencies needs to rerender - // if (module_node->module->needs_to_rerender()) - // _compositing_module.needs_to_rerender_flag().set_dirty(); // Because compositing module depends on particles module - } render_module_ifn(*_root_module_node, data_to_pass_to_shader); } void ModulesGraph::render_module_ifn(ModulesGraphNode& node, DataToPassToShader const& data) { - if (!node.module->needs_to_rerender()) + if (!node.needs_to_rerender()) return; // Render all the dependencies first, so that we can use their textures diff --git a/src/ModulesGraph/ModulesGraphNode.cpp b/src/ModulesGraph/ModulesGraphNode.cpp new file mode 100644 index 00000000..7cd68b54 --- /dev/null +++ b/src/ModulesGraph/ModulesGraphNode.cpp @@ -0,0 +1,12 @@ +#include "ModulesGraphNode.hpp" + +namespace Lab { + +auto ModulesGraphNode::needs_to_rerender() const -> bool +{ + return module->needs_to_rerender() || std::any_of(dependencies.begin(), dependencies.end(), [&](auto&& node) { + return node->module->needs_to_rerender(); + }); +} + +} // namespace Lab \ No newline at end of file diff --git a/src/ModulesGraph/ModulesGraphNode.hpp b/src/ModulesGraph/ModulesGraphNode.hpp index 0bbdd45b..ea7a61a1 100644 --- a/src/ModulesGraph/ModulesGraphNode.hpp +++ b/src/ModulesGraph/ModulesGraphNode.hpp @@ -23,6 +23,8 @@ struct ModulesGraphNode { std::string texture_name_in_shader{}; std::vector> dependencies{}; + auto needs_to_rerender() const -> bool; + private: friend class ser20::access; template From c1e6d10f6c168da96a1dbc63ff56dbc59d106368 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 13:39:12 +0200 Subject: [PATCH 10/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Check=20depe?= =?UTF-8?q?ndencies=20on=20time,=20audio,=20osc,=20etc.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module/Module.h | 6 +++ src/Module_Compositing/Module_Compositing.h | 6 +-- src/Module_Particles/Module_Particles.h | 15 +++--- src/ModulesGraph/ModulesGraph.cpp | 51 +++++++++------------ 4 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/Module/Module.h b/src/Module/Module.h index 31d4d4e7..24163ca0 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include "Cool/Gpu/OpenGL/TextureRef.hpp" #include "Cool/Gpu/RenderTarget.h" @@ -57,6 +58,8 @@ class Module { auto render_target() -> Cool::RenderTarget& { return _render_target; } auto render_target() const -> Cool::RenderTarget const& { return _render_target; } + [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } + private: virtual void render(DataToPassToShader const&, std::vector> const& module_dependencies) = 0; @@ -65,6 +68,9 @@ class Module { Cool::DirtyFlag _needs_to_rerender_flag; Cool::RenderTarget _render_target{}; +protected: + ModuleDependencies _depends_on{}; + private: friend class ser20::access; template diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index 7a5a20fb..f3992e75 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -1,8 +1,6 @@ #pragma once #include #include -#include -#include "Cool/Gpu/DoubleBufferedRenderTarget.h" #include "Cool/Gpu/FullscreenPipeline.h" #include "Module/Module.h" @@ -23,8 +21,7 @@ class Module_Compositing : public Module { void set_shader_code(tl::expected const& shader_code); - [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } + void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; @@ -34,7 +31,6 @@ class Module_Compositing : public Module { mutable std::string _shader_code{}; mutable Cool::FullscreenPipeline _pipeline{}; mutable Cool::MessageSender _shader_error_sender{}; - mutable ModuleDependencies _depends_on{}; private: // Serialization diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index c118e275..23d6a24b 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -29,8 +29,7 @@ class Module_Particles : public Module { void set_simulation_shader_code(tl::expected const& shader_code, bool for_testing_nodes, int dimension); void on_time_reset() override; - [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } + void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; @@ -45,12 +44,12 @@ class Module_Particles : public Module { private: mutable std::optional _particle_system{}; int _particle_system_dimension{}; - ModuleDependencies _depends_on{}; // TODO(Particles) Two dependencies, one for each shader (simulation and render) - Cool::NodeId _id_of_node_storing_particles_count{}; - bool _needs_to_update_particles{true}; - bool _force_init_particles{true}; - mutable Cool::MessageSender _simulation_shader_error_sender{}; - mutable std::string _shader_code{}; + // ModuleDependencies _depends_on{}; // TODO(Particles) Two dependencies, one for each shader (simulation and render) + Cool::NodeId _id_of_node_storing_particles_count{}; + bool _needs_to_update_particles{true}; + bool _force_init_particles{true}; + mutable Cool::MessageSender _simulation_shader_error_sender{}; + mutable std::string _shader_code{}; private: // Serialization diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 4e7b4bd5..50c54406 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -355,52 +355,45 @@ void ModulesGraph::on_time_changed() for (auto& node : _module_nodes) { node->module->on_time_changed(); - // TODO(FeedbackLoop) - // if (node->module->depends_on().time) - // { - // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on time - // } + if (node->module->depends_on().time) + node->module->needs_to_rerender_flag().set_dirty(); } } void ModulesGraph::on_audio_changed() { - // TODO(FeedbackLoop) Reintroduce this - // if (_compositing_module.depends_on().audio() - // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [](auto const& module_node) { return module_node->module.depends_on().audio(); })) - // { - // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on audio - // } + for (auto& node : _module_nodes) + { + if (node->module->depends_on().audio()) + node->module->needs_to_rerender_flag().set_dirty(); + } } void ModulesGraph::on_osc_channel_changed(Cool::OSCChannel const& osc_channel) { - // TODO(FeedbackLoop) Reintroduce this - // if (_compositing_module.depends_on().osc_channel(osc_channel) - // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().osc_channel(osc_channel); })) - // { - // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this OSC channel - // } + for (auto& node : _module_nodes) + { + if (node->module->depends_on().osc_channel(osc_channel)) + node->module->needs_to_rerender_flag().set_dirty(); + } } void ModulesGraph::on_midi_channel_changed(Cool::MidiChannel const& midi_channel) { - // TODO(FeedbackLoop) Reintroduce this - // if (_compositing_module.depends_on().midi_channel(midi_channel) - // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().midi_channel(midi_channel); })) - // { - // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this Midi channel - // } + for (auto& node : _module_nodes) + { + if (node->module->depends_on().midi_channel(midi_channel)) + node->module->needs_to_rerender_flag().set_dirty(); + } } void ModulesGraph::on_last_midi_button_pressed_changed() { - // TODO(FeedbackLoop) Reintroduce this - // if (_compositing_module.depends_on().last_midi_button_pressed - // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().last_midi_button_pressed; })) - // { - // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this last_midi_button_pressed - // } + for (auto& node : _module_nodes) + { + if (node->module->depends_on().last_midi_button_pressed) + node->module->needs_to_rerender_flag().set_dirty(); + } } void ModulesGraph::update_dependencies_from_nodes_graph() From 96abc58c22c19ca113ecac0f56580965ddc832d3 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 13:47:52 +0200 Subject: [PATCH 11/31] =?UTF-8?q?=F0=9F=A7=BC=20[ModulesGraph]=20Cleanup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module/Module.h | 2 +- src/ModulesGraph/ModulesGraph.cpp | 29 ++++++++++------------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/src/Module/Module.h b/src/Module/Module.h index 24163ca0..2389c30d 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -18,7 +18,7 @@ class ModulesGraphNode; class Module { public: - Module() = default; // TODO(FeedbackLoop) remove? + Module() = default; // TODO(Module) remove? Module(Module const&) = delete; auto operator=(Module const&) -> Module& = delete; Module(Module&&) noexcept = default; diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 50c54406..a668fd7e 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -34,34 +34,24 @@ void ModulesGraph::check_for_rerender_and_rebuild(DataToPassToShader const& data if (rebuild_modules_graph_flag().is_dirty()) { if (DebugOptions::log_when_compiling_nodes()) - Cool::Log::ToUser::info("Modules Graph", "Compiled"); + Cool::Log::ToUser::info("Modules Graph", "Rebuilt"); recreate_all_modules(_main_node_id, data_to_generate_shader_code); - request_rerender_all(); rebuild_modules_graph_flag().set_clean(); - return; // We already requested to rerender all, no need to check if we need to rerender } - // TODO(FeedbackLoop) reintroduce it - // if (_compositing_module.depends_on().time_since_last_midi_button_pressed - // || std::any_of(_particles_module_nodes.begin(), _particles_module_nodes.end(), [&](auto const& module_node) { return module_node->module.depends_on().time_since_last_midi_button_pressed; })) - // { - // request_rerender_all(); // TODO(Modules) Only rerender the modules that depend on this - // } - - // if (render_target.needs_resizing()) // TODO(FeedbackLoop) handle rerender when size changes - // request_rerender_all(); + if (rerender_all_flag().is_dirty()) + { + request_rerender_all(); + rerender_all_flag().set_clean(); + } for (auto const& node : _module_nodes) { - if (data_to_pass_to_shader.system_values.render_target_size != node->module->texture().size) + if (node->module->depends_on().time_since_last_midi_button_pressed) node->module->needs_to_rerender_flag().set_dirty(); - } - if (rerender_all_flag().is_dirty()) - { - request_rerender_all(); - rerender_all_flag().set_clean(); - return; + if (data_to_pass_to_shader.system_values.render_target_size != node->module->texture().size) + node->module->needs_to_rerender_flag().set_dirty(); } } @@ -142,6 +132,7 @@ void ModulesGraph::recreate_all_modules(Cool::NodeId const& root_node_id, DataTo { _module_nodes.clear(); _root_module_node = create_module(root_node_id, data_to_generate_shader_code); + request_rerender_all(); } auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr From 05ca90d747a75f36845afc2e4b2dc4bbc9e8af2f Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 18:27:25 +0200 Subject: [PATCH 12/31] =?UTF-8?q?=F0=9F=90=9B=20Fix=20image=20and=20video?= =?UTF-8?q?=20export?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cool | 2 +- .../Module_FeedbackLoop.cpp | 41 ++----------------- 2 files changed, 5 insertions(+), 38 deletions(-) diff --git a/Cool b/Cool index eff4b783..42269316 160000 --- a/Cool +++ b/Cool @@ -1 +1 @@ -Subproject commit eff4b783d754fdfe9fe82710df2e8e8bcdb0e4ee +Subproject commit 4226931694ce654291af5295e891921765a69855 diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index 3057e461..b52e932c 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -1,5 +1,5 @@ #include "Module_FeedbackLoop.hpp" -#include "Cool/Gpu/OpenGL/FullscreenPipeline.h" +#include "Cool/Gpu/OpenGL/copy_tex_pipeline.hpp" #include "ModulesGraph/ModulesGraphNode.hpp" namespace Lab { @@ -27,39 +27,6 @@ auto Module_FeedbackLoop::texture() const -> Cool::TextureRef return _bob ? _render_target.texture_ref() : render_target().texture_ref(); } -static auto make_copy_tex_pipeline() -> Cool::OpenGL::FullscreenPipeline -{ - auto instance = Cool::OpenGL::FullscreenPipeline{}; - auto const res = instance.compile(R"GLSL( -#version 410 -#include "_COOL_RES_/shaders/shader-utils.glsl" -out vec4 out_Color; -uniform sampler2D tex_to_copy; -void main() -{ - out_Color = texture(tex_to_copy, _uv); -} - )GLSL"); - res.send_error_if_any( - [&](std::string const& message) { - return Cool::Message{ - .category = "Internal", - .message = "Failed to create shader to copy texture:\n" + message, - .severity = Cool::MessageSeverity::Error, - }; - }, - Cool::Log::ToUser::console() - ); - - return instance; -} - -static auto copy_tex_pipeline() -> Cool::OpenGL::FullscreenPipeline& -{ - static auto instance = make_copy_tex_pipeline(); - return instance; -} - void Module_FeedbackLoop::render(DataToPassToShader const& data, std::vector> const& module_dependencies) { _bob = !_bob; @@ -68,10 +35,10 @@ void Module_FeedbackLoop::render(DataToPassToShader const& data, std::vectorbind(); - copy_tex_pipeline().shader()->set_uniform_texture("tex_to_copy", module_dependencies[0]->module->texture().id); + Cool::copy_tex_pipeline().shader()->bind(); + Cool::copy_tex_pipeline().shader()->set_uniform_texture("tex_to_copy", module_dependencies[0]->module->texture().id); glDisable(GL_BLEND); - copy_tex_pipeline().draw(); + Cool::copy_tex_pipeline().draw(); glEnable(GL_BLEND); }); } From 8e8d0476bdd8829a52bbe38fc27affe63e34c09a Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 18:44:23 +0200 Subject: [PATCH 13/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Show=20gener?= =?UTF-8?q?ated=20shader=20code=20for=20each=20module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module/Module.h | 1 + src/Module_Compositing/Module_Compositing.cpp | 8 ++++--- src/Module_Compositing/Module_Compositing.h | 2 +- src/Module_Particles/Module_Particles.cpp | 10 ++++++--- src/Module_Particles/Module_Particles.h | 4 ++-- src/ModulesGraph/ModulesGraph.cpp | 22 +++++-------------- src/ModulesGraph/ModulesGraph.h | 2 +- 7 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/Module/Module.h b/src/Module/Module.h index 2389c30d..bee149fe 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -43,6 +43,7 @@ class Module { virtual void on_time_changed() {}; virtual void on_time_reset() {}; virtual void update_dependencies_from_nodes_graph(Cool::NodesGraph const&) {}; + virtual void imgui_generated_shader_code_tab() {}; [[nodiscard]] virtual auto needs_to_rerender() const -> bool { diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index 4e867a0e..4ec58a1e 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -47,11 +47,13 @@ void Module_Compositing::log_shader_error(Cool::OptionalErrorMessage const& mayb log_module_error(maybe_err, _shader_error_sender); } -void Module_Compositing::imgui_show_generated_shader_code() +void Module_Compositing::imgui_generated_shader_code_tab() { - if (Cool::ImGuiExtras::input_text_multiline("##Compositing shader code", &_shader_code, ImVec2{-1.f, -1.f})) + if (ImGui::BeginTabItem(name().c_str())) { - set_shader_code(_shader_code); + if (Cool::ImGuiExtras::input_text_multiline("##Compositing shader code", &_shader_code, ImVec2{-1.f, -1.f})) + set_shader_code(_shader_code); + ImGui::EndTabItem(); } } diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index f3992e75..a213b6c7 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -15,7 +15,7 @@ class Module_Compositing : public Module { // auto operator=(Module_Compositing&&) noexcept -> Module_Compositing& = default; // TODO(Modules) void update() override; - void imgui_show_generated_shader_code(); + void imgui_generated_shader_code_tab() override; void reset_shader(); diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index 37d0755e..3440ed14 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -143,10 +143,14 @@ void Module_Particles::update_particles(DataToPassToShader const& data) #endif } -void Module_Particles::imgui_show_generated_shader_code() +void Module_Particles::imgui_generated_shader_code_tab() { - if (Cool::ImGuiExtras::input_text_multiline("##Particles simulation", &_shader_code, ImVec2{-1.f, -1.f})) - set_simulation_shader_code(_shader_code, false, _particle_system ? _particle_system->dimension() : _particle_system_dimension); + if (ImGui::BeginTabItem(fmt::format("{} (Simulation)", name()).c_str())) + { + if (Cool::ImGuiExtras::input_text_multiline("##Particles simulation", &_shader_code, ImVec2{-1.f, -1.f})) + set_simulation_shader_code(_shader_code, false, _particle_system ? _particle_system->dimension() : _particle_system_dimension); + ImGui::EndTabItem(); + } } void Module_Particles::render(DataToPassToShader const& data, std::vector> const& module_dependencies) diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index 23d6a24b..07da623b 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -9,7 +9,7 @@ namespace Lab { class Module_Particles : public Module { public: - Module_Particles() = default; // TODO(FeedbackLoop) remove? + Module_Particles() = default; // TODO(Module) remove? explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count); Module_Particles(Module_Particles const&) = delete; auto operator=(Module_Particles const&) -> Module_Particles& = delete; @@ -19,7 +19,7 @@ class Module_Particles : public Module { void update() override; void on_time_changed() override; - void imgui_show_generated_shader_code(); + void imgui_generated_shader_code_tab() override; [[nodiscard]] auto needs_to_rerender() const -> bool override { diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index a668fd7e..7616fe68 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -267,22 +267,12 @@ void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, C DebugOptions::show_generated_shader_code([&] { if (ImGui::BeginTabBar("Shaders Tabs", ImGuiTabBarFlags_None)) { - // TODO(FeedbackLoop) - // if (ImGui::BeginTabItem("Compositing")) - // { - // _compositing_module.imgui_show_generated_shader_code(); - // ImGui::EndTabItem(); - // } - // for (auto const& _particles_module : _particles_module_nodes) - // { - // ImGui::PushID(&_particles_module); - // if (ImGui::BeginTabItem("Particle Simulation")) - // { - // static_cast(_particles_module->module.get())->imgui_show_generated_shader_code(); - // ImGui::EndTabItem(); - // } - // ImGui::PopID(); - // } + for (auto const& node : _module_nodes) + { + ImGui::PushID(&node); + node->module->imgui_generated_shader_code_tab(); + ImGui::PopID(); + } ImGui::EndTabBar(); } }); diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index 4cfa8eb1..bc307fbd 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -74,7 +74,7 @@ class ModulesGraph { mutable Cool::NodeId _main_node_id{}; // TODO(Modules) Rename as _root_node_id? Or _output_node_id? DirtyFlags _dirty_flags{}; - std::vector> _module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) // TODO(FeedbackLoop) No need for the unique_ptr + std::vector> _module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) std::shared_ptr _root_module_node{}; private: From 490e69022572b31869be2b50dac737edb210232d Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 18:50:53 +0200 Subject: [PATCH 14/31] =?UTF-8?q?=E2=9C=A8=20[FeedbackLoop]=20When=20the?= =?UTF-8?q?=20previous=20frame=20hasn't=20been=20init=20yet,=20use=20the?= =?UTF-8?q?=20current=20frame=20instead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module_FeedbackLoop/Module_FeedbackLoop.cpp | 6 ++++-- src/Module_FeedbackLoop/Module_FeedbackLoop.hpp | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index b52e932c..a740bc73 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -19,17 +19,19 @@ Module_FeedbackLoop::Module_FeedbackLoop() void Module_FeedbackLoop::on_time_reset() { - // TODO(FeedbackLoop) Reset the textures + _renders_count = 0; } auto Module_FeedbackLoop::texture() const -> Cool::TextureRef { - return _bob ? _render_target.texture_ref() : render_target().texture_ref(); + auto const b = _renders_count < 2 ? !_bob : _bob; + return b ? _render_target.texture_ref() : render_target().texture_ref(); } void Module_FeedbackLoop::render(DataToPassToShader const& data, std::vector> const& module_dependencies) { _bob = !_bob; + _renders_count++; assert(module_dependencies.size() == 1); auto& rt = _bob ? render_target() : _render_target; rt.set_size(data.system_values.render_target_size); diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index 68837a69..2654e0b2 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -25,6 +25,7 @@ class Module_FeedbackLoop : public Module { Cool::RenderTarget _render_target{}; ModuleDependencies _depends_on{}; bool _bob{false}; + int _renders_count{0}; private: // Serialization From 590ce21ce8782bb2e0ed5baad58c108faf58d65d Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 22:11:22 +0200 Subject: [PATCH 15/31] =?UTF-8?q?=E2=99=BB=20[ModulesGraph]=20Remove=20Mod?= =?UTF-8?q?ulesGraphNode,=20put=20all=20the=20data=20on=20the=20Module?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Meshing/gen_mesh_from_sdf.cpp | 10 +- src/Meshing/gen_mesh_from_sdf.hpp | 4 +- src/Module/Module.cpp | 7 + src/Module/Module.h | 36 ++-- .../set_uniforms_for_shader_based_module.cpp | 17 +- .../set_uniforms_for_shader_based_module.hpp | 4 +- src/Module_Compositing/Module_Compositing.cpp | 14 +- src/Module_Compositing/Module_Compositing.h | 5 +- .../Module_FeedbackLoop.cpp | 29 ++- .../Module_FeedbackLoop.hpp | 11 +- src/Module_Particles/Module_Particles.cpp | 12 +- src/Module_Particles/Module_Particles.h | 6 +- src/ModulesGraph/ModulesGraph.cpp | 165 ++++++++---------- src/ModulesGraph/ModulesGraph.h | 19 +- src/ModulesGraph/ModulesGraphNode.cpp | 12 -- src/ModulesGraph/ModulesGraphNode.hpp | 39 ----- 16 files changed, 178 insertions(+), 212 deletions(-) delete mode 100644 src/ModulesGraph/ModulesGraphNode.cpp delete mode 100644 src/ModulesGraph/ModulesGraphNode.hpp diff --git a/src/Meshing/gen_mesh_from_sdf.cpp b/src/Meshing/gen_mesh_from_sdf.cpp index 8fd1cb62..8b4abdf1 100644 --- a/src/Meshing/gen_mesh_from_sdf.cpp +++ b/src/Meshing/gen_mesh_from_sdf.cpp @@ -83,11 +83,11 @@ void cool_main() } auto gen_mesh_from_sdf( - Cool::NodeId const& main_node_id, - MeshingSettings const& meshing_settings, - DataToPassToShader const& data_to_pass_to_shader, - DataToGenerateShaderCode const& data_to_generate_shader_code, - std::vector> const& module_dependencies + Cool::NodeId const& main_node_id, + MeshingSettings const& meshing_settings, + DataToPassToShader const& data_to_pass_to_shader, + DataToGenerateShaderCode const& data_to_generate_shader_code, + std::vector> const& module_dependencies ) -> std::optional { if constexpr (COOL_OPENGL_VERSION < 430) diff --git a/src/Meshing/gen_mesh_from_sdf.hpp b/src/Meshing/gen_mesh_from_sdf.hpp index 8e5d0d5e..d2dd70b8 100644 --- a/src/Meshing/gen_mesh_from_sdf.hpp +++ b/src/Meshing/gen_mesh_from_sdf.hpp @@ -7,7 +7,7 @@ namespace Lab { -class ModulesGraphNode; +class Module; // TODO(Meshing) Return error message in case of failure (tl::expected) auto gen_mesh_from_sdf( @@ -15,7 +15,7 @@ auto gen_mesh_from_sdf( MeshingSettings const&, DataToPassToShader const&, DataToGenerateShaderCode const&, - std::vector> const& module_dependencies + std::vector> const& module_dependencies ) -> std::optional; } // namespace Lab \ No newline at end of file diff --git a/src/Module/Module.cpp b/src/Module/Module.cpp index d2aa9c6b..ddcc9b87 100644 --- a/src/Module/Module.cpp +++ b/src/Module/Module.cpp @@ -13,4 +13,11 @@ void Module::log_module_error(Cool::OptionalErrorMessage const& maybe_err, Cool: }); } +auto Module::needs_to_rerender() const -> bool +{ + return _needs_to_rerender_flag.is_dirty() || std::any_of(_dependencies.begin(), _dependencies.end(), [&](auto&& module) { + return module->needs_to_rerender(); + }); +}; + } // namespace Lab \ No newline at end of file diff --git a/src/Module/Module.h b/src/Module/Module.h index bee149fe..05390a9a 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -14,8 +14,6 @@ namespace Lab { /// Each module has a State struct, and that's what is serialized / modified through commands / stored in presets. /// Rendering only has const access to the registries: creating / updating values is done trough ui() -class ModulesGraphNode; - class Module { public: Module() = default; // TODO(Module) remove? @@ -25,30 +23,28 @@ class Module { auto operator=(Module&&) noexcept -> Module& = default; virtual ~Module() = default; - explicit Module(std::string_view name) + explicit Module(std::string_view name, std::string texture_name_in_shader, std::vector> dependencies) : _name{name} + , _texture_name_in_shader{std::move(texture_name_in_shader)} + , _dependencies{std::move(dependencies)} {} Cool::NodesGraph const* _nodes_graph{}; // TODO(Particles) Remove [[nodiscard]] auto name() const -> const std::string& { return _name; } - void do_rendering(DataToPassToShader const& data, std::vector> const& module_dependencies) + void do_rendering(DataToPassToShader const& data) { - render(data, module_dependencies); + render(data); _needs_to_rerender_flag.set_clean(); } - virtual void imgui_windows(Ui_Ref) const {}; /// The ui() method should be const, because it should only trigger commands, not modify internal values (allows us to handle history / re-rendering at a higher level). If you really need to mutate one of your member variables, mark it as `mutable`. - virtual void update() {}; - virtual void on_time_changed() {}; - virtual void on_time_reset() {}; - virtual void update_dependencies_from_nodes_graph(Cool::NodesGraph const&) {}; - virtual void imgui_generated_shader_code_tab() {}; - - [[nodiscard]] virtual auto needs_to_rerender() const -> bool - { - return _needs_to_rerender_flag.is_dirty(); - }; + virtual void imgui_windows(Ui_Ref) const {}; /// The ui() method should be const, because it should only trigger commands, not modify internal values (allows us to handle history / re-rendering at a higher level). If you really need to mutate one of your member variables, mark it as `mutable`. + virtual void update() {}; + virtual void on_time_changed() {}; + virtual void on_time_reset() {}; + virtual void update_dependencies_from_nodes_graph(Cool::NodesGraph const&) {}; + virtual void imgui_generated_shader_code_tab() {}; + [[nodiscard]] virtual auto needs_to_rerender() const -> bool; [[nodiscard]] auto needs_to_rerender_flag() const -> Cool::DirtyFlag const& { return _needs_to_rerender_flag; } @@ -61,14 +57,20 @@ class Module { [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } + [[nodiscard]] auto texture_name_in_shader() const -> std::string const& { return _texture_name_in_shader; } + [[nodiscard]] auto dependencies() const -> std::vector> const& { return _dependencies; } + private: - virtual void render(DataToPassToShader const&, std::vector> const& module_dependencies) = 0; + virtual void render(DataToPassToShader const&) = 0; private: std::string _name; Cool::DirtyFlag _needs_to_rerender_flag; Cool::RenderTarget _render_target{}; + std::string _texture_name_in_shader{}; + std::vector> _dependencies{}; + protected: ModuleDependencies _depends_on{}; diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp index 46044001..0e2c7f3e 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp @@ -6,11 +6,10 @@ #include "Cool/Midi/MidiManager.h" #include "Cool/StrongTypes/set_uniform.h" #include "Cool/TextureSource/TextureLibrary_Image.h" -#include "ModulesGraph/ModulesGraphNode.hpp" +#include "Module/Module.h" #include "Nodes/Node.h" #include "Nodes/valid_input_name.h" - namespace Lab { template @@ -90,10 +89,10 @@ static void set_uniform(Cool::OpenGL::Shader const& shader, Cool::SharedVariable } void set_uniforms_for_shader_based_module( - Cool::OpenGL::Shader const& shader, - ModuleDependencies const& depends_on, - DataToPassToShader const& data, - std::vector> const& module_dependencies + Cool::OpenGL::Shader const& shader, + ModuleDependencies const& depends_on, + DataToPassToShader const& data, + std::vector> const& module_dependencies ) { shader.bind(); @@ -128,11 +127,11 @@ void set_uniforms_for_shader_based_module( } }); - for (auto const& module_node : module_dependencies) + for (auto const& module : module_dependencies) { shader.set_uniform_texture( - module_node->texture_name_in_shader, - module_node->module->texture().id, + module->texture_name_in_shader(), + module->texture().id, Cool::TextureSamplerDescriptor{ .repeat_mode = Cool::TextureRepeatMode::None, .interpolation_mode = glpp::Interpolation::Linear, // TODO(FeedbackLoop) The texture coming from feedback loop module must use nearest neighbour interpolation (cf // Very important. If set to linear, artifacts can appear over time (very visible with the Slit Scan effect).) diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp index 9833f97a..7792cb68 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp @@ -5,13 +5,13 @@ namespace Lab { -class ModulesGraphNode; +class Module; void set_uniforms_for_shader_based_module( Cool::OpenGL::Shader const&, ModuleDependencies const&, DataToPassToShader const&, - std::vector> const& module_dependencies + std::vector> const& module_dependencies ); } // namespace Lab \ No newline at end of file diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index 4ec58a1e..9cbd726c 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -6,11 +6,15 @@ namespace Lab { static auto module_id() { static auto i{0}; - return ++i; + return i++; } -Module_Compositing::Module_Compositing() - : Module{fmt::format("Compositing {}", module_id())} +Module_Compositing::Module_Compositing(std::string texture_name_in_shader, std::vector> dependencies) + : Module{ + fmt::format("Compositing {}", module_id()), + std::move(texture_name_in_shader), + std::move(dependencies) + } { } @@ -57,7 +61,7 @@ void Module_Compositing::imgui_generated_shader_code_tab() } } -void Module_Compositing::render(DataToPassToShader const& data, std::vector> const& module_dependencies) +void Module_Compositing::render(DataToPassToShader const& data) { if (!_pipeline.shader()) return; @@ -66,7 +70,7 @@ void Module_Compositing::render(DataToPassToShader const& data, std::vector> dependencies); Module_Compositing(Module_Compositing const&) = delete; auto operator=(Module_Compositing const&) -> Module_Compositing& = delete; // Module_Compositing(Module_Compositing&&) noexcept = default; // TODO(Modules) @@ -24,7 +25,7 @@ class Module_Compositing : public Module { void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: - void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; + void render(DataToPassToShader const&) override; void log_shader_error(Cool::OptionalErrorMessage const&) const; private: diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index a740bc73..fab163df 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -1,6 +1,6 @@ #include "Module_FeedbackLoop.hpp" #include "Cool/Gpu/OpenGL/copy_tex_pipeline.hpp" -#include "ModulesGraph/ModulesGraphNode.hpp" +#include "Cool/Log/ToUser.h" namespace Lab { @@ -10,13 +10,16 @@ static auto module_id() return i++; } -Module_FeedbackLoop::Module_FeedbackLoop() - : Module{fmt::format("Feedback Loop {}", module_id())} +Module_FeedbackLoop::Module_FeedbackLoop(std::string texture_name_in_shader, std::vector> deps) + : Module{ + fmt::format("Feedback Loop {}", module_id()), + std::move(texture_name_in_shader), + std::move(deps) + } { + assert(dependencies().size() == 1); } -// TODO(FeedbackLoop) each time the module before you renders, you need to request a rerender for the next frame - void Module_FeedbackLoop::on_time_reset() { _renders_count = 0; @@ -28,21 +31,29 @@ auto Module_FeedbackLoop::texture() const -> Cool::TextureRef return b ? _render_target.texture_ref() : render_target().texture_ref(); } -void Module_FeedbackLoop::render(DataToPassToShader const& data, std::vector> const& module_dependencies) +void Module_FeedbackLoop::render(DataToPassToShader const& data) { _bob = !_bob; _renders_count++; - assert(module_dependencies.size() == 1); - auto& rt = _bob ? render_target() : _render_target; + _rerender_next_frame = Module::needs_to_rerender(); + auto& rt = _bob ? render_target() : _render_target; rt.set_size(data.system_values.render_target_size); rt.render([&]() { // TODO(WebGPU) use a texture copy operation instead, it will be more efficient Cool::copy_tex_pipeline().shader()->bind(); - Cool::copy_tex_pipeline().shader()->set_uniform_texture("tex_to_copy", module_dependencies[0]->module->texture().id); + Cool::copy_tex_pipeline().shader()->set_uniform_texture("tex_to_copy", dependencies()[0]->texture().id); glDisable(GL_BLEND); Cool::copy_tex_pipeline().draw(); glEnable(GL_BLEND); }); } +auto Module_FeedbackLoop::needs_to_rerender() const -> bool +{ + if (Module::needs_to_rerender() || _rerender_next_frame) + Cool::Log::ToUser::info("bob", _rerender_next_frame ? "true" : "false"); + // TODO store the result, and use that in render() to check if we need to rerender next frame + return Module::needs_to_rerender() || _rerender_next_frame; +} + } // namespace Lab diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index 2654e0b2..08fe3aeb 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -5,27 +5,30 @@ namespace Lab { class Module_FeedbackLoop : public Module { public: - Module_FeedbackLoop(); + Module_FeedbackLoop() = default; + Module_FeedbackLoop(std::string texture_name_in_shader, std::vector> deps); Module_FeedbackLoop(Module_FeedbackLoop const&) = delete; auto operator=(Module_FeedbackLoop const&) -> Module_FeedbackLoop& = delete; Module_FeedbackLoop(Module_FeedbackLoop&&) noexcept = default; auto operator=(Module_FeedbackLoop&&) noexcept -> Module_FeedbackLoop& = default; ~Module_FeedbackLoop() override = default; - void on_time_reset() override; - auto texture() const -> Cool::TextureRef override; + void on_time_reset() override; + auto texture() const -> Cool::TextureRef override; + [[nodiscard]] auto needs_to_rerender() const -> bool override; [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: - void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; + void render(DataToPassToShader const&) override; private: Cool::RenderTarget _render_target{}; ModuleDependencies _depends_on{}; bool _bob{false}; int _renders_count{0}; + bool _rerender_next_frame{false}; private: // Serialization diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index 3440ed14..a0b2f534 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -11,8 +11,12 @@ static auto module_id() return i++; } -Module_Particles::Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count) - : Module{fmt::format("Particles {}", module_id())} +Module_Particles::Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies) + : Module{ + fmt::format("Particles {}", module_id()), + std::move(texture_name_in_shader), + std::move(dependencies) + } , _id_of_node_storing_particles_count{id_of_node_storing_particles_count} { } @@ -153,7 +157,7 @@ void Module_Particles::imgui_generated_shader_code_tab() } } -void Module_Particles::render(DataToPassToShader const& data, std::vector> const& module_dependencies) +void Module_Particles::render(DataToPassToShader const& data) { if (!_particle_system) return; @@ -166,7 +170,7 @@ void Module_Particles::render(DataToPassToShader const& data, std::vectorrender_shader(), _depends_on, data, module_dependencies); + set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data, dependencies()); auto const view_proj_matrix_2D_mat3 = data.system_values.camera_2D_view_projection_matrix(); auto const view_proj_matrix_2D_mat4 = glm::mat4{ diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index 07da623b..9a2f817d 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -9,8 +9,8 @@ namespace Lab { class Module_Particles : public Module { public: - Module_Particles() = default; // TODO(Module) remove? - explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count); + Module_Particles() = default; + explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies); Module_Particles(Module_Particles const&) = delete; auto operator=(Module_Particles const&) -> Module_Particles& = delete; Module_Particles(Module_Particles&&) noexcept = default; @@ -32,7 +32,7 @@ class Module_Particles : public Module { void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } private: - void render(DataToPassToShader const&, std::vector> const& module_dependencies) override; + void render(DataToPassToShader const&) override; void update_particles(DataToPassToShader const&); auto create_particle_system() const -> std::optional; void update_particles_count_ifn(); diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 7616fe68..d1bf60c9 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -22,10 +22,10 @@ namespace Lab { void ModulesGraph::update() { - for (auto& module_node : _module_nodes) + for (auto& module : _modules) { - module_node->module->_nodes_graph = &_nodes_editor.graph(); - module_node->module->update(); + module->_nodes_graph = &_nodes_editor.graph(); + module->update(); } } @@ -45,55 +45,55 @@ void ModulesGraph::check_for_rerender_and_rebuild(DataToPassToShader const& data rerender_all_flag().set_clean(); } - for (auto const& node : _module_nodes) + for (auto const& module : _modules) { - if (node->module->depends_on().time_since_last_midi_button_pressed) - node->module->needs_to_rerender_flag().set_dirty(); + if (module->depends_on().time_since_last_midi_button_pressed) + module->needs_to_rerender_flag().set_dirty(); - if (data_to_pass_to_shader.system_values.render_target_size != node->module->texture().size) - node->module->needs_to_rerender_flag().set_dirty(); + if (data_to_pass_to_shader.system_values.render_target_size != module->texture().size) + module->needs_to_rerender_flag().set_dirty(); } } void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, DataToGenerateShaderCode const& data_to_generate_shader_code) { check_for_rerender_and_rebuild(data_to_pass_to_shader, data_to_generate_shader_code); - if (!_root_module_node) + if (!_root_module) return; // TODO(Particles) Remove those _nodes_graph - for (auto& module_node : _module_nodes) - module_node->module->_nodes_graph = &_nodes_editor.graph(); + for (auto& module : _modules) + module->_nodes_graph = &_nodes_editor.graph(); - render_module_ifn(*_root_module_node, data_to_pass_to_shader); + render_module_ifn(*_root_module, data_to_pass_to_shader); } -void ModulesGraph::render_module_ifn(ModulesGraphNode& node, DataToPassToShader const& data) +void ModulesGraph::render_module_ifn(Module& module, DataToPassToShader const& data) { - if (!node.needs_to_rerender()) + if (!module.needs_to_rerender()) return; // Render all the dependencies first, so that we can use their textures - for (auto const& prev : node.dependencies) + for (auto const& prev : module.dependencies()) render_module_ifn(*prev, data); - node.module->do_rendering(data, node.dependencies); - node.module->needs_to_rerender_flag().set_clean(); + module.do_rendering(data); + module.needs_to_rerender_flag().set_clean(); if (DebugOptions::log_when_rendering()) - Cool::Log::ToUser::info(node.module->name(), fmt::format("Rendered ({}x{})", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); + Cool::Log::ToUser::info(module.name(), fmt::format("Rendered ({}x{})", data.system_values.render_target_size.width(), data.system_values.render_target_size.height())); } void ModulesGraph::request_rerender_all() { - for (auto& node : _module_nodes) - node->module->needs_to_rerender_flag().set_dirty(); + for (auto& module : _modules) + module->needs_to_rerender_flag().set_dirty(); } void ModulesGraph::on_time_reset() { - for (auto& node : _module_nodes) - node->module->on_time_reset(); + for (auto& module : _modules) + module->on_time_reset(); } static auto texture_name_for_module(Cool::NodeId const& id) -> std::string @@ -130,12 +130,12 @@ static auto node_moduleness(NodeDefinition const& node_definition) void ModulesGraph::recreate_all_modules(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data_to_generate_shader_code) { - _module_nodes.clear(); - _root_module_node = create_module(root_node_id, data_to_generate_shader_code); + _modules.clear(); + _root_module = create_module(root_node_id, data_to_generate_shader_code); request_rerender_all(); } -auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr +auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr { auto const* node = data.nodes_graph.try_get_node(root_node_id); if (!node) @@ -155,9 +155,9 @@ auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerat } } -auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr +auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr { - auto dependencies = std::vector>{}; + auto dependencies = std::vector>{}; auto const shader_code = generate_compositing_shader_code( root_node_id, @@ -169,47 +169,42 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D case NodeModuleness::Particle: { dependencies.push_back(create_particles_module(node_id, node_definition, data)); - return dependencies.back()->texture_name_in_shader; + return dependencies.back()->texture_name_in_shader(); } case NodeModuleness::FeedbackLoop: { dependencies.push_back(create_feedback_loop_module(node_id, data)); - return dependencies.back()->texture_name_in_shader; + return dependencies.back()->texture_name_in_shader(); } } }, [&]() { std::vector tex_names; - tex_names.reserve(_module_nodes.size()); - for (auto const& node : _module_nodes) + tex_names.reserve(_modules.size()); + for (auto const& module : _modules) { - tex_names.push_back(node->texture_name_in_shader); + tex_names.push_back(module->texture_name_in_shader()); } return tex_names; }, data ); - auto module = std::make_shared(); + auto module = std::make_shared(texture_name_for_module(root_node_id), std::move(dependencies)); module->set_shader_code(shader_code); - - _module_nodes.push_back(std::make_shared( - /* .module = */ module, - /* .texture_name_in_shader = */ texture_name_for_module(root_node_id), - /* .dependencies = */ std::move(dependencies) - )); - return _module_nodes.back(); + _modules.push_back(module); + return module; } -auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, NodeDefinition const& node_definition, DataToGenerateShaderCode const& data) -> std::shared_ptr +auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, NodeDefinition const& node_definition, DataToGenerateShaderCode const& data) -> std::shared_ptr { int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; auto const texture_name_in_shader = texture_name_for_module(root_node_id); // TODO(FeedbackLoop) if a module with the same texture_name_in_shader already exists, return it // if (std::none_of( - // _particles_module_nodes.begin(), - // _particles_module_nodes.end(), + // _particles_modules.begin(), + // _particles_modules.end(), // [&](std::unique_ptr const& node) { // return node->texture_name_in_shader == texture_name_in_shader; // } @@ -223,21 +218,18 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod data ); - auto module = std::make_shared(id_of_node_storing_particles_count); + auto module = std::make_shared( + id_of_node_storing_particles_count, + texture_name_in_shader, + std::vector>{} // TODO(FeedbackLoop) Accumulate the dependencies while generating the shader code + ); module->set_simulation_shader_code(simulation_shader_code, false, dimension); - - _module_nodes.push_back(std::make_shared( - /* .module = */ module, - /* .texture_name_in_shader = */ texture_name_in_shader, - /* .dependencies = */ std::vector>{} // TODO(FeedbackLoop) Accumulate the dependencies while generating the shader code - )); - return _module_nodes.back(); + _modules.push_back(module); + return module; } -auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr +auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr { - auto module = std::make_shared(); - auto const* node = data.nodes_graph.try_get_node(root_node_id); if (!node) return nullptr; // TODO(FeedbackLoop) Return an error message? @@ -246,18 +238,18 @@ auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, auto const predecessor_node_id = data.nodes_graph.find_node_connected_to_input_pin(node->input_pins()[0].id()); auto const dependency = create_module(predecessor_node_id, data); // TODO(FeedbackLoop) Handle the case where the input pin is not connected to anything (generate a dummy module that returns a default texture? we could reuse the same dummy module when there is no node at all in the graph) - _module_nodes.push_back(std::make_shared( - /* .module = */ module, - /* .texture_name_in_shader = */ texture_name_for_module(root_node_id), - /* .dependencies = */ std::vector>{dependency} - )); - return _module_nodes.back(); + auto module = std::make_shared( + texture_name_for_module(root_node_id), + std::vector>{dependency} + ); + _modules.push_back(module); + return module; } void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const { - for (auto const& node : _module_nodes) - node->module->imgui_windows(ui); + for (auto const& module : _modules) + module->imgui_windows(ui); { auto cfg = Cool::NodesConfig{nodes_config(ui, audio_manager, nodes_library)}; @@ -267,10 +259,10 @@ void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, C DebugOptions::show_generated_shader_code([&] { if (ImGui::BeginTabBar("Shaders Tabs", ImGuiTabBarFlags_None)) { - for (auto const& node : _module_nodes) + for (auto const& module : _modules) { - ImGui::PushID(&node); - node->module->imgui_generated_shader_code_tab(); + ImGui::PushID(module.get()); + module->imgui_generated_shader_code_tab(); ImGui::PopID(); } ImGui::EndTabBar(); @@ -307,14 +299,9 @@ void ModulesGraph::submit_gizmos(Cool::GizmoManager& gizmos, CommandExecutor con }); } -auto ModulesGraph::root_module() const -> Module const* -{ - return _root_module_node ? _root_module_node->module.get() : nullptr; -} - auto ModulesGraph::final_texture() const -> Cool::TextureRef { - return root_module() ? root_module()->texture() : Cool::TextureRef{}; + return _root_module ? _root_module->texture() : Cool::TextureRef{}; } auto ModulesGraph::nodes_config(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const -> NodesConfig @@ -333,54 +320,54 @@ auto ModulesGraph::nodes_config(Ui_Ref ui, Cool::AudioManager& audio_manager, Co void ModulesGraph::on_time_changed() { - for (auto& node : _module_nodes) + for (auto& module : _modules) { - node->module->on_time_changed(); - if (node->module->depends_on().time) - node->module->needs_to_rerender_flag().set_dirty(); + module->on_time_changed(); + if (module->depends_on().time) + module->needs_to_rerender_flag().set_dirty(); } } void ModulesGraph::on_audio_changed() { - for (auto& node : _module_nodes) + for (auto& module : _modules) { - if (node->module->depends_on().audio()) - node->module->needs_to_rerender_flag().set_dirty(); + if (module->depends_on().audio()) + module->needs_to_rerender_flag().set_dirty(); } } void ModulesGraph::on_osc_channel_changed(Cool::OSCChannel const& osc_channel) { - for (auto& node : _module_nodes) + for (auto& module : _modules) { - if (node->module->depends_on().osc_channel(osc_channel)) - node->module->needs_to_rerender_flag().set_dirty(); + if (module->depends_on().osc_channel(osc_channel)) + module->needs_to_rerender_flag().set_dirty(); } } void ModulesGraph::on_midi_channel_changed(Cool::MidiChannel const& midi_channel) { - for (auto& node : _module_nodes) + for (auto& module : _modules) { - if (node->module->depends_on().midi_channel(midi_channel)) - node->module->needs_to_rerender_flag().set_dirty(); + if (module->depends_on().midi_channel(midi_channel)) + module->needs_to_rerender_flag().set_dirty(); } } void ModulesGraph::on_last_midi_button_pressed_changed() { - for (auto& node : _module_nodes) + for (auto& module : _modules) { - if (node->module->depends_on().last_midi_button_pressed) - node->module->needs_to_rerender_flag().set_dirty(); + if (module->depends_on().last_midi_button_pressed) + module->needs_to_rerender_flag().set_dirty(); } } void ModulesGraph::update_dependencies_from_nodes_graph() { - for (auto const& module_node : _module_nodes) - module_node->module->update_dependencies_from_nodes_graph(_nodes_editor.graph()); + for (auto const& module : _modules) + module->update_dependencies_from_nodes_graph(_nodes_editor.graph()); } void ModulesGraph::debug_show_nodes_and_links_registries_windows(Ui_Ref ui) const diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index bc307fbd..5804fd69 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -3,8 +3,8 @@ #include "Cool/OSC/OSCChannel.h" #include "Cool/View/GizmoManager.h" #include "DirtyFlags.h" +#include "Module/Module.h" #include "Module/ShaderBased/DataToGenerateShaderCode.hpp" -#include "ModulesGraphNode.hpp" #include "Nodes/NodesConfig.h" namespace Lab { @@ -60,22 +60,21 @@ class ModulesGraph { private: void recreate_all_modules(Cool::NodeId const& node_id, DataToGenerateShaderCode const&); - auto create_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; - auto create_compositing_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; - auto create_particles_module(Cool::NodeId const& node_id, NodeDefinition const&, DataToGenerateShaderCode const&) -> std::shared_ptr; - auto create_feedback_loop_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_compositing_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_particles_module(Cool::NodeId const& node_id, NodeDefinition const&, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_feedback_loop_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; - void render_module_ifn(ModulesGraphNode&, DataToPassToShader const&); + void render_module_ifn(Module&, DataToPassToShader const&); void check_for_rerender_and_rebuild(DataToPassToShader const&, DataToGenerateShaderCode const&); - auto root_module() const -> Module const*; private: mutable Cool::NodesEditor _nodes_editor{}; mutable Cool::NodeId _main_node_id{}; // TODO(Modules) Rename as _root_node_id? Or _output_node_id? DirtyFlags _dirty_flags{}; - std::vector> _module_nodes{}; // TODO(Particles) No need for the unique_ptr (in theory) - std::shared_ptr _root_module_node{}; + std::vector> _modules{}; // TODO(Particles) No need for the unique_ptr (in theory) + std::shared_ptr _root_module{}; private: // Serialization @@ -84,7 +83,7 @@ class ModulesGraph { void serialize(Archive& archive) { archive( - ser20::make_nvp("Modules", _module_nodes), + ser20::make_nvp("Modules", _modules), ser20::make_nvp("Dirty flags", _dirty_flags), ser20::make_nvp("Node editor", _nodes_editor), ser20::make_nvp("Main node ID", _main_node_id) diff --git a/src/ModulesGraph/ModulesGraphNode.cpp b/src/ModulesGraph/ModulesGraphNode.cpp deleted file mode 100644 index 7cd68b54..00000000 --- a/src/ModulesGraph/ModulesGraphNode.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "ModulesGraphNode.hpp" - -namespace Lab { - -auto ModulesGraphNode::needs_to_rerender() const -> bool -{ - return module->needs_to_rerender() || std::any_of(dependencies.begin(), dependencies.end(), [&](auto&& node) { - return node->module->needs_to_rerender(); - }); -} - -} // namespace Lab \ No newline at end of file diff --git a/src/ModulesGraph/ModulesGraphNode.hpp b/src/ModulesGraph/ModulesGraphNode.hpp deleted file mode 100644 index ea7a61a1..00000000 --- a/src/ModulesGraph/ModulesGraphNode.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once -#include "Module/Module.h" - -namespace Lab { - -struct ModulesGraphNode { - ModulesGraphNode() = default; - // ~ModulesGraphNode() = default; - - // ModulesGraphNode(const ModulesGraphNode&) = delete; // We disable copying - // ModulesGraphNode& operator=(const ModulesGraphNode&) = delete; // We disable copying - // ModulesGraphNode(ModulesGraphNode&& other) noexcept = default; - // ModulesGraphNode& operator=(ModulesGraphNode&& other) noexcept = default; - - ModulesGraphNode(std::shared_ptr module, std::string texture_name_in_shader, std::vector> dependencies) - : module{std::move(module)} - , texture_name_in_shader{std::move(texture_name_in_shader)} - , dependencies{std::move(dependencies)} - { - } - - std::shared_ptr module; - std::string texture_name_in_shader{}; - std::vector> dependencies{}; - - auto needs_to_rerender() const -> bool; - -private: - friend class ser20::access; - template - void serialize(Archive& archive) - { - archive( - ser20::make_nvp("Module", module) - ); - } -}; - -} // namespace Lab \ No newline at end of file From 9eaf4df56c3a4a5702bfc60df06e4515dd5eb1d0 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 22:31:32 +0200 Subject: [PATCH 16/31] =?UTF-8?q?=E2=9C=A8=20[FeedbackLoop]=20Request=20a?= =?UTF-8?q?=20rerender=20for=20the=20next=20frame,=20after=20the=20depende?= =?UTF-8?q?ncy=20rendered=20on=20a=20given=20frame?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module_FeedbackLoop/Module_FeedbackLoop.cpp | 14 ++++++++------ src/Module_FeedbackLoop/Module_FeedbackLoop.hpp | 2 ++ src/ModulesGraph/ModulesGraph.cpp | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index fab163df..30b4bf7b 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -35,8 +35,7 @@ void Module_FeedbackLoop::render(DataToPassToShader const& data) { _bob = !_bob; _renders_count++; - _rerender_next_frame = Module::needs_to_rerender(); - auto& rt = _bob ? render_target() : _render_target; + auto& rt = _bob ? render_target() : _render_target; rt.set_size(data.system_values.render_target_size); rt.render([&]() { // TODO(WebGPU) use a texture copy operation instead, it will be more efficient @@ -48,12 +47,15 @@ void Module_FeedbackLoop::render(DataToPassToShader const& data) }); } +void Module_FeedbackLoop::before_module_graph_renders() +{ + _rerender_this_frame = _rerender_next_frame; + _rerender_next_frame = Module::needs_to_rerender(); +} + auto Module_FeedbackLoop::needs_to_rerender() const -> bool { - if (Module::needs_to_rerender() || _rerender_next_frame) - Cool::Log::ToUser::info("bob", _rerender_next_frame ? "true" : "false"); - // TODO store the result, and use that in render() to check if we need to rerender next frame - return Module::needs_to_rerender() || _rerender_next_frame; + return Module::needs_to_rerender() || _rerender_this_frame; } } // namespace Lab diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index 08fe3aeb..de57fe54 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -16,6 +16,7 @@ class Module_FeedbackLoop : public Module { void on_time_reset() override; auto texture() const -> Cool::TextureRef override; [[nodiscard]] auto needs_to_rerender() const -> bool override; + void before_module_graph_renders() override; [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } @@ -29,6 +30,7 @@ class Module_FeedbackLoop : public Module { bool _bob{false}; int _renders_count{0}; bool _rerender_next_frame{false}; + bool _rerender_this_frame{false}; private: // Serialization diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index d1bf60c9..4bb3ca4f 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -63,7 +63,10 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data // TODO(Particles) Remove those _nodes_graph for (auto& module : _modules) + { module->_nodes_graph = &_nodes_editor.graph(); + module->before_module_graph_renders(); + } render_module_ifn(*_root_module, data_to_pass_to_shader); } From 7aa7c4241bd3ffbe4f053f617264f2065faededb Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 22:59:58 +0200 Subject: [PATCH 17/31] =?UTF-8?q?=E2=9C=A8=20[Module=5FDefault]=20Added?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module/Module.h | 16 ++++------ src/Module_Compositing/Module_Compositing.h | 2 -- src/Module_Default/Module_Default.cpp | 28 +++++++++++++++++ src/Module_Default/Module_Default.hpp | 31 +++++++++++++++++++ .../Module_FeedbackLoop.hpp | 4 --- src/Module_Particles/Module_Particles.h | 2 -- src/ModulesGraph/ModulesGraph.cpp | 13 ++++---- src/ModulesGraph/ModulesGraph.h | 4 +-- src/Serialization/impl.cpp | 4 ++- 9 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 src/Module_Default/Module_Default.cpp create mode 100644 src/Module_Default/Module_Default.hpp diff --git a/src/Module/Module.h b/src/Module/Module.h index 05390a9a..e9543ce9 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -42,21 +42,17 @@ class Module { virtual void update() {}; virtual void on_time_changed() {}; virtual void on_time_reset() {}; - virtual void update_dependencies_from_nodes_graph(Cool::NodesGraph const&) {}; virtual void imgui_generated_shader_code_tab() {}; [[nodiscard]] virtual auto needs_to_rerender() const -> bool; + virtual void before_module_graph_renders() {}; + virtual auto texture() const -> Cool::TextureRef { return _render_target.texture_ref(); } [[nodiscard]] auto needs_to_rerender_flag() const -> Cool::DirtyFlag const& { return _needs_to_rerender_flag; } - - void log_module_error(Cool::OptionalErrorMessage const&, Cool::MessageSender&) const; - - virtual auto texture() const -> Cool::TextureRef { return _render_target.texture_ref(); } - - auto render_target() -> Cool::RenderTarget& { return _render_target; } - auto render_target() const -> Cool::RenderTarget const& { return _render_target; } - + void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } + void log_module_error(Cool::OptionalErrorMessage const&, Cool::MessageSender&) const; + auto render_target() -> Cool::RenderTarget& { return _render_target; } + auto render_target() const -> Cool::RenderTarget const& { return _render_target; } [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } - [[nodiscard]] auto texture_name_in_shader() const -> std::string const& { return _texture_name_in_shader; } [[nodiscard]] auto dependencies() const -> std::vector> const& { return _dependencies; } diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index 47a8f358..078cf717 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -22,8 +22,6 @@ class Module_Compositing : public Module { void set_shader_code(tl::expected const& shader_code); - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } - private: void render(DataToPassToShader const&) override; void log_shader_error(Cool::OptionalErrorMessage const&) const; diff --git a/src/Module_Default/Module_Default.cpp b/src/Module_Default/Module_Default.cpp new file mode 100644 index 00000000..4d703267 --- /dev/null +++ b/src/Module_Default/Module_Default.cpp @@ -0,0 +1,28 @@ +#include "Module_Default.hpp" + +namespace Lab { + +static auto module_id() +{ + static auto i{0}; + return i++; +} + +Module_Default::Module_Default(std::string texture_name_in_shader) + : Module{ + fmt::format("Default {}", module_id()), + std::move(texture_name_in_shader), + {} + } +{} + +void Module_Default::render(DataToPassToShader const& data) +{ + render_target().set_size(data.system_values.render_target_size); + render_target().render([&]() { + glClearColor(0.f, 0.f, 0.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + }); +} + +} // namespace Lab diff --git a/src/Module_Default/Module_Default.hpp b/src/Module_Default/Module_Default.hpp new file mode 100644 index 00000000..e84c2d05 --- /dev/null +++ b/src/Module_Default/Module_Default.hpp @@ -0,0 +1,31 @@ +#pragma once +#include "Module/Module.h" +#include "Module/ModuleDependencies.h" + +namespace Lab { +class Module_Default : public Module { +public: + Module_Default() = default; + Module_Default(std::string texture_name_in_shader); + Module_Default(Module_Default const&) = delete; + auto operator=(Module_Default const&) -> Module_Default& = delete; + Module_Default(Module_Default&&) noexcept = default; + auto operator=(Module_Default&&) noexcept -> Module_Default& = default; + ~Module_Default() override = default; + +private: + void render(DataToPassToShader const&) override; + +private: + // Serialization + friend class ser20::access; + template + void serialize(Archive& archive) + { + archive( + ser20::make_nvp("Base Module", ser20::base_class(this)) + ); + } +}; + +} // namespace Lab diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index de57fe54..9272fe68 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -18,15 +18,11 @@ class Module_FeedbackLoop : public Module { [[nodiscard]] auto needs_to_rerender() const -> bool override; void before_module_graph_renders() override; - [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } - private: void render(DataToPassToShader const&) override; private: Cool::RenderTarget _render_target{}; - ModuleDependencies _depends_on{}; bool _bob{false}; int _renders_count{0}; bool _rerender_next_frame{false}; diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index 9a2f817d..ee8f71ca 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -29,8 +29,6 @@ class Module_Particles : public Module { void set_simulation_shader_code(tl::expected const& shader_code, bool for_testing_nodes, int dimension); void on_time_reset() override; - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) override { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } - private: void render(DataToPassToShader const&) override; void update_particles(DataToPassToShader const&); diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 4bb3ca4f..474c2d0f 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -11,6 +11,7 @@ #include "Cool/StrongTypes/Camera2D.h" #include "Module_Compositing/Module_Compositing.h" #include "Module_Compositing/generate_compositing_shader_code.h" +#include "Module_Default/Module_Default.hpp" #include "Module_FeedbackLoop/Module_FeedbackLoop.hpp" #include "Module_Particles/Module_Particles.h" #include "Module_Particles/generate_simulation_shader_code.h" @@ -142,10 +143,10 @@ auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerat { auto const* node = data.nodes_graph.try_get_node(root_node_id); if (!node) - return nullptr; // TODO(FeedbackLoop) Return an error message? + return std::make_shared(texture_name_for_module(root_node_id)); // TODO(Module) Return an error message? Probably not because this is legit, eg when a feedback loop has nothing in its input pin auto const* node_def = data.get_node_definition(node->id_names()); if (!node_def) - return nullptr; // TODO(FeedbackLoop) Return an error message? + return std::make_shared(texture_name_for_module(root_node_id)); // TODO(Module) Return an error message, this shouldn't happen switch (node_moduleness(*node_def)) { @@ -224,7 +225,7 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod auto module = std::make_shared( id_of_node_storing_particles_count, texture_name_in_shader, - std::vector>{} // TODO(FeedbackLoop) Accumulate the dependencies while generating the shader code + std::vector>{} // TODO(Module) Accumulate the dependencies while generating the shader code ); module->set_simulation_shader_code(simulation_shader_code, false, dimension); _modules.push_back(module); @@ -235,11 +236,11 @@ auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, { auto const* node = data.nodes_graph.try_get_node(root_node_id); if (!node) - return nullptr; // TODO(FeedbackLoop) Return an error message? + return nullptr; // TODO(Module) Return an error message? This should never happen assert(node->input_pins().size() == 1); auto const predecessor_node_id = data.nodes_graph.find_node_connected_to_input_pin(node->input_pins()[0].id()); - auto const dependency = create_module(predecessor_node_id, data); // TODO(FeedbackLoop) Handle the case where the input pin is not connected to anything (generate a dummy module that returns a default texture? we could reuse the same dummy module when there is no node at all in the graph) + auto const dependency = create_module(predecessor_node_id, data); auto module = std::make_shared( texture_name_for_module(root_node_id), @@ -304,7 +305,7 @@ void ModulesGraph::submit_gizmos(Cool::GizmoManager& gizmos, CommandExecutor con auto ModulesGraph::final_texture() const -> Cool::TextureRef { - return _root_module ? _root_module->texture() : Cool::TextureRef{}; + return _root_module->texture(); } auto ModulesGraph::nodes_config(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const -> NodesConfig diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index 5804fd69..764a646b 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -73,8 +73,8 @@ class ModulesGraph { mutable Cool::NodeId _main_node_id{}; // TODO(Modules) Rename as _root_node_id? Or _output_node_id? DirtyFlags _dirty_flags{}; - std::vector> _modules{}; // TODO(Particles) No need for the unique_ptr (in theory) - std::shared_ptr _root_module{}; + std::vector> _modules{}; // TODO(Particles) No need for the unique_ptr (in theory) + std::shared_ptr _root_module{}; // Never null private: // Serialization diff --git a/src/Serialization/impl.cpp b/src/Serialization/impl.cpp index 75cb7dea..2f4a3daa 100644 --- a/src/Serialization/impl.cpp +++ b/src/Serialization/impl.cpp @@ -8,6 +8,7 @@ #include "Cool/Serialization/Serialization.h" #include "Dump/coollab_version.h" #include "Module_Compositing/Module_Compositing.h" +#include "Module_Default/Module_Default.hpp" #include "Module_FeedbackLoop/Module_FeedbackLoop.hpp" #include "Module_Particles/Module_Particles.h" #include "SNodesCategoryConfig.h" @@ -61,4 +62,5 @@ auto string_to_nodes_clipboard(std::string const& string) -> NodesClipboard SER20_REGISTER_TYPE(Lab::Module_Compositing); // NOLINT SER20_REGISTER_TYPE(Lab::Module_Particles); // NOLINT -SER20_REGISTER_TYPE(Lab::Module_FeedbackLoop); // NOLINT \ No newline at end of file +SER20_REGISTER_TYPE(Lab::Module_FeedbackLoop); // NOLINT +SER20_REGISTER_TYPE(Lab::Module_Default); // NOLINT \ No newline at end of file From e25667f7e779f964ef1dec955d0e53bc5d71c51d Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 23:11:22 +0200 Subject: [PATCH 18/31] =?UTF-8?q?=F0=9F=90=9B=20[Module=5FDefault]=20When?= =?UTF-8?q?=20creating=20one,=20forgot=20to=20add=20it=20to=20the=20list?= =?UTF-8?q?=20of=20all=20modules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ModulesGraph/ModulesGraph.cpp | 13 +++++++++---- src/ModulesGraph/ModulesGraph.h | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 474c2d0f..8428abd9 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -59,8 +59,6 @@ void ModulesGraph::check_for_rerender_and_rebuild(DataToPassToShader const& data void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, DataToGenerateShaderCode const& data_to_generate_shader_code) { check_for_rerender_and_rebuild(data_to_pass_to_shader, data_to_generate_shader_code); - if (!_root_module) - return; // TODO(Particles) Remove those _nodes_graph for (auto& module : _modules) @@ -143,10 +141,10 @@ auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerat { auto const* node = data.nodes_graph.try_get_node(root_node_id); if (!node) - return std::make_shared(texture_name_for_module(root_node_id)); // TODO(Module) Return an error message? Probably not because this is legit, eg when a feedback loop has nothing in its input pin + return create_default_module(); // TODO(Module) Return an error message? Probably not because this is legit, eg when a feedback loop has nothing in its input pin auto const* node_def = data.get_node_definition(node->id_names()); if (!node_def) - return std::make_shared(texture_name_for_module(root_node_id)); // TODO(Module) Return an error message, this shouldn't happen + return create_default_module(); // TODO(Module) Return an error message, this shouldn't happen switch (node_moduleness(*node_def)) { @@ -250,6 +248,13 @@ auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, return module; } +auto ModulesGraph::create_default_module() -> std::shared_ptr +{ + auto module = std::make_shared("texture_of_the_default_module"); + _modules.push_back(module); + return module; +} + void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const { for (auto const& module : _modules) diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index 764a646b..e1c87f3b 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -64,6 +64,7 @@ class ModulesGraph { auto create_compositing_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; auto create_particles_module(Cool::NodeId const& node_id, NodeDefinition const&, DataToGenerateShaderCode const&) -> std::shared_ptr; auto create_feedback_loop_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_default_module() -> std::shared_ptr; void render_module_ifn(Module&, DataToPassToShader const&); void check_for_rerender_and_rebuild(DataToPassToShader const&, DataToGenerateShaderCode const&); From a8378a7cba338ed91fdc7924249342d30e9e8ab7 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 23:27:31 +0200 Subject: [PATCH 19/31] =?UTF-8?q?=E2=9C=A8=20[ModulesGraph]=20Don't=20recr?= =?UTF-8?q?eate=20the=20same=20module=20twice,=20return=20the=20existing?= =?UTF-8?q?=20one?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ModulesGraph/ModulesGraph.cpp | 171 ++++++++++++++++-------------- src/ModulesGraph/ModulesGraph.h | 1 + 2 files changed, 92 insertions(+), 80 deletions(-) diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 8428abd9..dcf2abe9 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -157,102 +157,113 @@ auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerat } } +auto ModulesGraph::create_module_impl(std::string const& texture_name_in_shader, std::function()> const& make_module) -> std::shared_ptr +{ + { // If the module already exists, just return it + auto const it = std::find_if(_modules.begin(), _modules.end(), [&](auto&& module) { + return module->texture_name_in_shader() == texture_name_in_shader; + }); + if (it != _modules.end()) + return *it; + } + + // Otherwise create it and add it to the list + _modules.push_back(make_module()); + return _modules.back(); +} + auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr { - auto dependencies = std::vector>{}; - - auto const shader_code = generate_compositing_shader_code( - root_node_id, - [&](Cool::NodeId const& node_id, NodeDefinition const& node_definition) -> std::optional { - switch (node_moduleness(node_definition)) - { - case NodeModuleness::Generic: - return std::nullopt; - case NodeModuleness::Particle: - { - dependencies.push_back(create_particles_module(node_id, node_definition, data)); - return dependencies.back()->texture_name_in_shader(); - } - case NodeModuleness::FeedbackLoop: - { - dependencies.push_back(create_feedback_loop_module(node_id, data)); - return dependencies.back()->texture_name_in_shader(); - } - } - }, - [&]() { - std::vector tex_names; - tex_names.reserve(_modules.size()); - for (auto const& module : _modules) - { - tex_names.push_back(module->texture_name_in_shader()); - } - return tex_names; - }, - data - ); + auto const texture_name_in_shader = texture_name_for_module(root_node_id); + return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { + auto dependencies = std::vector>{}; + + auto const shader_code = generate_compositing_shader_code( + root_node_id, + [&](Cool::NodeId const& node_id, NodeDefinition const& node_definition) -> std::optional { + switch (node_moduleness(node_definition)) + { + case NodeModuleness::Generic: + return std::nullopt; + case NodeModuleness::Particle: + { + dependencies.push_back(create_particles_module(node_id, node_definition, data)); + return dependencies.back()->texture_name_in_shader(); + } + case NodeModuleness::FeedbackLoop: + { + dependencies.push_back(create_feedback_loop_module(node_id, data)); + return dependencies.back()->texture_name_in_shader(); + } + } + }, + [&]() { + std::vector tex_names; + tex_names.reserve(_modules.size()); + for (auto const& module : _modules) + { + tex_names.push_back(module->texture_name_in_shader()); + } + return tex_names; + }, + data + ); - auto module = std::make_shared(texture_name_for_module(root_node_id), std::move(dependencies)); - module->set_shader_code(shader_code); - _modules.push_back(module); - return module; + auto module = std::make_shared(texture_name_in_shader, std::move(dependencies)); + module->set_shader_code(shader_code); + return module; + }); } auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, NodeDefinition const& node_definition, DataToGenerateShaderCode const& data) -> std::shared_ptr { - int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; auto const texture_name_in_shader = texture_name_for_module(root_node_id); - - // TODO(FeedbackLoop) if a module with the same texture_name_in_shader already exists, return it - // if (std::none_of( - // _particles_modules.begin(), - // _particles_modules.end(), - // [&](std::unique_ptr const& node) { - // return node->texture_name_in_shader == texture_name_in_shader; - // } - // )) - - auto id_of_node_storing_particles_count = Cool::NodeId{}; // Will be initialized by generate_simulation_shader_code() - auto const simulation_shader_code = generate_simulation_shader_code( - root_node_id, - id_of_node_storing_particles_count, - dimension, - data - ); - - auto module = std::make_shared( - id_of_node_storing_particles_count, - texture_name_in_shader, - std::vector>{} // TODO(Module) Accumulate the dependencies while generating the shader code - ); - module->set_simulation_shader_code(simulation_shader_code, false, dimension); - _modules.push_back(module); - return module; + return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { + int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; + + auto id_of_node_storing_particles_count = Cool::NodeId{}; // Will be initialized by generate_simulation_shader_code() + auto const simulation_shader_code = generate_simulation_shader_code( + root_node_id, + id_of_node_storing_particles_count, + dimension, + data + ); + + auto module = std::make_shared( + id_of_node_storing_particles_count, + texture_name_in_shader, + std::vector>{} // TODO(Module) Accumulate the dependencies while generating the shader code + ); + module->set_simulation_shader_code(simulation_shader_code, false, dimension); + return module; + }); } auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, DataToGenerateShaderCode const& data) -> std::shared_ptr { - auto const* node = data.nodes_graph.try_get_node(root_node_id); - if (!node) - return nullptr; // TODO(Module) Return an error message? This should never happen - - assert(node->input_pins().size() == 1); - auto const predecessor_node_id = data.nodes_graph.find_node_connected_to_input_pin(node->input_pins()[0].id()); - auto const dependency = create_module(predecessor_node_id, data); - - auto module = std::make_shared( - texture_name_for_module(root_node_id), - std::vector>{dependency} - ); - _modules.push_back(module); - return module; + auto const texture_name_in_shader = texture_name_for_module(root_node_id); + return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { + auto const* node = data.nodes_graph.try_get_node(root_node_id); + if (!node) + return nullptr; // TODO(Module) Return an error message? This should never happen + + assert(node->input_pins().size() == 1); + auto const predecessor_node_id = data.nodes_graph.find_node_connected_to_input_pin(node->input_pins()[0].id()); + auto const dependency = create_module(predecessor_node_id, data); + + return std::make_shared( + texture_name_in_shader, + std::vector>{dependency} + ); + }); } auto ModulesGraph::create_default_module() -> std::shared_ptr { - auto module = std::make_shared("texture_of_the_default_module"); - _modules.push_back(module); - return module; + auto const texture_name_in_shader = "texture_of_the_default_module"s; + return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { + return std::make_shared(texture_name_in_shader); + }); } void ModulesGraph::imgui_windows(Ui_Ref ui, Cool::AudioManager& audio_manager, Cool::NodesLibrary const& nodes_library) const diff --git a/src/ModulesGraph/ModulesGraph.h b/src/ModulesGraph/ModulesGraph.h index e1c87f3b..915e3e23 100644 --- a/src/ModulesGraph/ModulesGraph.h +++ b/src/ModulesGraph/ModulesGraph.h @@ -61,6 +61,7 @@ class ModulesGraph { private: void recreate_all_modules(Cool::NodeId const& node_id, DataToGenerateShaderCode const&); auto create_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; + auto create_module_impl(std::string const& texture_name_in_shader, std::function()> const& make_module) -> std::shared_ptr; auto create_compositing_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; auto create_particles_module(Cool::NodeId const& node_id, NodeDefinition const&, DataToGenerateShaderCode const&) -> std::shared_ptr; auto create_feedback_loop_module(Cool::NodeId const& node_id, DataToGenerateShaderCode const&) -> std::shared_ptr; From d2d195bb0d6c8868d4e6bd7d5ec9f3eae3d32674 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Sun, 1 Sep 2024 23:28:20 +0200 Subject: [PATCH 20/31] =?UTF-8?q?=F0=9F=9A=A7=20[ModulesGraph]=20WIP=20int?= =?UTF-8?q?erpolation=5Fmode=20of=20module=20textures=20should=20be=20some?= =?UTF-8?q?tines=20linear=20and=20sometimes=20nearest=20neighbour?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp index 0e2c7f3e..167c97ae 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp @@ -134,7 +134,7 @@ void set_uniforms_for_shader_based_module( module->texture().id, Cool::TextureSamplerDescriptor{ .repeat_mode = Cool::TextureRepeatMode::None, - .interpolation_mode = glpp::Interpolation::Linear, // TODO(FeedbackLoop) The texture coming from feedback loop module must use nearest neighbour interpolation (cf // Very important. If set to linear, artifacts can appear over time (very visible with the Slit Scan effect).) + .interpolation_mode = glpp::Interpolation::NearestNeighbour, // TODO(FeedbackLoop) The texture coming from feedback loop module must use nearest neighbour interpolation (cf // Very important. If set to linear, artifacts can appear over time (very visible with the Slit Scan effect).), but the texture from other modules is probably better off using Linear ??? } ); } From 87a4ca2e0693d648ccc6bec706ddc87effa402e0 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 00:01:04 +0200 Subject: [PATCH 21/31] =?UTF-8?q?=E2=9C=A8=20[Modules]=20Only=20depend=20o?= =?UTF-8?q?n=20the=20nodes=20that=20are=20actually=20used=20in=20the=20mod?= =?UTF-8?q?ule?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit eg if there is a Midi node that is not connected to anything in the graph, now we won't think we depend on that Midi channel --- src/Meshing/gen_mesh_from_sdf.cpp | 2 +- src/Module/Module.h | 6 ++- src/Module/ModuleDependencies.cpp | 43 +++++++++++-------- src/Module/ModuleDependencies.h | 4 +- src/Module_Compositing/Module_Compositing.cpp | 5 ++- src/Module_Compositing/Module_Compositing.h | 2 +- src/Module_Default/Module_Default.cpp | 3 +- .../Module_FeedbackLoop.cpp | 3 +- src/Module_Particles/Module_Particles.cpp | 5 ++- src/Module_Particles/Module_Particles.h | 2 +- src/ModulesGraph/ModulesGraph.cpp | 32 ++++++++++++-- 11 files changed, 71 insertions(+), 36 deletions(-) diff --git a/src/Meshing/gen_mesh_from_sdf.cpp b/src/Meshing/gen_mesh_from_sdf.cpp index 8b4abdf1..06ff9d02 100644 --- a/src/Meshing/gen_mesh_from_sdf.cpp +++ b/src/Meshing/gen_mesh_from_sdf.cpp @@ -125,7 +125,7 @@ auto gen_mesh_from_sdf( { auto dependencies = ModuleDependencies{}; update_dependencies_from_shader_code(dependencies, *shader_code); - update_dependencies_from_nodes_graph(dependencies, data_to_pass_to_shader.nodes_graph); + update_dependencies_from_nodes_graph(dependencies, data_to_pass_to_shader.nodes_graph, {} /*TODO(Meshing) Properly pass the nodes that we depend on*/); set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader, module_dependencies); } diff --git a/src/Module/Module.h b/src/Module/Module.h index e9543ce9..de510fc8 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -23,10 +23,11 @@ class Module { auto operator=(Module&&) noexcept -> Module& = default; virtual ~Module() = default; - explicit Module(std::string_view name, std::string texture_name_in_shader, std::vector> dependencies) + explicit Module(std::string_view name, std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on) : _name{name} , _texture_name_in_shader{std::move(texture_name_in_shader)} , _dependencies{std::move(dependencies)} + , _nodes_that_we_depend_on{std::move(nodes_that_we_depend_on)} {} Cool::NodesGraph const* _nodes_graph{}; // TODO(Particles) Remove @@ -48,7 +49,7 @@ class Module { virtual auto texture() const -> Cool::TextureRef { return _render_target.texture_ref(); } [[nodiscard]] auto needs_to_rerender_flag() const -> Cool::DirtyFlag const& { return _needs_to_rerender_flag; } - void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) { Lab::update_dependencies_from_nodes_graph(_depends_on, graph); } + void update_dependencies_from_nodes_graph(Cool::NodesGraph const& graph) { Lab::update_dependencies_from_nodes_graph(_depends_on, graph, _nodes_that_we_depend_on); } void log_module_error(Cool::OptionalErrorMessage const&, Cool::MessageSender&) const; auto render_target() -> Cool::RenderTarget& { return _render_target; } auto render_target() const -> Cool::RenderTarget const& { return _render_target; } @@ -66,6 +67,7 @@ class Module { std::string _texture_name_in_shader{}; std::vector> _dependencies{}; + std::vector _nodes_that_we_depend_on{}; protected: ModuleDependencies _depends_on{}; diff --git a/src/Module/ModuleDependencies.cpp b/src/Module/ModuleDependencies.cpp index bca68a4e..abec83b5 100644 --- a/src/Module/ModuleDependencies.cpp +++ b/src/Module/ModuleDependencies.cpp @@ -1,4 +1,5 @@ #include "ModuleDependencies.h" +#include "Cool/Nodes/NodeId.h" #include "Cool/String/String.h" #include "Cool/TextureSource/TextureDescriptor.h" #include "Nodes/Node.h" @@ -29,31 +30,35 @@ void update_dependencies_from_shader_code(ModuleDependencies& dependencies, std: dependencies.audio_spectrum |= contains_two_or_more("_audio_spectrum", shader_code); } -void update_dependencies_from_nodes_graph(ModuleDependencies& dependencies, Cool::NodesGraph const& graph) +void update_dependencies_from_nodes_graph(ModuleDependencies& dependencies, Cool::NodesGraph const& graph, std::vector const& nodes_that_we_depend_on) { dependencies.osc_channels.clear(); dependencies.midi_channels.clear(); - graph.for_each_node([&](Node const& node) { // TODO(Modules) Only check for the nodes that are actually compiled in the graph. Otherwise we might pick up dependencies from other modules or from unused nodes. - for (auto const& value_input : node.value_inputs()) - { + for (auto const& node_id : nodes_that_we_depend_on) + { + graph.nodes().with_ref(node_id, [&](Cool::Node const& abstract_node) { + auto const& node = abstract_node.downcast(); + for (auto const& value_input : node.value_inputs()) { - auto const* osc_channel = std::get_if>(&value_input); - if (osc_channel) - dependencies.osc_channels.insert(osc_channel->value()); + { + auto const* osc_channel = std::get_if>(&value_input); + if (osc_channel) + dependencies.osc_channels.insert(osc_channel->value()); + } + { + auto const* midi_channel = std::get_if>(&value_input); + if (midi_channel) + dependencies.midi_channels.insert(midi_channel->value()); + } + { + auto const* video_file = std::get_if>(&value_input); + if (video_file) + dependencies.time = true; + } } - { - auto const* midi_channel = std::get_if>(&value_input); - if (midi_channel) - dependencies.midi_channels.insert(midi_channel->value()); - } - { - auto const* video_file = std::get_if>(&value_input); - if (video_file) - dependencies.time = true; - } - } - }); + }); + } } } // namespace Lab diff --git a/src/Module/ModuleDependencies.h b/src/Module/ModuleDependencies.h index 0ba03c6c..ed0d7fae 100644 --- a/src/Module/ModuleDependencies.h +++ b/src/Module/ModuleDependencies.h @@ -23,7 +23,7 @@ struct ModuleDependencies { auto midi_channel(Cool::MidiChannel const& midi_channel) const -> bool { return midi_channels.find(midi_channel) != midi_channels.end(); } }; -void update_dependencies_from_shader_code(ModuleDependencies& dependencies, std::string shader_code); -void update_dependencies_from_nodes_graph(ModuleDependencies& dependencies, Cool::NodesGraph const&); +void update_dependencies_from_shader_code(ModuleDependencies&, std::string shader_code); +void update_dependencies_from_nodes_graph(ModuleDependencies&, Cool::NodesGraph const&, std::vector const& nodes_that_we_depend_on); } // namespace Lab diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index 9cbd726c..2a96d3f8 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -9,11 +9,12 @@ static auto module_id() return i++; } -Module_Compositing::Module_Compositing(std::string texture_name_in_shader, std::vector> dependencies) +Module_Compositing::Module_Compositing(std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on) : Module{ fmt::format("Compositing {}", module_id()), std::move(texture_name_in_shader), - std::move(dependencies) + std::move(dependencies), + std::move(nodes_that_we_depend_on) } { } diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index 078cf717..07ab103f 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -9,7 +9,7 @@ namespace Lab { class Module_Compositing : public Module { public: Module_Compositing() = default; - Module_Compositing(std::string texture_name_in_shader, std::vector> dependencies); + Module_Compositing(std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on); Module_Compositing(Module_Compositing const&) = delete; auto operator=(Module_Compositing const&) -> Module_Compositing& = delete; // Module_Compositing(Module_Compositing&&) noexcept = default; // TODO(Modules) diff --git a/src/Module_Default/Module_Default.cpp b/src/Module_Default/Module_Default.cpp index 4d703267..ae3fe252 100644 --- a/src/Module_Default/Module_Default.cpp +++ b/src/Module_Default/Module_Default.cpp @@ -12,7 +12,8 @@ Module_Default::Module_Default(std::string texture_name_in_shader) : Module{ fmt::format("Default {}", module_id()), std::move(texture_name_in_shader), - {} + {}, // We don't depend on any module + {} // We don't depend on any node } {} diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index 30b4bf7b..1ca86cc6 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -14,7 +14,8 @@ Module_FeedbackLoop::Module_FeedbackLoop(std::string texture_name_in_shader, std : Module{ fmt::format("Feedback Loop {}", module_id()), std::move(texture_name_in_shader), - std::move(deps) + std::move(deps), + {} // We don't depend on any node } { assert(dependencies().size() == 1); diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index a0b2f534..740e77b2 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -11,11 +11,12 @@ static auto module_id() return i++; } -Module_Particles::Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies) +Module_Particles::Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on) : Module{ fmt::format("Particles {}", module_id()), std::move(texture_name_in_shader), - std::move(dependencies) + std::move(dependencies), + std::move(nodes_that_we_depend_on) } , _id_of_node_storing_particles_count{id_of_node_storing_particles_count} { diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index ee8f71ca..1cdbae2c 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -10,7 +10,7 @@ namespace Lab { class Module_Particles : public Module { public: Module_Particles() = default; - explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies); + explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on); Module_Particles(Module_Particles const&) = delete; auto operator=(Module_Particles const&) -> Module_Particles& = delete; Module_Particles(Module_Particles&&) noexcept = default; diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index dcf2abe9..d0b5914f 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -176,7 +176,8 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D { auto const texture_name_in_shader = texture_name_for_module(root_node_id); return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { - auto dependencies = std::vector>{}; + auto dependencies = std::vector>{}; + auto nodes_that_we_depend_on = std::vector{}; auto const shader_code = generate_compositing_shader_code( root_node_id, @@ -184,7 +185,10 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D switch (node_moduleness(node_definition)) { case NodeModuleness::Generic: + { + nodes_that_we_depend_on.push_back(node_id); return std::nullopt; + } case NodeModuleness::Particle: { dependencies.push_back(create_particles_module(node_id, node_definition, data)); @@ -209,7 +213,7 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D data ); - auto module = std::make_shared(texture_name_in_shader, std::move(dependencies)); + auto module = std::make_shared(texture_name_in_shader, std::move(dependencies), std::move(nodes_that_we_depend_on)); module->set_shader_code(shader_code); return module; }); @@ -219,6 +223,9 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod { auto const texture_name_in_shader = texture_name_for_module(root_node_id); return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { + auto dependencies = std::vector>{}; + auto nodes_that_we_depend_on = std::vector{}; + int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; auto id_of_node_storing_particles_count = Cool::NodeId{}; // Will be initialized by generate_simulation_shader_code() @@ -226,13 +233,30 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod root_node_id, id_of_node_storing_particles_count, dimension, - data + data, + [&](Cool::NodeId const& node_id, NodeDefinition const& node_definition) -> std::optional { + switch (node_moduleness(node_definition)) + { + case NodeModuleness::Generic: + case NodeModuleness::Particle: // TODO(Particles) This is not quite right, a particle system might depend on the image generated by another particles module + { + nodes_that_we_depend_on.push_back(node_id); + return std::nullopt; + } + case NodeModuleness::FeedbackLoop: + { + dependencies.push_back(create_feedback_loop_module(node_id, data)); + return dependencies.back()->texture_name_in_shader(); + } + } + } ); auto module = std::make_shared( id_of_node_storing_particles_count, texture_name_in_shader, - std::vector>{} // TODO(Module) Accumulate the dependencies while generating the shader code + std::move(dependencies), + std::move(nodes_that_we_depend_on) ); module->set_simulation_shader_code(simulation_shader_code, false, dimension); return module; From 85f1f96a5376f9c65f8d87ff1a000d65031fae99 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 00:15:53 +0200 Subject: [PATCH 22/31] =?UTF-8?q?=E2=9C=A8=20[Modules]=20Set=20uniforms=20?= =?UTF-8?q?only=20for=20the=20nodes=20that=20are=20actually=20used=20in=20?= =?UTF-8?q?the=20module.=20Fixes=20webcams=20triggerring=20rerenders=20eve?= =?UTF-8?q?n=20when=20they=20aren't=20actually=20used!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Meshing/gen_mesh_from_sdf.cpp | 2 +- src/Module/Module.h | 1 + .../set_uniforms_for_shader_based_module.cpp | 25 +++++++++++-------- .../set_uniforms_for_shader_based_module.hpp | 3 ++- src/Module_Compositing/Module_Compositing.cpp | 2 +- src/Module_Particles/Module_Particles.cpp | 4 +-- .../generate_simulation_shader_code.cpp | 7 +++--- .../generate_simulation_shader_code.h | 4 ++- src/Project.cpp | 4 +-- 9 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/Meshing/gen_mesh_from_sdf.cpp b/src/Meshing/gen_mesh_from_sdf.cpp index 06ff9d02..34fc9ed2 100644 --- a/src/Meshing/gen_mesh_from_sdf.cpp +++ b/src/Meshing/gen_mesh_from_sdf.cpp @@ -126,7 +126,7 @@ auto gen_mesh_from_sdf( auto dependencies = ModuleDependencies{}; update_dependencies_from_shader_code(dependencies, *shader_code); update_dependencies_from_nodes_graph(dependencies, data_to_pass_to_shader.nodes_graph, {} /*TODO(Meshing) Properly pass the nodes that we depend on*/); - set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader, module_dependencies); + set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader, module_dependencies, {} /*TODO(Meshing) Properly pass the nodes that we depend on*/); } meshing_compute_shader->compute(meshing_settings.samples_count); diff --git a/src/Module/Module.h b/src/Module/Module.h index de510fc8..441cd706 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -56,6 +56,7 @@ class Module { [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } [[nodiscard]] auto texture_name_in_shader() const -> std::string const& { return _texture_name_in_shader; } [[nodiscard]] auto dependencies() const -> std::vector> const& { return _dependencies; } + [[nodiscard]] auto nodes_that_we_depend_on() const -> std::vector const& { return _nodes_that_we_depend_on; } private: virtual void render(DataToPassToShader const&) = 0; diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp index 167c97ae..f392e30b 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp @@ -92,7 +92,8 @@ void set_uniforms_for_shader_based_module( Cool::OpenGL::Shader const& shader, ModuleDependencies const& depends_on, DataToPassToShader const& data, - std::vector> const& module_dependencies + std::vector> const& module_dependencies, + std::vector const& nodes_that_we_depend_on ) { shader.bind(); @@ -117,15 +118,19 @@ void set_uniforms_for_shader_based_module( Cool::CameraShaderU::set_uniform(shader, data.system_values.camera_3D, data.system_values.aspect_ratio()); - data.nodes_graph.for_each_node([&](Node const& node) { // TODO(Modules) Only set it for nodes that are actually compiled in the graph. Otherwise causes problems, e.g. if a webcam node is here but unused, we still request webcam capture every frame, which forces us to rerender every frame for no reason + it does extra work. // TODO(Modules) Each module should store a list of its inputs, so that we can set them there - for (auto const& value_input : node.value_inputs()) - { - std::visit([&](auto&& value_input) { - set_uniform(shader, value_input); - }, - value_input); - } - }); + for (auto const& node_id : nodes_that_we_depend_on) + { + data.nodes_graph.nodes().with_ref(node_id, [&](Cool::Node const& abstract_node) { + auto const& node = abstract_node.downcast(); + for (auto const& value_input : node.value_inputs()) + { + std::visit([&](auto&& value_input) { + set_uniform(shader, value_input); + }, + value_input); + } + }); + } for (auto const& module : module_dependencies) { diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp index 7792cb68..091c0e6e 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp @@ -11,7 +11,8 @@ void set_uniforms_for_shader_based_module( Cool::OpenGL::Shader const&, ModuleDependencies const&, DataToPassToShader const&, - std::vector> const& module_dependencies + std::vector> const& module_dependencies, + std::vector const& nodes_that_we_depend_on ); } // namespace Lab \ No newline at end of file diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index 2a96d3f8..45344f6a 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -71,7 +71,7 @@ void Module_Compositing::render(DataToPassToShader const& data) render_target().render([&]() { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data, dependencies()); + set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data, dependencies(), nodes_that_we_depend_on()); _pipeline.draw(); }); } diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index 740e77b2..c253e42f 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -139,7 +139,7 @@ void Module_Particles::update_particles(DataToPassToShader const& data) _particle_system->simulation_shader().bind(); _particle_system->simulation_shader().set_uniform("_force_init_particles", _force_init_particles); - set_uniforms_for_shader_based_module(_particle_system->simulation_shader(), _depends_on, data, {}); // TODO(Module) We need to access the modules that this module depends on + set_uniforms_for_shader_based_module(_particle_system->simulation_shader(), _depends_on, data, dependencies(), nodes_that_we_depend_on()); _particle_system->update(); _force_init_particles = false; _needs_to_update_particles = false; @@ -171,7 +171,7 @@ void Module_Particles::render(DataToPassToShader const& data) render_target().render([&]() { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data, dependencies()); + set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data, dependencies(), nodes_that_we_depend_on()); auto const view_proj_matrix_2D_mat3 = data.system_values.camera_2D_view_projection_matrix(); auto const view_proj_matrix_2D_mat4 = glm::mat4{ diff --git a/src/Module_Particles/generate_simulation_shader_code.cpp b/src/Module_Particles/generate_simulation_shader_code.cpp index 04660890..fd2f80fd 100644 --- a/src/Module_Particles/generate_simulation_shader_code.cpp +++ b/src/Module_Particles/generate_simulation_shader_code.cpp @@ -10,7 +10,8 @@ auto generate_simulation_shader_code( Cool::NodeId const& root_node_id, Cool::NodeId& id_of_node_storing_particles_count, int dimension, - DataToGenerateShaderCode const& data + DataToGenerateShaderCode const& data, + MaybeGenerateModule const& maybe_generate_module ) -> tl::expected { using fmt::literals::operator""_a; @@ -142,11 +143,11 @@ void cool_main() .arity = 1, }; - auto const node_definition_callback = [&](auto const& node_id, auto const&) { + auto const node_definition_callback = [&](Cool::NodeId const& node_id, NodeDefinition const& node_definition) { auto const* maybe_node = data.nodes_graph.try_get_node(node_id); if (maybe_node && maybe_node->particles_count().has_value()) id_of_node_storing_particles_count = node_id; - return std::nullopt; + return maybe_generate_module(node_id, node_definition); }; return generate_shader_code( diff --git a/src/Module_Particles/generate_simulation_shader_code.h b/src/Module_Particles/generate_simulation_shader_code.h index 05c86b76..6c821809 100644 --- a/src/Module_Particles/generate_simulation_shader_code.h +++ b/src/Module_Particles/generate_simulation_shader_code.h @@ -1,5 +1,6 @@ #pragma once #include "Module/ShaderBased/DataToGenerateShaderCode.hpp" +#include "Nodes/MaybeGenerateModule.h" namespace Lab { @@ -7,7 +8,8 @@ auto generate_simulation_shader_code( Cool::NodeId const& root_node_id, Cool::NodeId& id_of_node_storing_particles_count, int dimension, - DataToGenerateShaderCode const& + DataToGenerateShaderCode const&, + MaybeGenerateModule const& ) -> tl::expected; } // namespace Lab diff --git a/src/Project.cpp b/src/Project.cpp index 4ba7314f..50b1d6d9 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -4,8 +4,8 @@ namespace Lab { Project::Project() - : camera_3D_manager{"3D Camera", modules_graph->rerender_all_flag()} - , camera_2D_manager{"2D Camera", modules_graph->rerender_all_flag()} + : camera_3D_manager{"3D Camera", modules_graph->rerender_all_flag()} // TODO(Modules) Actually, some modules don't depend on the camera, so we shouldn't rerender everything + , camera_2D_manager{"2D Camera", modules_graph->rerender_all_flag()} // TODO(Modules) Actually, some modules don't depend on the camera, so we shouldn't rerender everything { } From d5e484897e573446d9a20f8615e0b7d7dfe719a1 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 00:18:43 +0200 Subject: [PATCH 23/31] =?UTF-8?q?=F0=9F=92=A9=20[Meshing]=20Consider=20tha?= =?UTF-8?q?t=20we=20depend=20on=20all=20the=20nodes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Meshing/gen_mesh_from_sdf.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Meshing/gen_mesh_from_sdf.cpp b/src/Meshing/gen_mesh_from_sdf.cpp index 34fc9ed2..fedca27f 100644 --- a/src/Meshing/gen_mesh_from_sdf.cpp +++ b/src/Meshing/gen_mesh_from_sdf.cpp @@ -123,10 +123,13 @@ auto gen_mesh_from_sdf( meshing_compute_shader->set_uniform("_step_size", meshing_settings.step_size().x); { - auto dependencies = ModuleDependencies{}; + auto dependencies = ModuleDependencies{}; + auto nodes_that_we_depend_on = std::vector{}; // TODO(Meshing) Properly compute the nodes that we depend on + for (auto const& [id, _] : data_to_pass_to_shader.nodes_graph.nodes()) + nodes_that_we_depend_on.emplace_back(id); update_dependencies_from_shader_code(dependencies, *shader_code); - update_dependencies_from_nodes_graph(dependencies, data_to_pass_to_shader.nodes_graph, {} /*TODO(Meshing) Properly pass the nodes that we depend on*/); - set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader, module_dependencies, {} /*TODO(Meshing) Properly pass the nodes that we depend on*/); + update_dependencies_from_nodes_graph(dependencies, data_to_pass_to_shader.nodes_graph, nodes_that_we_depend_on); + set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader, module_dependencies, nodes_that_we_depend_on); } meshing_compute_shader->compute(meshing_settings.samples_count); From c27864c6c0f35016f4f8d9e10aa5c42e433f0c4c Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 12:08:14 +0200 Subject: [PATCH 24/31] =?UTF-8?q?=E2=AC=86=20[Cool]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cool | 2 +- src/App.cpp | 8 ++++---- src/App.h | 11 +++++------ 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Cool b/Cool index 42269316..4ad11857 160000 --- a/Cool +++ b/Cool @@ -1 +1 @@ -Subproject commit 4226931694ce654291af5295e891921765a69855 +Subproject commit 4ad1185714fc03f7f8bb05192ea1d81f0ccc7fb9 diff --git a/src/App.cpp b/src/App.cpp index 78afea82..235b6251 100644 --- a/src/App.cpp +++ b/src/App.cpp @@ -52,13 +52,13 @@ namespace Lab { App::App(Cool::WindowManager& windows, Cool::ViewsManager& views) : _main_window{windows.main_window()} - , _output_view{views.make_view(Cool::ViewCreationParams{ + , _output_view{views.make_view(Cool::ViewCreationParams{ .name = Cool::icon_fmt("Output", ICOMOON_IMAGE), .is_output_view = true, .is_closable = true, .start_open = false, })} - , _preview_view{views.make_view( + , _preview_view{views.make_view( _output_view, Cool::ViewCreationParams{ .name = Cool::icon_fmt("View", ICOMOON_IMAGE), @@ -152,7 +152,7 @@ void App::update() if (!_project.exporter.is_exporting()) { _project.clock.update(); - auto const render_size = render_view().desired_image_size(_project.view_constraint); // TODO(JF) Integrate the notion of View Constraint inside the RenderView ? But that's maybe too much coupling + auto const render_size = render_view().desired_image_size(_project.view_constraint); // TODO(JF) Integrate the notion of View Constraint inside the TextureView ? But that's may be too much coupling polaroid().render(render_size, _project.clock.time(), _project.clock.delta_time()); } else @@ -199,7 +199,7 @@ void App::request_rerender() // TODO(Modules) Sometimes we don't need to call th _project.modules_graph->request_rerender_all(); } -auto App::render_view() -> Cool::RenderView& +auto App::render_view() -> Cool::TextureView& { if (_output_view.is_open()) return _output_view; diff --git a/src/App.h b/src/App.h index c33f688b..31052d28 100644 --- a/src/App.h +++ b/src/App.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -35,8 +34,8 @@ #include "Cool/StrongTypes/Camera2D.h" #include "Cool/Time/Clock_Realtime.h" #include "Cool/Tips/TipsManager.h" -#include "Cool/View/ForwardingOrRenderView.h" -#include "Cool/View/RenderView.h" +#include "Cool/View/ForwardingOrTextureView.hpp" +#include "Cool/View/TextureView.hpp" #include "Cool/View/ViewsManager.h" #include "Cool/Webcam/WebcamsConfigs.h" #include "Cool/Window/WindowManager.h" @@ -81,7 +80,7 @@ class App : public Cool::IApp { void render(img::Size size, Cool::Time time, Cool::Time delta_time); void on_time_changed(); void on_time_reset(); - auto render_view() -> Cool::RenderView&; + auto render_view() -> Cool::TextureView&; void check_inputs(); void check_inputs__history(); @@ -123,8 +122,8 @@ class App : public Cool::IApp { private: Cool::Window& _main_window; - Cool::RenderView& _output_view; - Cool::ForwardingOrRenderView& _preview_view; // Must be after _output_view because it stores a reference to it + Cool::TextureView& _output_view; + Cool::ForwardingOrTextureView& _preview_view; // Must be after _output_view because it stores a reference to it Project _project{}; std::optional _current_project_path{}; RecentlyOpened _recently_opened_projects{}; From ded35589a660dfcada908812557db968b748afe9 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 18:53:03 +0200 Subject: [PATCH 25/31] =?UTF-8?q?=F0=9F=A7=BC=20[Feedback=20Loop]=20Cleanu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ACK LOOP.clbnode => Feedback (One frame delay).clbnode} | 0 Nodes/10 Image/Feedback (Previous frame).clbnode | 7 ------- src/Module/ModuleDependencies.cpp | 3 +-- src/Module/ShaderBased/generate_shader_code.cpp | 1 - src/ModulesGraph/ModulesGraph.cpp | 2 +- 5 files changed, 2 insertions(+), 11 deletions(-) rename Nodes/10 Image/{FEEDBACK LOOP.clbnode => Feedback (One frame delay).clbnode} (100%) delete mode 100644 Nodes/10 Image/Feedback (Previous frame).clbnode diff --git a/Nodes/10 Image/FEEDBACK LOOP.clbnode b/Nodes/10 Image/Feedback (One frame delay).clbnode similarity index 100% rename from Nodes/10 Image/FEEDBACK LOOP.clbnode rename to Nodes/10 Image/Feedback (One frame delay).clbnode diff --git a/Nodes/10 Image/Feedback (Previous frame).clbnode b/Nodes/10 Image/Feedback (Previous frame).clbnode deleted file mode 100644 index b6516d31..00000000 --- a/Nodes/10 Image/Feedback (Previous frame).clbnode +++ /dev/null @@ -1,7 +0,0 @@ -// To learn how to write nodes, see https://coollab-art.com/Tutorials/Writing%20Nodes/Intro - -sRGB_StraightA main(UV uv) -{ - uv = unnormalize_uv(to_view_space(uv)); - return texture(_previous_frame_texture, uv); -} \ No newline at end of file diff --git a/src/Module/ModuleDependencies.cpp b/src/Module/ModuleDependencies.cpp index abec83b5..e2efc89e 100644 --- a/src/Module/ModuleDependencies.cpp +++ b/src/Module/ModuleDependencies.cpp @@ -20,8 +20,7 @@ void update_dependencies_from_shader_code(ModuleDependencies& dependencies, std: { shader_code = Cool::String::remove_comments(shader_code); - dependencies.time |= contains_two_or_more("_time", shader_code) - || contains_two_or_more("_previous_frame_texture", shader_code); + dependencies.time |= contains_two_or_more("_time", shader_code); dependencies.last_midi_button_pressed |= contains_two_or_more("_last_midi_button_pressed", shader_code) || contains_two_or_more("_last_last_midi_button_pressed", shader_code); dependencies.time_since_last_midi_button_pressed |= contains_two_or_more("_time_since_last_midi_button_pressed", shader_code); diff --git a/src/Module/ShaderBased/generate_shader_code.cpp b/src/Module/ShaderBased/generate_shader_code.cpp index 3863d406..81ed22f2 100644 --- a/src/Module/ShaderBased/generate_shader_code.cpp +++ b/src/Module/ShaderBased/generate_shader_code.cpp @@ -97,7 +97,6 @@ uniform sampler1D _audio_spectrum; uniform sampler1D _audio_waveform; uniform mat3 _camera2D_transform; uniform mat3 _camera2D_view; -uniform sampler2D _previous_frame_texture; uniform sampler2D mixbox_lut; // The uniform must have this exact name that mixbox.glsl expects. {modules_textures_uniforms} diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index d0b5914f..496ed6e6 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -118,7 +118,7 @@ enum class NodeModuleness { static auto is_feedback_loop(NodeDefinition const& node_definition) { - return node_definition.name() == "FEEDBACK LOOP"; + return node_definition.name() == "Feedback (One frame delay)"; } static auto node_moduleness(NodeDefinition const& node_definition) From 5dae953de3b198375b229b1cfc9732abb0d44055 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 19:18:22 +0200 Subject: [PATCH 26/31] =?UTF-8?q?=F0=9F=A7=BC=20[Feedback=20Loop]=20Cleanu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module/Module.cpp | 2 +- src/Module/Module.h | 8 +++--- src/Module_Compositing/Module_Compositing.cpp | 6 ++-- src/Module_Compositing/Module_Compositing.h | 2 +- .../Module_FeedbackLoop.cpp | 10 +++---- .../Module_FeedbackLoop.hpp | 2 +- src/Module_Particles/Module_Particles.cpp | 8 +++--- src/Module_Particles/Module_Particles.h | 2 +- src/ModulesGraph/ModulesGraph.cpp | 28 +++++++++---------- 9 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/Module/Module.cpp b/src/Module/Module.cpp index ddcc9b87..c2fd0989 100644 --- a/src/Module/Module.cpp +++ b/src/Module/Module.cpp @@ -15,7 +15,7 @@ void Module::log_module_error(Cool::OptionalErrorMessage const& maybe_err, Cool: auto Module::needs_to_rerender() const -> bool { - return _needs_to_rerender_flag.is_dirty() || std::any_of(_dependencies.begin(), _dependencies.end(), [&](auto&& module) { + return _needs_to_rerender_flag.is_dirty() || std::any_of(_modules_that_we_depend_on.begin(), _modules_that_we_depend_on.end(), [&](auto&& module) { return module->needs_to_rerender(); }); }; diff --git a/src/Module/Module.h b/src/Module/Module.h index 441cd706..58870675 100644 --- a/src/Module/Module.h +++ b/src/Module/Module.h @@ -23,10 +23,10 @@ class Module { auto operator=(Module&&) noexcept -> Module& = default; virtual ~Module() = default; - explicit Module(std::string_view name, std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on) + explicit Module(std::string_view name, std::string texture_name_in_shader, std::vector> modules_that_we_depend_on, std::vector nodes_that_we_depend_on) : _name{name} , _texture_name_in_shader{std::move(texture_name_in_shader)} - , _dependencies{std::move(dependencies)} + , _modules_that_we_depend_on{std::move(modules_that_we_depend_on)} , _nodes_that_we_depend_on{std::move(nodes_that_we_depend_on)} {} @@ -55,7 +55,7 @@ class Module { auto render_target() const -> Cool::RenderTarget const& { return _render_target; } [[nodiscard]] auto depends_on() const -> ModuleDependencies const& { return _depends_on; } [[nodiscard]] auto texture_name_in_shader() const -> std::string const& { return _texture_name_in_shader; } - [[nodiscard]] auto dependencies() const -> std::vector> const& { return _dependencies; } + [[nodiscard]] auto modules_that_we_depend_on() const -> std::vector> const& { return _modules_that_we_depend_on; } [[nodiscard]] auto nodes_that_we_depend_on() const -> std::vector const& { return _nodes_that_we_depend_on; } private: @@ -67,7 +67,7 @@ class Module { Cool::RenderTarget _render_target{}; std::string _texture_name_in_shader{}; - std::vector> _dependencies{}; + std::vector> _modules_that_we_depend_on{}; std::vector _nodes_that_we_depend_on{}; protected: diff --git a/src/Module_Compositing/Module_Compositing.cpp b/src/Module_Compositing/Module_Compositing.cpp index 45344f6a..ca1660f0 100644 --- a/src/Module_Compositing/Module_Compositing.cpp +++ b/src/Module_Compositing/Module_Compositing.cpp @@ -9,11 +9,11 @@ static auto module_id() return i++; } -Module_Compositing::Module_Compositing(std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on) +Module_Compositing::Module_Compositing(std::string texture_name_in_shader, std::vector> modules_that_we_depend_on, std::vector nodes_that_we_depend_on) : Module{ fmt::format("Compositing {}", module_id()), std::move(texture_name_in_shader), - std::move(dependencies), + std::move(modules_that_we_depend_on), std::move(nodes_that_we_depend_on) } { @@ -71,7 +71,7 @@ void Module_Compositing::render(DataToPassToShader const& data) render_target().render([&]() { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data, dependencies(), nodes_that_we_depend_on()); + set_uniforms_for_shader_based_module(*_pipeline.shader(), _depends_on, data, modules_that_we_depend_on(), nodes_that_we_depend_on()); _pipeline.draw(); }); } diff --git a/src/Module_Compositing/Module_Compositing.h b/src/Module_Compositing/Module_Compositing.h index 07ab103f..75ead3ad 100644 --- a/src/Module_Compositing/Module_Compositing.h +++ b/src/Module_Compositing/Module_Compositing.h @@ -9,7 +9,7 @@ namespace Lab { class Module_Compositing : public Module { public: Module_Compositing() = default; - Module_Compositing(std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on); + Module_Compositing(std::string texture_name_in_shader, std::vector> modules_that_we_depend_on, std::vector nodes_that_we_depend_on); Module_Compositing(Module_Compositing const&) = delete; auto operator=(Module_Compositing const&) -> Module_Compositing& = delete; // Module_Compositing(Module_Compositing&&) noexcept = default; // TODO(Modules) diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index 1ca86cc6..79c20868 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -10,16 +10,14 @@ static auto module_id() return i++; } -Module_FeedbackLoop::Module_FeedbackLoop(std::string texture_name_in_shader, std::vector> deps) +Module_FeedbackLoop::Module_FeedbackLoop(std::string texture_name_in_shader, std::shared_ptr module_that_we_depend_on) : Module{ fmt::format("Feedback Loop {}", module_id()), std::move(texture_name_in_shader), - std::move(deps), + {std::move(module_that_we_depend_on)}, {} // We don't depend on any node } -{ - assert(dependencies().size() == 1); -} +{} void Module_FeedbackLoop::on_time_reset() { @@ -41,7 +39,7 @@ void Module_FeedbackLoop::render(DataToPassToShader const& data) rt.render([&]() { // TODO(WebGPU) use a texture copy operation instead, it will be more efficient Cool::copy_tex_pipeline().shader()->bind(); - Cool::copy_tex_pipeline().shader()->set_uniform_texture("tex_to_copy", dependencies()[0]->texture().id); + Cool::copy_tex_pipeline().shader()->set_uniform_texture("tex_to_copy", modules_that_we_depend_on()[0]->texture().id); glDisable(GL_BLEND); Cool::copy_tex_pipeline().draw(); glEnable(GL_BLEND); diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index 9272fe68..7c799fb5 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -6,7 +6,7 @@ namespace Lab { class Module_FeedbackLoop : public Module { public: Module_FeedbackLoop() = default; - Module_FeedbackLoop(std::string texture_name_in_shader, std::vector> deps); + Module_FeedbackLoop(std::string texture_name_in_shader, std::shared_ptr module_that_we_depend_on); Module_FeedbackLoop(Module_FeedbackLoop const&) = delete; auto operator=(Module_FeedbackLoop const&) -> Module_FeedbackLoop& = delete; Module_FeedbackLoop(Module_FeedbackLoop&&) noexcept = default; diff --git a/src/Module_Particles/Module_Particles.cpp b/src/Module_Particles/Module_Particles.cpp index c253e42f..0e55aef6 100644 --- a/src/Module_Particles/Module_Particles.cpp +++ b/src/Module_Particles/Module_Particles.cpp @@ -11,11 +11,11 @@ static auto module_id() return i++; } -Module_Particles::Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on) +Module_Particles::Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> modules_that_we_depend_on, std::vector nodes_that_we_depend_on) : Module{ fmt::format("Particles {}", module_id()), std::move(texture_name_in_shader), - std::move(dependencies), + std::move(modules_that_we_depend_on), std::move(nodes_that_we_depend_on) } , _id_of_node_storing_particles_count{id_of_node_storing_particles_count} @@ -139,7 +139,7 @@ void Module_Particles::update_particles(DataToPassToShader const& data) _particle_system->simulation_shader().bind(); _particle_system->simulation_shader().set_uniform("_force_init_particles", _force_init_particles); - set_uniforms_for_shader_based_module(_particle_system->simulation_shader(), _depends_on, data, dependencies(), nodes_that_we_depend_on()); + set_uniforms_for_shader_based_module(_particle_system->simulation_shader(), _depends_on, data, modules_that_we_depend_on(), nodes_that_we_depend_on()); _particle_system->update(); _force_init_particles = false; _needs_to_update_particles = false; @@ -171,7 +171,7 @@ void Module_Particles::render(DataToPassToShader const& data) render_target().render([&]() { glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data, dependencies(), nodes_that_we_depend_on()); + set_uniforms_for_shader_based_module(_particle_system->render_shader(), _depends_on, data, modules_that_we_depend_on(), nodes_that_we_depend_on()); auto const view_proj_matrix_2D_mat3 = data.system_values.camera_2D_view_projection_matrix(); auto const view_proj_matrix_2D_mat4 = glm::mat4{ diff --git a/src/Module_Particles/Module_Particles.h b/src/Module_Particles/Module_Particles.h index 1cdbae2c..290a400f 100644 --- a/src/Module_Particles/Module_Particles.h +++ b/src/Module_Particles/Module_Particles.h @@ -10,7 +10,7 @@ namespace Lab { class Module_Particles : public Module { public: Module_Particles() = default; - explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> dependencies, std::vector nodes_that_we_depend_on); + explicit Module_Particles(Cool::NodeId const& id_of_node_storing_particles_count, std::string texture_name_in_shader, std::vector> modules_that_we_depend_on, std::vector nodes_that_we_depend_on); Module_Particles(Module_Particles const&) = delete; auto operator=(Module_Particles const&) -> Module_Particles& = delete; Module_Particles(Module_Particles&&) noexcept = default; diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 496ed6e6..7c95db8f 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -76,7 +76,7 @@ void ModulesGraph::render_module_ifn(Module& module, DataToPassToShader const& d return; // Render all the dependencies first, so that we can use their textures - for (auto const& prev : module.dependencies()) + for (auto const& prev : module.modules_that_we_depend_on()) render_module_ifn(*prev, data); module.do_rendering(data); @@ -176,8 +176,8 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D { auto const texture_name_in_shader = texture_name_for_module(root_node_id); return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { - auto dependencies = std::vector>{}; - auto nodes_that_we_depend_on = std::vector{}; + auto modules_that_we_depend_on = std::vector>{}; + auto nodes_that_we_depend_on = std::vector{}; auto const shader_code = generate_compositing_shader_code( root_node_id, @@ -191,13 +191,13 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D } case NodeModuleness::Particle: { - dependencies.push_back(create_particles_module(node_id, node_definition, data)); - return dependencies.back()->texture_name_in_shader(); + modules_that_we_depend_on.push_back(create_particles_module(node_id, node_definition, data)); + return modules_that_we_depend_on.back()->texture_name_in_shader(); } case NodeModuleness::FeedbackLoop: { - dependencies.push_back(create_feedback_loop_module(node_id, data)); - return dependencies.back()->texture_name_in_shader(); + modules_that_we_depend_on.push_back(create_feedback_loop_module(node_id, data)); + return modules_that_we_depend_on.back()->texture_name_in_shader(); } } }, @@ -213,7 +213,7 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D data ); - auto module = std::make_shared(texture_name_in_shader, std::move(dependencies), std::move(nodes_that_we_depend_on)); + auto module = std::make_shared(texture_name_in_shader, std::move(modules_that_we_depend_on), std::move(nodes_that_we_depend_on)); module->set_shader_code(shader_code); return module; }); @@ -223,8 +223,8 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod { auto const texture_name_in_shader = texture_name_for_module(root_node_id); return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { - auto dependencies = std::vector>{}; - auto nodes_that_we_depend_on = std::vector{}; + auto modules_that_we_depend_on = std::vector>{}; + auto nodes_that_we_depend_on = std::vector{}; int const dimension = is_particle_3D(node_definition.signature()) ? 3 : 2; @@ -245,8 +245,8 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod } case NodeModuleness::FeedbackLoop: { - dependencies.push_back(create_feedback_loop_module(node_id, data)); - return dependencies.back()->texture_name_in_shader(); + modules_that_we_depend_on.push_back(create_feedback_loop_module(node_id, data)); + return modules_that_we_depend_on.back()->texture_name_in_shader(); } } } @@ -255,7 +255,7 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod auto module = std::make_shared( id_of_node_storing_particles_count, texture_name_in_shader, - std::move(dependencies), + std::move(modules_that_we_depend_on), std::move(nodes_that_we_depend_on) ); module->set_simulation_shader_code(simulation_shader_code, false, dimension); @@ -277,7 +277,7 @@ auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, return std::make_shared( texture_name_in_shader, - std::vector>{dependency} + dependency ); }); } From 17244fe20512ebb6db0e68e91dab89724ccc49da Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 20:03:19 +0200 Subject: [PATCH 27/31] =?UTF-8?q?=F0=9F=A7=BC=20[Feedback=20Loop]=20Cleanu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShaderBased/set_uniforms_for_shader_based_module.cpp | 4 ++-- .../ShaderBased/set_uniforms_for_shader_based_module.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp index f392e30b..aaf0b61e 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.cpp @@ -92,7 +92,7 @@ void set_uniforms_for_shader_based_module( Cool::OpenGL::Shader const& shader, ModuleDependencies const& depends_on, DataToPassToShader const& data, - std::vector> const& module_dependencies, + std::vector> const& modules_that_we_depend_on, std::vector const& nodes_that_we_depend_on ) { @@ -132,7 +132,7 @@ void set_uniforms_for_shader_based_module( }); } - for (auto const& module : module_dependencies) + for (auto const& module : modules_that_we_depend_on) { shader.set_uniform_texture( module->texture_name_in_shader(), diff --git a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp index 091c0e6e..16528022 100644 --- a/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp +++ b/src/Module/ShaderBased/set_uniforms_for_shader_based_module.hpp @@ -11,7 +11,7 @@ void set_uniforms_for_shader_based_module( Cool::OpenGL::Shader const&, ModuleDependencies const&, DataToPassToShader const&, - std::vector> const& module_dependencies, + std::vector> const& modules_that_we_depend_on, std::vector const& nodes_that_we_depend_on ); From d39bddd0930e86e02704c6bebf4cbfcae706f018 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 23:51:32 +0200 Subject: [PATCH 28/31] =?UTF-8?q?=F0=9F=A7=BC=20[Feedback=20Loop]=20Cleanu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module_FeedbackLoop/Module_FeedbackLoop.cpp | 6 +++--- src/Module_FeedbackLoop/Module_FeedbackLoop.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index 79c20868..330d805c 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -26,15 +26,15 @@ void Module_FeedbackLoop::on_time_reset() auto Module_FeedbackLoop::texture() const -> Cool::TextureRef { - auto const b = _renders_count < 2 ? !_bob : _bob; + auto const b = _renders_count < 2 ? !_render_target_ping_pong : _render_target_ping_pong; return b ? _render_target.texture_ref() : render_target().texture_ref(); } void Module_FeedbackLoop::render(DataToPassToShader const& data) { - _bob = !_bob; + _render_target_ping_pong = !_render_target_ping_pong; _renders_count++; - auto& rt = _bob ? render_target() : _render_target; + auto& rt = _render_target_ping_pong ? render_target() : _render_target; rt.set_size(data.system_values.render_target_size); rt.render([&]() { // TODO(WebGPU) use a texture copy operation instead, it will be more efficient diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp index 7c799fb5..1ca32136 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.hpp @@ -23,7 +23,7 @@ class Module_FeedbackLoop : public Module { private: Cool::RenderTarget _render_target{}; - bool _bob{false}; + bool _render_target_ping_pong{false}; int _renders_count{0}; bool _rerender_next_frame{false}; bool _rerender_this_frame{false}; From 1601a1dc9a015befcea79c800bf0f7621e552635 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 23:54:26 +0200 Subject: [PATCH 29/31] =?UTF-8?q?=F0=9F=9A=A8=20Fix=20warnings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ModulesGraph/ModulesGraph.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 7c95db8f..5607c5e0 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -155,6 +155,8 @@ auto ModulesGraph::create_module(Cool::NodeId const& root_node_id, DataToGenerat case NodeModuleness::FeedbackLoop: return create_feedback_loop_module(root_node_id, data); } + assert(false); + return create_default_module(); } auto ModulesGraph::create_module_impl(std::string const& texture_name_in_shader, std::function()> const& make_module) -> std::shared_ptr @@ -200,6 +202,8 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D return modules_that_we_depend_on.back()->texture_name_in_shader(); } } + assert(false); + return std::nullopt; }, [&]() { std::vector tex_names; @@ -249,6 +253,8 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod return modules_that_we_depend_on.back()->texture_name_in_shader(); } } + assert(false); + return std::nullopt; } ); From e2e22c6a6279d165237af0170cf2c4a554f9f597 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Mon, 2 Sep 2024 23:59:10 +0200 Subject: [PATCH 30/31] =?UTF-8?q?=F0=9F=A7=BC=20[Feedback=20Loop]=20Cleanu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Module_FeedbackLoop/Module_FeedbackLoop.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp index 330d805c..2af23d34 100644 --- a/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp +++ b/src/Module_FeedbackLoop/Module_FeedbackLoop.cpp @@ -1,6 +1,5 @@ #include "Module_FeedbackLoop.hpp" #include "Cool/Gpu/OpenGL/copy_tex_pipeline.hpp" -#include "Cool/Log/ToUser.h" namespace Lab { @@ -26,8 +25,8 @@ void Module_FeedbackLoop::on_time_reset() auto Module_FeedbackLoop::texture() const -> Cool::TextureRef { - auto const b = _renders_count < 2 ? !_render_target_ping_pong : _render_target_ping_pong; - return b ? _render_target.texture_ref() : render_target().texture_ref(); + auto const b = _renders_count < 2 ? !_render_target_ping_pong : _render_target_ping_pong; // During the first frame, the previous frame texture is not init, so use the current frame texture instead + return (b ? _render_target : render_target()).texture_ref(); } void Module_FeedbackLoop::render(DataToPassToShader const& data) @@ -49,7 +48,7 @@ void Module_FeedbackLoop::render(DataToPassToShader const& data) void Module_FeedbackLoop::before_module_graph_renders() { _rerender_this_frame = _rerender_next_frame; - _rerender_next_frame = Module::needs_to_rerender(); + _rerender_next_frame = Module::needs_to_rerender(); // Make sure we will also render one frame after our dependencies rendered } auto Module_FeedbackLoop::needs_to_rerender() const -> bool From ec15d3cdcda16d9a083183856c43ef570de66f75 Mon Sep 17 00:00:00 2001 From: Jules Fouchy Date: Tue, 3 Sep 2024 00:24:21 +0200 Subject: [PATCH 31/31] =?UTF-8?q?=F0=9F=A7=BC=20[Modules=20Graph]=20Cleanu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ModulesGraph/ModulesGraph.cpp | 36 ++++++++++++++----------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/src/ModulesGraph/ModulesGraph.cpp b/src/ModulesGraph/ModulesGraph.cpp index 5607c5e0..1e86e75e 100644 --- a/src/ModulesGraph/ModulesGraph.cpp +++ b/src/ModulesGraph/ModulesGraph.cpp @@ -5,8 +5,6 @@ #include #include #include "Cool/Audio/AudioManager.h" -#include "Cool/Camera/CameraShaderU.h" -#include "Cool/Gpu/RenderTarget.h" #include "Cool/Nodes/NodesLibrary.h" #include "Cool/StrongTypes/Camera2D.h" #include "Module_Compositing/Module_Compositing.h" @@ -15,7 +13,6 @@ #include "Module_FeedbackLoop/Module_FeedbackLoop.hpp" #include "Module_Particles/Module_Particles.h" #include "Module_Particles/generate_simulation_shader_code.h" -#include "ModulesGraph/ModulesGraph.h" #include "Nodes/valid_glsl.h" #include "UI/imgui_show.h" @@ -23,7 +20,7 @@ namespace Lab { void ModulesGraph::update() { - for (auto& module : _modules) + for (auto const& module : _modules) { module->_nodes_graph = &_nodes_editor.graph(); module->update(); @@ -48,9 +45,11 @@ void ModulesGraph::check_for_rerender_and_rebuild(DataToPassToShader const& data for (auto const& module : _modules) { + // Modules that depend on time_since_last_midi_button_pressed should rerender every frame if (module->depends_on().time_since_last_midi_button_pressed) module->needs_to_rerender_flag().set_dirty(); + // Rerender when render size changes if (data_to_pass_to_shader.system_values.render_target_size != module->texture().size) module->needs_to_rerender_flag().set_dirty(); } @@ -60,10 +59,9 @@ void ModulesGraph::render(DataToPassToShader const& data_to_pass_to_shader, Data { check_for_rerender_and_rebuild(data_to_pass_to_shader, data_to_generate_shader_code); - // TODO(Particles) Remove those _nodes_graph for (auto& module : _modules) { - module->_nodes_graph = &_nodes_editor.graph(); + module->_nodes_graph = &_nodes_editor.graph(); // TODO(Particles) Remove those _nodes_graph module->before_module_graph_renders(); } @@ -100,14 +98,7 @@ void ModulesGraph::on_time_reset() static auto texture_name_for_module(Cool::NodeId const& id) -> std::string { - using fmt::literals::operator""_a; - return valid_glsl(fmt::format( - FMT_COMPILE( - R"STR(texture_{id})STR" - ), - "id"_a = to_string(id.underlying_uuid()) - ) - ); + return valid_glsl(fmt::format("texture_{})", to_string(id.underlying_uuid()))); } enum class NodeModuleness { @@ -217,7 +208,11 @@ auto ModulesGraph::create_compositing_module(Cool::NodeId const& root_node_id, D data ); - auto module = std::make_shared(texture_name_in_shader, std::move(modules_that_we_depend_on), std::move(nodes_that_we_depend_on)); + auto module = std::make_shared( + texture_name_in_shader, // Don't move it because it might still be used by create_module_impl() + std::move(modules_that_we_depend_on), + std::move(nodes_that_we_depend_on) + ); module->set_shader_code(shader_code); return module; }); @@ -260,7 +255,7 @@ auto ModulesGraph::create_particles_module(Cool::NodeId const& root_node_id, Nod auto module = std::make_shared( id_of_node_storing_particles_count, - texture_name_in_shader, + texture_name_in_shader, // Don't move it because it might still be used by create_module_impl() std::move(modules_that_we_depend_on), std::move(nodes_that_we_depend_on) ); @@ -275,15 +270,15 @@ auto ModulesGraph::create_feedback_loop_module(Cool::NodeId const& root_node_id, return create_module_impl(texture_name_in_shader, [&]() -> std::shared_ptr { auto const* node = data.nodes_graph.try_get_node(root_node_id); if (!node) - return nullptr; // TODO(Module) Return an error message? This should never happen + return create_default_module(); // TODO(Module) Return an error message? This should never happen assert(node->input_pins().size() == 1); auto const predecessor_node_id = data.nodes_graph.find_node_connected_to_input_pin(node->input_pins()[0].id()); - auto const dependency = create_module(predecessor_node_id, data); + auto dependency = create_module(predecessor_node_id, data); return std::make_shared( - texture_name_in_shader, - dependency + texture_name_in_shader, // Don't move it because it might still be used by create_module_impl() + std::move(dependency) ); }); } @@ -351,6 +346,7 @@ void ModulesGraph::submit_gizmos(Cool::GizmoManager& gizmos, CommandExecutor con auto ModulesGraph::final_texture() const -> Cool::TextureRef { + assert(_root_module && "You must call render() before trying to access the final texture"); return _root_module->texture(); }