mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 15:30:00 +01:00
Improve Shader Editor with shader files
Add a filename to FilteringProgram, and use the content of this file instead of code when file exists. Refer to this file in the menu of shader editor, when saving as or loading a file. Keep history of shader files in settings.
This commit is contained in:
@@ -104,20 +104,21 @@ glm::vec4 FilteringProgram::iMouse = glm::vec4(0.f,0.f,0.f,0.f);
|
||||
/// ////
|
||||
////////////////////////////////////////
|
||||
|
||||
FilteringProgram::FilteringProgram() : name_("Default"), code_({"shaders/filters/default.glsl",""}), two_pass_filter_(false)
|
||||
FilteringProgram::FilteringProgram() : name_("Default"), filename_(""),
|
||||
code_({"shaders/filters/default.glsl",""}), two_pass_filter_(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FilteringProgram::FilteringProgram(const std::string &name, const std::string &first_pass, const std::string &second_pass,
|
||||
const std::map<std::string, float> ¶meters) :
|
||||
name_(name), code_({first_pass, second_pass}), parameters_(parameters)
|
||||
const std::map<std::string, float> ¶meters, const std::string &filename) :
|
||||
name_(name), filename_(filename), code_({first_pass, second_pass}), parameters_(parameters)
|
||||
{
|
||||
two_pass_filter_ = !second_pass.empty();
|
||||
}
|
||||
|
||||
FilteringProgram::FilteringProgram(const FilteringProgram &other) :
|
||||
name_(other.name_), code_(other.code_), two_pass_filter_(other.two_pass_filter_), parameters_(other.parameters_)
|
||||
name_(other.name_), filename_(other.filename_), code_(other.code_), two_pass_filter_(other.two_pass_filter_), parameters_(other.parameters_)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -126,6 +127,7 @@ FilteringProgram& FilteringProgram::operator= (const FilteringProgram& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
this->name_ = other.name_;
|
||||
this->filename_ = other.filename_;
|
||||
this->code_ = other.code_;
|
||||
this->parameters_.clear();
|
||||
this->parameters_ = other.parameters_;
|
||||
@@ -143,9 +145,6 @@ std::pair< std::string, std::string > FilteringProgram::code()
|
||||
if (Resource::hasPath(code_.second))
|
||||
code_.second = Resource::getText(code_.second);
|
||||
|
||||
// if (SystemToolkit::file_exists(code_.first))
|
||||
// code_.first = SystemToolkit::get_text_content(code_.first);
|
||||
|
||||
return code_;
|
||||
}
|
||||
|
||||
@@ -447,19 +446,20 @@ void ImageFilter::setProgram(const FilteringProgram &f, std::promise<std::string
|
||||
// always keep local copy
|
||||
program_ = f;
|
||||
|
||||
// change code
|
||||
// get code
|
||||
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());
|
||||
|
||||
// FIRST PASS
|
||||
// set code to the shader for first-pass
|
||||
std::string __code = codes.first;
|
||||
if (SystemToolkit::file_exists(__code))
|
||||
__code = SystemToolkit::get_text_content(__code);
|
||||
shaders_.first->setCode( __code, ret );
|
||||
shaders_.first->setCode( codes.first, ret );
|
||||
|
||||
// Parse code to detect additional declaration of uniform variables
|
||||
// Search for "uniform float", a variable name, with possibly a '=' and float value
|
||||
std::string glslcode(__code);
|
||||
std::string glslcode(codes.first);
|
||||
std::smatch found_uniform;
|
||||
std::regex is_a_uniform(REGEX_UNIFORM_DECLARATION REGEX_VARIABLE_NAME REGEX_UNIFORM_VALUE);
|
||||
// loop over every uniform declarations in the GLSL code
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
class FilteringProgram
|
||||
{
|
||||
std::string name_;
|
||||
std::string filename_;
|
||||
|
||||
// code : resource file or GLSL (ShaderToy style)
|
||||
std::pair< std::string, std::string > code_;
|
||||
@@ -30,7 +31,7 @@ public:
|
||||
|
||||
FilteringProgram();
|
||||
FilteringProgram(const std::string &name, const std::string &first_pass, const std::string &second_pass,
|
||||
const std::map<std::string, float> ¶meters);
|
||||
const std::map<std::string, float> ¶meters, const std::string &filename = std::string());
|
||||
FilteringProgram(const FilteringProgram &other);
|
||||
|
||||
FilteringProgram& operator= (const FilteringProgram& other);
|
||||
@@ -40,6 +41,11 @@ public:
|
||||
inline void setName(const std::string &name) { name_ = name; }
|
||||
inline std::string name() const { return name_; }
|
||||
|
||||
// get the filename
|
||||
inline void resetFilename() { filename_ = std::string(); }
|
||||
inline void setFilename(const std::string &filename) { filename_ = filename; }
|
||||
inline std::string filename() const { return filename_; }
|
||||
|
||||
// set the code
|
||||
inline void setCode(const std::pair< std::string, std::string > &code) { code_ = code; }
|
||||
|
||||
|
||||
@@ -1476,8 +1476,7 @@ std::map< std::string, float > get_parameters_(XMLElement* parameters)
|
||||
float val = 0.f;
|
||||
param->QueryFloatAttribute("value", &val);
|
||||
const char * name;
|
||||
param->QueryStringAttribute("name", &name);
|
||||
if (name)
|
||||
if ( param->QueryStringAttribute("name", &name) == XML_SUCCESS && name != NULL)
|
||||
filter_params[name] = val;
|
||||
}
|
||||
}
|
||||
@@ -1532,10 +1531,17 @@ void SessionLoader::visit (AlphaFilter& f)
|
||||
|
||||
void SessionLoader::visit (ImageFilter& f)
|
||||
{
|
||||
const char * filter_name;
|
||||
std::pair< std::string, std::string > filter_codes;
|
||||
|
||||
xmlCurrent_->QueryStringAttribute("name", &filter_name);
|
||||
const char *name = NULL;
|
||||
std::string filter_name;
|
||||
if (xmlCurrent_->QueryStringAttribute("name", &name) == XML_SUCCESS && name != NULL)
|
||||
filter_name = std::string(name);
|
||||
|
||||
const char *filename = NULL;
|
||||
std::string filter_filename;
|
||||
if (xmlCurrent_->QueryStringAttribute("filename", &filename) == XML_SUCCESS && filename != NULL)
|
||||
filter_filename = std::string(filename);
|
||||
|
||||
// image filter code
|
||||
XMLElement* firstpass = xmlCurrent_->FirstChildElement("firstpass");
|
||||
@@ -1555,7 +1561,8 @@ void SessionLoader::visit (ImageFilter& f)
|
||||
std::map< std::string, float > filter_params = get_parameters_(xmlCurrent_->FirstChildElement("parameters"));
|
||||
|
||||
// set image filter program and parameters
|
||||
f.setProgram( FilteringProgram(filter_name, filter_codes.first, filter_codes.second, filter_params) );
|
||||
f.setProgram( FilteringProgram(filter_name, filter_codes.first, filter_codes.second,
|
||||
filter_params, filter_filename) );
|
||||
|
||||
// set global iMouse
|
||||
XMLElement* imouse = xmlCurrent_->FirstChildElement("iMouse");
|
||||
|
||||
@@ -800,6 +800,7 @@ void SessionVisitor::visit (AlphaFilter& f)
|
||||
void SessionVisitor::visit (ImageFilter& f)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("name", f.program().name().c_str() );
|
||||
xmlCurrent_->SetAttribute("filename", f.program().filename().c_str() );
|
||||
|
||||
// image filter code
|
||||
std::pair< std::string, std::string > filter_codes = f.program().code();
|
||||
|
||||
@@ -18,6 +18,7 @@ TextEditor _editor;
|
||||
#include "SystemToolkit.h"
|
||||
#include "CloneSource.h"
|
||||
#include "DialogToolkit.h"
|
||||
#include "BaseToolkit.h"
|
||||
#include "UserInterfaceManager.h"
|
||||
|
||||
#include "ShaderEditWindow.h"
|
||||
@@ -107,18 +108,14 @@ void ShaderEditWindow::BuildShader()
|
||||
// if the UI has a current clone, and ref to code for current clone is valid
|
||||
if (current_ != nullptr && filters_.find(current_) != filters_.end()) {
|
||||
|
||||
// set the code of the current filter
|
||||
if (Settings::application.recentShaderCode.path.empty()
|
||||
|| !SystemToolkit::file_exists(Settings::application.recentShaderCode.path)) {
|
||||
filters_[current_].setCode({_editor.GetText(), ""});
|
||||
filters_[current_].setName("Custom"); // TODO SET BY FILENAME
|
||||
}
|
||||
else {
|
||||
filters_[current_].setCode({Settings::application.recentShaderCode.path, ""});
|
||||
filters_[current_].setName(SystemToolkit::base_filename(Settings::application.recentShaderCode.path));
|
||||
}
|
||||
// get the editor text and remove trailing '\n'
|
||||
std::string code = _editor.GetText();
|
||||
code = code.substr(0, code.size() -1);
|
||||
|
||||
// set parameters TODO VERIFY IT WORKS FOR LOADED FILE
|
||||
// set the code to the current content of editor
|
||||
filters_[current_].setCode({code, ""});
|
||||
|
||||
// set parameters
|
||||
filters_[current_].setParameters(current_->program().parameters());
|
||||
|
||||
// change the filter of the current image filter
|
||||
@@ -151,7 +148,7 @@ void ShaderEditWindow::Render()
|
||||
return;
|
||||
}
|
||||
|
||||
std::string file_to_open_ = "";
|
||||
std::string file_to_build_ = "";
|
||||
Source *cs = Mixer::manager().currentSource();
|
||||
|
||||
// menu (no title bar)
|
||||
@@ -205,8 +202,9 @@ void ShaderEditWindow::Render()
|
||||
if (ImGui::MenuItem(LABEL_SHADER_EMBEDDED, NULL,
|
||||
Settings::application.recentShaderCode.path.empty())) {
|
||||
// cancel path of recent shader
|
||||
filters_[current_].resetFilename();
|
||||
Settings::application.recentShaderCode.assign("");
|
||||
// build with code
|
||||
// build code
|
||||
BuildShader();
|
||||
}
|
||||
|
||||
@@ -221,7 +219,10 @@ void ShaderEditWindow::Render()
|
||||
Settings::application.recentShaderCode.path)
|
||||
== 0;
|
||||
if (ImGui::MenuItem(label.c_str(), NULL, selected)) {
|
||||
file_to_open_ = *filename;
|
||||
// set shader program to be a file
|
||||
file_to_build_ = *filename;
|
||||
// read file and display content in editor
|
||||
_editor.SetText(SystemToolkit::get_text_content(file_to_build_));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,16 +248,8 @@ void ShaderEditWindow::Render()
|
||||
p != FilteringProgram::presets.end();
|
||||
++p) {
|
||||
if (ImGui::MenuItem(p->name().c_str())) {
|
||||
// change the filter of the current image filter
|
||||
// => this triggers compilation of shader
|
||||
compilation_ = new std::promise<std::string>();
|
||||
current_->setProgram(*p, compilation_);
|
||||
compilation_return_ = compilation_->get_future();
|
||||
// inform status
|
||||
status_ = "Building...";
|
||||
Refresh();
|
||||
// cancel path of recent shader
|
||||
Settings::application.recentShaderCode.assign("");
|
||||
// copy text code into editor
|
||||
_editor.SetText( p->code().first );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,8 +291,21 @@ void ShaderEditWindow::Render()
|
||||
}
|
||||
|
||||
// Build action menu
|
||||
if (ImGui::MenuItem( ICON_FA_HAMMER " Build", CTRL_MOD "B", nullptr, current_ != nullptr ))
|
||||
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
|
||||
|
||||
// build
|
||||
BuildShader();
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
@@ -312,45 +318,40 @@ void ShaderEditWindow::Render()
|
||||
_editor.SetText("");
|
||||
}
|
||||
|
||||
|
||||
// File dialog Export code gives a filename to save to
|
||||
if (exportcodedialog.closed() && !exportcodedialog.path().empty()) {
|
||||
// Open the file
|
||||
std::ofstream file(exportcodedialog.path());
|
||||
|
||||
// Save content to file
|
||||
// set shader program to be a file
|
||||
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();
|
||||
|
||||
// Close the file
|
||||
file.close();
|
||||
|
||||
// set shader code by file
|
||||
file_to_open_ = exportcodedialog.path();
|
||||
}
|
||||
|
||||
// File dialog select code gives a filename to open
|
||||
if (selectcodedialog.closed() && !selectcodedialog.path().empty()) {
|
||||
// set shader code by file
|
||||
file_to_open_ = selectcodedialog.path();
|
||||
|
||||
// set shader program to be a file
|
||||
file_to_build_ = selectcodedialog.path();
|
||||
|
||||
// read file and display content in editor
|
||||
_editor.SetText(SystemToolkit::get_text_content(file_to_build_));
|
||||
}
|
||||
|
||||
if ( !file_to_open_.empty() ) {
|
||||
if ( current_ != nullptr && !file_to_build_.empty() ) {
|
||||
|
||||
// ok editor
|
||||
_editor.SetReadOnly(false);
|
||||
_editor.SetColorizerEnable(true);
|
||||
|
||||
// link to file
|
||||
Settings::application.recentShaderCode.push(file_to_open_);
|
||||
Settings::application.recentShaderCode.assign(file_to_open_);
|
||||
|
||||
// read and display content
|
||||
std::string filecontent = SystemToolkit::get_text_content(file_to_open_);
|
||||
|
||||
// TODO = ACTIONS BUILD should save the file
|
||||
if (!filecontent.empty()) {
|
||||
// replace text of editor
|
||||
_editor.SetText(filecontent);
|
||||
_editor.SetReadOnly(false);
|
||||
_editor.SetColorizerEnable(true);
|
||||
}
|
||||
filters_[current_].setFilename(file_to_build_);
|
||||
Settings::application.recentShaderCode.push(file_to_build_);
|
||||
Settings::application.recentShaderCode.assign(file_to_build_);
|
||||
|
||||
// build with new code
|
||||
BuildShader();
|
||||
@@ -385,7 +386,7 @@ void ShaderEditWindow::Render()
|
||||
if (i != nullptr) {
|
||||
// if the current clone was not already registered
|
||||
if ( filters_.find(i) == filters_.end() )
|
||||
// remember code for this clone
|
||||
// remember program for this image filter
|
||||
filters_[i] = i->program();
|
||||
}
|
||||
}
|
||||
@@ -413,17 +414,11 @@ void ShaderEditWindow::Render()
|
||||
|
||||
// if switch to another shader code
|
||||
if ( i != nullptr ) {
|
||||
std::string c = filters_[i].code().first;
|
||||
if (SystemToolkit::file_exists(c)) {
|
||||
Settings::application.recentShaderCode.push(c);
|
||||
Settings::application.recentShaderCode.assign(c);
|
||||
c = SystemToolkit::get_text_content(c);
|
||||
}
|
||||
else
|
||||
Settings::application.recentShaderCode.assign("");
|
||||
// set current shader code menu
|
||||
Settings::application.recentShaderCode.assign(filters_[i].filename());
|
||||
|
||||
// change editor
|
||||
_editor.SetText( c );
|
||||
_editor.SetText( filters_[i].code().first );
|
||||
_editor.SetReadOnly(false);
|
||||
_editor.SetColorizerEnable(true);
|
||||
status_ = "Ready";
|
||||
@@ -446,26 +441,37 @@ void ShaderEditWindow::Render()
|
||||
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_ITALIC);
|
||||
ImGui::Text("Status: %s", status_.c_str());
|
||||
|
||||
// render filename and file close button
|
||||
if (!Settings::application.recentShaderCode.path.empty()) { // if current is linked file
|
||||
// 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::PopStyleColor(1);
|
||||
}
|
||||
// or Display filename and close button for shaders from file
|
||||
else {
|
||||
const float w = ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeight();
|
||||
|
||||
// right-aligned filename, in italics and greyed out
|
||||
ImVec2 txtsize = ImGui::CalcTextSize(Settings::application.recentShaderCode.path.c_str(), NULL);
|
||||
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", Settings::application.recentShaderCode.path.c_str());
|
||||
ImGui::Text("%s", filters_[current_].filename().c_str());
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
// 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")) {
|
||||
// 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 and rebuild from existing code as embeded
|
||||
Settings::application.recentShaderCode.remove(Settings::application.recentShaderCode.path);
|
||||
// assign a non-filename to path
|
||||
Settings::application.recentShaderCode.assign("");
|
||||
// rebuild from existing code as embeded
|
||||
BuildShader();
|
||||
}
|
||||
ImGui::PopStyleVar(1);
|
||||
|
||||
Reference in New Issue
Block a user