mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-09 01:09:59 +01:00
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.
This commit is contained in:
@@ -23,12 +23,13 @@
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#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<std::string> *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<std::string
|
||||
std::pair<std::string, std::string> 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<std::string
|
||||
std::string varname =
|
||||
std::regex_replace(declaration,std::regex(REGEX_UNIFORM_DECLARATION),"");
|
||||
varname = std::regex_replace(varname, std::regex(REGEX_UNIFORM_VALUE), "");
|
||||
// add to list of parameters if was not already there, with default value
|
||||
if ( !program_.hasParameter(varname) )
|
||||
program_.setParameter(varname, 0.f);
|
||||
|
||||
// try to find a value in uniform declaration, and set parameter value if valid
|
||||
float val = 0.f;
|
||||
std::string valuestring =
|
||||
std::regex_replace(declaration,std::regex(REGEX_UNIFORM_DECLARATION),"");
|
||||
valuestring = std::regex_replace(valuestring, std::regex(REGEX_VARIABLE_NAME),"");
|
||||
std::smatch found_value;
|
||||
std::regex is_a_float_value("[[:digit:]]+(\\.[[:digit:]]*)?");
|
||||
if (std::regex_search(valuestring, found_value, is_a_float_value)) {
|
||||
// set value only if a value is given
|
||||
if ( BaseToolkit::is_a_value(found_value.str(), &val) )
|
||||
program_.setParameter(varname, val);
|
||||
// add to list of parameters if was not already there, with value
|
||||
if ( !program_.hasParameter(varname) ) {
|
||||
// try to find a value in uniform declaration, and set parameter value if valid
|
||||
float val = 0.f;
|
||||
std::string valuestring =
|
||||
std::regex_replace(declaration,std::regex(REGEX_UNIFORM_DECLARATION),"");
|
||||
valuestring = std::regex_replace(valuestring, std::regex(REGEX_VARIABLE_NAME),"");
|
||||
std::smatch found_value;
|
||||
std::regex is_a_float_value("[[:digit:]]+(\\.[[:digit:]]*)?");
|
||||
if (std::regex_search(valuestring, found_value, is_a_float_value)) {
|
||||
// set value only if a value is given
|
||||
if ( BaseToolkit::is_a_value(found_value.str(), &val) )
|
||||
program_.setParameter(varname, val);
|
||||
else
|
||||
program_.setParameter(varname, 0.f);
|
||||
}
|
||||
}
|
||||
// keep parsing
|
||||
glslcode = found_uniform.suffix().str();
|
||||
|
||||
@@ -22,6 +22,40 @@ TextEditor _editor;
|
||||
|
||||
#include "ShaderEditWindow.h"
|
||||
|
||||
ImageFilter *getImageFilter(Source *s)
|
||||
{
|
||||
ImageFilter *i = nullptr;
|
||||
|
||||
// if s is a source
|
||||
if (s != nullptr) {
|
||||
CloneSource *c = dynamic_cast<CloneSource *>(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<ImageFilter *>(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<CloneSource *>(*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<ImageFilter *>(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<CloneSource *>(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<ImageFilter *>(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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
void setVisible(bool on);
|
||||
|
||||
void BuildShader();
|
||||
void BuildAll();
|
||||
|
||||
// from WorkspaceWindow
|
||||
bool Visible() const override;
|
||||
|
||||
Reference in New Issue
Block a user