Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedback loop #107

Merged
merged 31 commits into from
Sep 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
bc66263
🎉 [FeedbackLoop]
JulesFouchy Aug 31, 2024
0647570
✨ [ModulesGraph] Handle all modules generically
JulesFouchy Aug 31, 2024
ab7339a
✨ [ModulesGraph] Generate all the modules
JulesFouchy Aug 31, 2024
f0b1ce4
✨ [ModulesGraph] Pass textures of modules to the modules that depend …
JulesFouchy Aug 31, 2024
833c912
✨ [FeebackLoop] Working module!
JulesFouchy Sep 1, 2024
cf69d21
✨ [ModulesGraph] Render modules in the right order
JulesFouchy Sep 1, 2024
cf273f1
✨ Added debug option to force rerender every frame
JulesFouchy Sep 1, 2024
73319da
✨ [ModulesGraph] Rerender when render target size changes
JulesFouchy Sep 1, 2024
79610af
✨ [ModulesGraph] If a dependency of a node needs to rerender, then th…
JulesFouchy Sep 1, 2024
c1e6d10
✨ [ModulesGraph] Check dependencies on time, audio, osc, etc.
JulesFouchy Sep 1, 2024
96abc58
🧼 [ModulesGraph] Cleanup
JulesFouchy Sep 1, 2024
05ca90d
🐛 Fix image and video export
JulesFouchy Sep 1, 2024
8e8d047
✨ [ModulesGraph] Show generated shader code for each module
JulesFouchy Sep 1, 2024
490e690
✨ [FeedbackLoop] When the previous frame hasn't been init yet, use th…
JulesFouchy Sep 1, 2024
590ce21
♻ [ModulesGraph] Remove ModulesGraphNode, put all the data on the Module
JulesFouchy Sep 1, 2024
9eaf4df
✨ [FeedbackLoop] Request a rerender for the next frame, after the dep…
JulesFouchy Sep 1, 2024
7aa7c42
✨ [Module_Default] Added
JulesFouchy Sep 1, 2024
e25667f
🐛 [Module_Default] When creating one, forgot to add it to the list of…
JulesFouchy Sep 1, 2024
a8378a7
✨ [ModulesGraph] Don't recreate the same module twice, return the exi…
JulesFouchy Sep 1, 2024
d2d195b
🚧 [ModulesGraph] WIP interpolation_mode of module textures should be …
JulesFouchy Sep 1, 2024
87a4ca2
✨ [Modules] Only depend on the nodes that are actually used in the mo…
JulesFouchy Sep 1, 2024
85f1f96
✨ [Modules] Set uniforms only for the nodes that are actually used in…
JulesFouchy Sep 1, 2024
d5e4848
💩 [Meshing] Consider that we depend on all the nodes
JulesFouchy Sep 1, 2024
c27864c
⬆ [Cool]
JulesFouchy Sep 2, 2024
ded3558
🧼 [Feedback Loop] Cleanup
JulesFouchy Sep 2, 2024
5dae953
🧼 [Feedback Loop] Cleanup
JulesFouchy Sep 2, 2024
17244fe
🧼 [Feedback Loop] Cleanup
JulesFouchy Sep 2, 2024
d39bddd
🧼 [Feedback Loop] Cleanup
JulesFouchy Sep 2, 2024
1601a1d
🚨 Fix warnings
JulesFouchy Sep 2, 2024
e2e22c6
🧼 [Feedback Loop] Cleanup
JulesFouchy Sep 2, 2024
ec15d3c
🧼 [Modules Graph] Cleanup
JulesFouchy Sep 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Nodes/10 Image/Feedback (One frame delay).clbnode
Original file line number Diff line number Diff line change
@@ -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
}
7 changes: 0 additions & 7 deletions Nodes/10 Image/Feedback (Previous frame).clbnode

This file was deleted.

