From 0289f4c06ed8c343be8b30f768922ff1dbe860b9 Mon Sep 17 00:00:00 2001 From: Bruno Herbelin Date: Sun, 15 Dec 2024 18:35:37 +0100 Subject: [PATCH] BugFix Shader Image filter set uniform value Use uniform value from code on first compile, then keep value from active shader. Fix bug reading uniform value in code. Various code improvement. --- src/ImageFilter.cpp | 61 +++++++++------ src/ShaderEditWindow.cpp | 159 +++++++++++++++++++++++---------------- src/ShaderEditWindow.h | 1 + 3 files changed, 133 insertions(+), 88 deletions(-) diff --git a/src/ImageFilter.cpp b/src/ImageFilter.cpp index 8948bb9..cf722fd 100644 --- a/src/ImageFilter.cpp +++ b/src/ImageFilter.cpp @@ -23,12 +23,13 @@ #include #include -#include "Resource.h" -#include "Visitor.h" -#include "FrameBuffer.h" -#include "Primitives.h" #include "BaseToolkit.h" +#include "FrameBuffer.h" +#include "Log.h" +#include "Primitives.h" +#include "Resource.h" #include "SystemToolkit.h" +#include "Visitor.h" #include "Mixer.h" @@ -443,6 +444,9 @@ FilteringProgram ImageFilter::program () const void ImageFilter::setProgram(const FilteringProgram &f, std::promise *ret) { + // impose C locale + setlocale(LC_ALL, "C"); + // always keep local copy program_ = f; @@ -450,9 +454,21 @@ void ImageFilter::setProgram(const FilteringProgram &f, std::promise codes = program_.code(); // if program code is given by a filename, read the file - if (!program_.filename().empty() && SystemToolkit::file_exists(program_.filename())) { - codes.first = SystemToolkit::get_text_content(program_.filename()); - program_.setCode( codes ); + if (!program_.filename().empty()) { + // read the file if it exists + std::string content_text_ = ""; + if (SystemToolkit::file_exists(program_.filename())) + content_text_ = SystemToolkit::get_text_content(program_.filename()); + // if content of text file is empty (also if file doesn't exists) + if (content_text_.empty()) { + Log::Info("File '%s' not found or not a text file; ignored.", program_.filename().c_str()); + // use embedded code and reset filename + program_.resetFilename(); + } else { + // set code to text content + codes.first = content_text_; + program_.setCode( codes ); + } } // FIRST PASS @@ -472,21 +488,22 @@ void ImageFilter::setProgram(const FilteringProgram &f, std::promise(s); + // if s is a clone + if (c != nullptr) { + // it has a filter + FrameBufferFilter *f = c->filter(); + // if the filter seems to be an Image Filter + if (f != nullptr && f->type() == FrameBufferFilter::FILTER_IMAGE) { + // cast to image filter + i = dynamic_cast(f); + } + } + } + + return i; +} + +void saveEditorText(const std::string &filename) +{ + std::ofstream file(filename); + if (file.is_open()) { + // get the editor text and remove trailing '\n' + std::string code = _editor.GetText(); + code = code.substr(0, code.size() -1); + file << code; + } + file.close(); +} + /// /// SHADER EDITOR /// @@ -76,6 +110,9 @@ ShaderEditWindow::ShaderEditWindow() : WorkspaceWindow("Shader"), current_(nullp _editor.SetReadOnly(true); _editor.SetColorizerEnable(false); + // validate list for menu + Settings::application.recentShaderCode.validate(); + // status status_ = "-"; } @@ -129,6 +166,20 @@ void ShaderEditWindow::BuildShader() } } +void ShaderEditWindow::BuildAll() +{ + // Loop over all sources + for (auto s = Mixer::manager().session()->begin(); s != Mixer::manager().session()->end(); ++s) { + // if image filter can be extracted from source + ImageFilter *imf = getImageFilter(*s); + if (imf != nullptr) { + // rebuild by re-injecting same program + imf->setProgram(imf->program()); + } + } +} + + void ShaderEditWindow::Render() { static DialogToolkit::OpenFileDialog selectcodedialog("Open GLSL shader code", @@ -159,7 +210,7 @@ void ShaderEditWindow::Render() if (ImGui::BeginMenu(IMGUI_TITLE_SHADEREDITOR)) { // Menu entry to allow creating a custom filter - if (ImGui::MenuItem(ICON_FA_SHARE_SQUARE " Clone & Custom shader", + if (ImGui::MenuItem(ICON_FA_SHARE_SQUARE " Clone source & add shader", nullptr, nullptr, cs != nullptr)) { CloneSource *filteredclone = Mixer::manager().createSourceClone(); filteredclone->setFilter(FrameBufferFilter::FILTER_IMAGE); @@ -168,26 +219,8 @@ void ShaderEditWindow::Render() } // Menu entry to rebuild all - if (ImGui::MenuItem(ICON_FA_HAMMER " Rebuild all")) { - // select all playable sources - for (auto s = Mixer::manager().session()->begin(); - s != Mixer::manager().session()->end(); - ++s) { - if (!(*s)->failed()) { - CloneSource *c = dynamic_cast(*s); - // if the source is a clone - if (c != nullptr) { - FrameBufferFilter *f = c->filter(); - // if the filter seems to be an Image Filter - if (f != nullptr && f->type() == FrameBufferFilter::FILTER_IMAGE) { - ImageFilter *imf = dynamic_cast(f); - if (imf != nullptr) - imf->setProgram(imf->program()); - } - } - } - } - } + if (ImGui::MenuItem(ICON_FA_HAMMER " Rebuild all")) + BuildAll(); ImGui::Separator(); @@ -320,14 +353,8 @@ void ShaderEditWindow::Render() if (ImGui::MenuItem( ICON_FA_HAMMER " Build", CTRL_MOD "B", nullptr, current_ != nullptr )) { // if present, save the program file with current content of editor - if (!filters_[current_].filename().empty()) { - std::ofstream file(filters_[current_].filename()); - if (file.is_open()) - file << _editor.GetText(); - file.close(); - } - - // TODO Rebuild all clone sources with same custom shading file + if (!filters_[current_].filename().empty()) + saveEditorText(filters_[current_].filename()); // build BuildShader(); @@ -339,9 +366,12 @@ void ShaderEditWindow::Render() // garbage collection if ( Mixer::manager().session()->numSources() < 1 ) { + // empty list of edited filter when session empty filters_.clear(); current_ = nullptr; _editor.SetText(""); + // validate list for menu + Settings::application.recentShaderCode.validate(); } // File dialog Export code gives a filename to save to @@ -351,11 +381,7 @@ void ShaderEditWindow::Render() file_to_build_ = exportcodedialog.path(); // save the current content of editor into given file - std::ofstream file(file_to_build_); - if (file.is_open()) - file << _editor.GetText(); - file.close(); - + saveEditorText(file_to_build_); } // File dialog select code gives a filename to open @@ -368,7 +394,7 @@ void ShaderEditWindow::Render() _editor.SetText(SystemToolkit::get_text_content(file_to_build_)); } - if ( current_ != nullptr && !file_to_build_.empty() ) { + if (current_ != nullptr && !file_to_build_.empty()) { // ok editor _editor.SetReadOnly(false); @@ -401,23 +427,15 @@ void ShaderEditWindow::Render() ImageFilter *i = nullptr; // if there is a current source if (cs != nullptr) { - CloneSource *c = dynamic_cast(cs); - // if the current source is a clone - if ( c != nullptr ) { - FrameBufferFilter *f = c->filter(); - // if the filter seems to be an Image Filter - if (f != nullptr && f->type() == FrameBufferFilter::FILTER_IMAGE ) { - i = dynamic_cast(f); - // if we can access the code of the filter - if (i != nullptr) { - // if the current clone was not already registered - if ( filters_.find(i) == filters_.end() ) { - // remember program for this image filter - filters_[i] = i->program(); - // set a name to the filter - filters_[i].setName(c->name()); - } - } + i = getImageFilter(cs); + // if we can access the code of the filter + if (i != nullptr) { + // if the current clone was not already registered + if ( filters_.find(i) == filters_.end() ) { + // remember program for this image filter + filters_[i] = i->program(); + // set a name to the filter + filters_[i].setName(cs->name()); } } // there is a current source, and it is not a filter @@ -426,6 +444,7 @@ void ShaderEditWindow::Render() _editor.SetText(""); _editor.SetReadOnly(true); current_ = nullptr; + Settings::application.recentShaderCode.assign(""); } } else @@ -443,7 +462,7 @@ void ShaderEditWindow::Render() // if switch to another shader code if ( i != nullptr ) { - // set current shader code menu + // set current shader code menu (can be empty for embedded) Settings::application.recentShaderCode.assign(filters_[i].filename()); // change editor @@ -470,34 +489,39 @@ void ShaderEditWindow::Render() ImGuiToolkit::PushFont(ImGuiToolkit::FONT_ITALIC); ImGui::Text("Status: %s", status_.c_str()); + const float w = ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeight(); + ImVec2 txtsize = ImGui::CalcTextSize(Settings::application.recentShaderCode.path.c_str(), NULL); + ImGui::SameLine(w - txtsize.x - IMGUI_SAME_LINE, 0); + // Right-align on same line than status // Display name of program for embedded code if (filters_[current_].filename().empty()) { // right-aligned in italics and greyed out - const float w = ImGui::GetContentRegionAvail().x - IMGUI_SAME_LINE; - ImVec2 txtsize = ImGui::CalcTextSize(filters_[current_].name().c_str(), NULL); - ImGui::SameLine(w - txtsize.x, 0); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8, 0.8, 0.8, 0.9f)); - ImGui::Text("%s", filters_[current_].name().c_str()); + ImGui::Text("%s", Settings::application.recentShaderCode.path.c_str()); ImGui::PopStyleColor(1); } // or Display filename and close button for shaders from file else { - const float w = ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeight(); - ImVec2 txtsize = ImGui::CalcTextSize(filters_[current_].filename().c_str(), NULL); - ImGui::SameLine(w - txtsize.x - IMGUI_SAME_LINE, 0); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8, 0.8, 0.8, 0.9f)); - ImGui::Text("%s", filters_[current_].filename().c_str()); - ImGui::PopStyleColor(1); + // right-aligned in italics + ImGui::Text("%s", Settings::application.recentShaderCode.path.c_str()); // top right X icon to close the file ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 0.f)); ImGui::SameLine(w, IMGUI_SAME_LINE); if (ImGuiToolkit::TextButton(ICON_FA_TIMES, "Close file")) { + // Test if there are other filters refering to this filename + uint count_file = 0; + for (auto const &fil : filters_) { + if (fil.first != nullptr && + filters_[current_].filename().compare(fil.first->program().filename()) == 0) + count_file++; + } + // remove the filename from list of menu if was used by other filters + if (count_file > 1) + Settings::application.recentShaderCode.remove(Settings::application.recentShaderCode.path); // unset filename for program filters_[current_].resetFilename(); - // remove the filename from list of menu - Settings::application.recentShaderCode.remove(Settings::application.recentShaderCode.path); // assign a non-filename to path Settings::application.recentShaderCode.assign(""); // rebuild from existing code as embeded @@ -556,7 +580,10 @@ void ShaderEditWindow::Render() BuildShader(); // special case for 'CTRL + S' keyboard shortcut if (ImGui::IsKeyPressed(io.KeyMap[ImGuiKey_V] - 3)) { - BuildShader(); + // if present, save the program file with current content of editor + if (!filters_[current_].filename().empty()) + saveEditorText(filters_[current_].filename()); + // save session Mixer::manager().save(); } } diff --git a/src/ShaderEditWindow.h b/src/ShaderEditWindow.h index 862dcbc..1d211bc 100644 --- a/src/ShaderEditWindow.h +++ b/src/ShaderEditWindow.h @@ -27,6 +27,7 @@ public: void setVisible(bool on); void BuildShader(); + void BuildAll(); // from WorkspaceWindow bool Visible() const override;