44 changes: 24 additions & 20 deletions src/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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::RenderView>(Cool::ViewCreationParams{
, _output_view{views.make_view<Cool::TextureView>(Cool::ViewCreationParams{
.name = Cool::icon_fmt("Output", ICOMOON_IMAGE),
.is_output_view = true,
.is_closable = true,
.start_open = false,
})}
, _preview_view{views.make_view<Cool::ForwardingOrRenderView>(
, _preview_view{views.make_view<Cool::ForwardingOrTextureView>(
_output_view,
Cool::ViewCreationParams{
.name = Cool::icon_fmt("View", ICOMOON_IMAGE),
Expand Down Expand Up @@ -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());
Expand All @@ -141,16 +144,16 @@ 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();
}

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 TextureView ? But that's may be too much coupling
polaroid().render(render_size, _project.clock.time(), _project.clock.delta_time());
}
else
{
Expand Down Expand Up @@ -196,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;
Expand All @@ -206,14 +209,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 = [this]() { return _project.modules_graph->final_texture(); },
.render = [this](img::Size size, Cool::Time time, Cool::Time delta_time) {
render(size, time, delta_time);
}
};
}
Expand All @@ -236,11 +234,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()
);
}
Expand Down Expand Up @@ -280,10 +282,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 = [&]() {
Expand Down Expand Up @@ -354,7 +358,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()
);
}
Expand Down Expand Up @@ -405,8 +409,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
Expand Down
15 changes: 7 additions & 8 deletions src/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include <Cool/Gpu/RenderTarget.h>
#include <Cool/Path/Path.h>
#include <Cool/Time/Clock_Realtime.h>
#include <Cool/View/RenderView.h>
#include <Cool/View/ViewsManager.h>
#include <Cool/Window/WindowManager.h>
#include <Nodes/NodesLibraryManager.h>
Expand All @@ -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"
Expand Down Expand Up @@ -78,10 +77,10 @@ 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&;
auto render_view() -> Cool::TextureView&;

void check_inputs();
void check_inputs__history();
Expand All @@ -97,7 +96,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<NodeDefinition>{_nodes_library_manager.library()} }; }
// clang-format on

Expand All @@ -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<std::filesystem::path> _current_project_path{};
RecentlyOpened _recently_opened_projects{};
Expand Down
5 changes: 5 additions & 0 deletions src/Debug/generate_debug_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
16 changes: 16 additions & 0 deletions src/Debug/generated/DebugOptions.inl
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down Expand Up @@ -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};
Expand All @@ -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),
Expand All @@ -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),
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -308,6 +318,12 @@ private:
throw 0.f; // To understand why we need to throw, see `toggle_first_option()` in <Cool/DebugOptions/DebugOptionsManager.h>
}

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 <Cool/DebugOptions/DebugOptionsManager.h>
}

if (wafl::similarity_match({filter, "Log when rendering"}) >= wafl::Matches::Strongly)
{
instance().log_when_rendering = !instance().log_when_rendering;
Expand Down
2 changes: 1 addition & 1 deletion src/Meshing/MeshingGui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
18 changes: 11 additions & 7 deletions src/Meshing/gen_mesh_from_sdf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::shared_ptr<Module>> const& module_dependencies
) -> std::optional<Cool::Mesh>
{
if constexpr (COOL_OPENGL_VERSION < 430)
Expand Down Expand Up @@ -122,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<Cool::NodeId>{}; // 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);
set_uniforms_for_shader_based_module(*meshing_compute_shader, dependencies, data_to_pass_to_shader);
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);
Expand Down
10 changes: 9 additions & 1 deletion src/Meshing/gen_mesh_from_sdf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@

namespace Lab {

class Module;

// 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<Cool::Mesh>;
auto gen_mesh_from_sdf(
Cool::NodeId const& main_node_id,
MeshingSettings const&,
DataToPassToShader const&,
DataToGenerateShaderCode const&,
std::vector<std::shared_ptr<Module>> const& module_dependencies
) -> std::optional<Cool::Mesh>;

} // namespace Lab
7 changes: 7 additions & 0 deletions src/Module/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(_modules_that_we_depend_on.begin(), _modules_that_we_depend_on.end(), [&](auto&& module) {
return module->needs_to_rerender();
});
};

} // namespace Lab
Loading
Loading