mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-05 15:30:00 +01:00
Add texture management as sampler2D uniform to ImageFilter and related components
This commit is contained in:
@@ -1293,6 +1293,39 @@ void ImGuiVisitor::visit (AlphaFilter& f)
|
||||
|
||||
}
|
||||
|
||||
|
||||
void list_textures_(ImageFilter &f, std::ostringstream &oss)
|
||||
{
|
||||
std::map<std::string, uint64_t > filter_textures = f.program().textures();
|
||||
|
||||
for (auto tex = filter_textures.rbegin(); tex != filter_textures.rend(); ++tex)
|
||||
{
|
||||
ImGui::PushID( tex->first.c_str() );
|
||||
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
|
||||
|
||||
Source *source = Mixer::manager().findSource( tex->second );
|
||||
std::string label = source == nullptr ? "Select source" : ""
|
||||
+ std::string( source->initials() )
|
||||
+ " - "
|
||||
+ source->name();
|
||||
if (ImGui::BeginCombo(tex->first.c_str(), label.c_str()) )
|
||||
{
|
||||
SourceList::iterator iter;
|
||||
for (iter = Mixer::manager().session()->begin(); iter != Mixer::manager().session()->end(); ++iter)
|
||||
{
|
||||
label = std::string((*iter)->initials()) + " - " + (*iter)->name();
|
||||
if (ImGui::Selectable( label.c_str())) {
|
||||
f.setProgramTexture(tex->first, (*iter)->id() );
|
||||
oss << " Texture " << tex->first << " " << label;
|
||||
Action::manager().store(oss.str());
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiVisitor::visit (ImageFilter& f)
|
||||
{
|
||||
// Open Editor
|
||||
@@ -1301,9 +1334,10 @@ void ImGuiVisitor::visit (ImageFilter& f)
|
||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||
ImGui::Text("Code");
|
||||
|
||||
// List of parameters
|
||||
// List of parameters & textures
|
||||
oss << "Custom ";
|
||||
list_parameters_(f, oss);
|
||||
list_textures_(f, oss);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <algorithm>
|
||||
#include <regex>
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <glm/gtc/matrix_access.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
@@ -30,6 +31,7 @@
|
||||
#include "Resource.h"
|
||||
#include "SystemToolkit.h"
|
||||
#include "Visitor.h"
|
||||
#include "Source.h"
|
||||
|
||||
#include "Mixer.h"
|
||||
|
||||
@@ -120,14 +122,17 @@ FilteringProgram::FilteringProgram() : name_("Default"), filename_(""),
|
||||
}
|
||||
|
||||
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::string &filename) :
|
||||
name_(name), filename_(filename), code_({first_pass, second_pass}), parameters_(parameters)
|
||||
const std::map<std::string, float> ¶meters, const std::string &filename,
|
||||
const std::map<std::string, uint64_t> &textures ) :
|
||||
name_(name), filename_(filename), code_({first_pass, second_pass}), parameters_(parameters), textures_(textures)
|
||||
{
|
||||
two_pass_filter_ = !second_pass.empty();
|
||||
}
|
||||
|
||||
FilteringProgram::FilteringProgram(const FilteringProgram &other) :
|
||||
name_(other.name_), filename_(other.filename_), 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_),
|
||||
textures_(other.textures_)
|
||||
{
|
||||
|
||||
}
|
||||
@@ -140,6 +145,8 @@ FilteringProgram& FilteringProgram::operator= (const FilteringProgram& other)
|
||||
this->code_ = other.code_;
|
||||
this->parameters_.clear();
|
||||
this->parameters_ = other.parameters_;
|
||||
this->textures_.clear();
|
||||
this->textures_ = other.textures_;
|
||||
this->two_pass_filter_ = other.two_pass_filter_;
|
||||
}
|
||||
|
||||
@@ -178,6 +185,17 @@ void FilteringProgram::removeParameter(const std::string &p)
|
||||
parameters_.erase(p);
|
||||
}
|
||||
|
||||
bool FilteringProgram::hasTexture(const std::string &t)
|
||||
{
|
||||
return textures_.find(t) != textures_.end();
|
||||
}
|
||||
|
||||
void FilteringProgram::removeTexture(const std::string &t)
|
||||
{
|
||||
if (hasTexture(t))
|
||||
textures_.erase(t);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
///// //
|
||||
@@ -251,11 +269,26 @@ void ImageFilteringShader::use()
|
||||
// uniform variable could be set, keep it
|
||||
++u;
|
||||
else {
|
||||
// uniform variable does not exist in code, remove it
|
||||
// uniform variable is not used in code, remove it
|
||||
u = uniforms_.erase(u);
|
||||
uniforms_changed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
// loop over sampler2D uniforms for channels (start at 2)
|
||||
int sampler_index = 2;
|
||||
for (auto u = sampler2D_.begin(); u != sampler2D_.end(); ) {
|
||||
// set uniform sampler2D to current sampler_index
|
||||
if ( program_->setUniform(u->first, sampler_index++) )
|
||||
// uniform variable could be set, keep it
|
||||
++u;
|
||||
else {
|
||||
// uniform variable is not used in code, remove it
|
||||
u = sampler2D_.erase(u);
|
||||
uniforms_changed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ImageFilteringShader::reset()
|
||||
@@ -356,6 +389,15 @@ void ImageFilter::update (float dt)
|
||||
if (shaders_.first->uniforms_.count(param->first) < 1)
|
||||
program_.removeParameter(param->first);
|
||||
}
|
||||
|
||||
// loop over the textures of the program...
|
||||
std::map<std::string, uint64_t > __T = program_.textures();
|
||||
for (auto tex = __T.begin(); tex != __T.end(); ++tex) {
|
||||
// .. and remove the textures that are not valid sampler2D
|
||||
if (shaders_.first->sampler2D_.count(tex->first) < 1)
|
||||
program_.removeTexture(tex->first);
|
||||
}
|
||||
|
||||
// done
|
||||
shaders_.first->uniforms_changed_ = false;
|
||||
}
|
||||
@@ -408,6 +450,8 @@ void ImageFilter::draw (FrameBuffer *input)
|
||||
if (buffers_.second != nullptr)
|
||||
delete buffers_.second;
|
||||
buffers_.second = new FrameBuffer( buffers_.first->resolution(), buffers_.first->flags() );
|
||||
// force update
|
||||
updateParameters();
|
||||
// forced draw
|
||||
forced = true;
|
||||
}
|
||||
@@ -417,6 +461,18 @@ void ImageFilter::draw (FrameBuffer *input)
|
||||
// FIRST PASS
|
||||
if (channel1_output_session)
|
||||
shaders_.first->secondary_texture = Mixer::manager().session()->frame()->texture();
|
||||
|
||||
// loop over sampler2D uniforms to bind textures
|
||||
uint texture_unit = 0;
|
||||
for (auto u = shaders_.first->sampler2D_.begin(); u != shaders_.first->sampler2D_.end(); ++u) {
|
||||
// setup mask texture
|
||||
glActiveTexture(GL_TEXTURE2 + texture_unit++);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glBindTexture (GL_TEXTURE_2D, u->second);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
// render input surface into frame buffer
|
||||
buffers_.first->begin();
|
||||
surfaces_.first->draw(glm::identity<glm::mat4>(), buffers_.first->projection());
|
||||
@@ -449,6 +505,7 @@ FilteringProgram ImageFilter::program () const
|
||||
#define REGEX_UNIFORM_DECLARATION "uniform\\s+float\\s+"
|
||||
#define REGEX_VARIABLE_NAME "[a-zA-Z_][\\w]+"
|
||||
#define REGEX_UNIFORM_VALUE "(\\s*=\\s*[[:digit:]]+(\\.[[:digit:]]*)?)?\\s*\\;"
|
||||
#define REGEX_SAMPLER_DECLARATION "uniform\\s+sampler2D\\s+"
|
||||
|
||||
void ImageFilter::setProgram(const FilteringProgram &f, std::promise<std::string> *ret)
|
||||
{
|
||||
@@ -512,11 +569,35 @@ void ImageFilter::setProgram(const FilteringProgram &f, std::promise<std::string
|
||||
else
|
||||
program_.setParameter(varname, 0.f);
|
||||
}
|
||||
else
|
||||
program_.setParameter(varname, 0.f);
|
||||
}
|
||||
// keep parsing
|
||||
glslcode = found_uniform.suffix().str();
|
||||
}
|
||||
|
||||
// Parse code to detect additional declaration of uniform sampler2D
|
||||
// Search for "uniform sampler2D" and a variable name
|
||||
glslcode = codes.first;
|
||||
std::smatch found_sampler2D;
|
||||
std::regex is_a_sampler2D(REGEX_SAMPLER_DECLARATION REGEX_VARIABLE_NAME);
|
||||
// loop over every uniform declarations in the GLSL code
|
||||
while (std::regex_search(glslcode, found_sampler2D, is_a_sampler2D)) {
|
||||
// found a complete declaration of uniform sampler2D
|
||||
std::string declaration = found_sampler2D.str();
|
||||
// extract variable name by erasing everything else
|
||||
std::string varname =
|
||||
std::regex_replace(declaration,std::regex(REGEX_SAMPLER_DECLARATION),"");
|
||||
if (!varname.empty()) {
|
||||
// add new detected texture with unknown source
|
||||
if ( !program_.hasTexture(varname) ){
|
||||
program_.setTexture(varname, 0);
|
||||
}
|
||||
}
|
||||
// keep parsing
|
||||
glslcode = found_sampler2D.suffix().str();
|
||||
}
|
||||
|
||||
// SECOND PASS
|
||||
if ( program_.isTwoPass() )
|
||||
// set the code to the shader for second-pass
|
||||
@@ -531,6 +612,35 @@ void ImageFilter::updateParameters()
|
||||
// change uniforms
|
||||
shaders_.first->uniforms_ = program_.parameters();
|
||||
|
||||
// change textures into sampler2D
|
||||
auto texturelist = program_.textures();
|
||||
if ( !texturelist.empty() ) {
|
||||
auto copy_sampler2D = shaders_.first->sampler2D_;
|
||||
for (auto T = texturelist.begin(); T != texturelist.end(); ++T) {
|
||||
// get texture id from source
|
||||
uint texture_id = Resource::getTextureBlack();
|
||||
Source *s = Mixer::manager().findSource(T->second);
|
||||
if ( s != nullptr )
|
||||
texture_id = s->texture();
|
||||
|
||||
// set or insert a texture id into sampler2D list
|
||||
shaders_.first->sampler2D_[T->first] = texture_id;
|
||||
|
||||
// remove from copy list
|
||||
if ( copy_sampler2D.find(T->first) != copy_sampler2D.end() ) {
|
||||
copy_sampler2D.erase(T->first);
|
||||
}
|
||||
}
|
||||
// remove textures that are not used anymore
|
||||
for (auto S = copy_sampler2D.begin(); S != copy_sampler2D.end(); ++S) {
|
||||
shaders_.first->sampler2D_.erase(S->first);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no texture, clear sampler2D list
|
||||
shaders_.first->sampler2D_.clear();
|
||||
}
|
||||
|
||||
if ( program_.isTwoPass() )
|
||||
shaders_.second->uniforms_ = program_.parameters();
|
||||
}
|
||||
@@ -555,6 +665,26 @@ void ImageFilter::setProgramParameter(const std::string &p, float value)
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
void ImageFilter::setProgramTextures(const std::map< std::string, uint64_t > &textures)
|
||||
{
|
||||
for (const auto &p : textures) {
|
||||
if (p.first.empty())
|
||||
return;
|
||||
}
|
||||
|
||||
program_.setTextures(textures);
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
void ImageFilter::setProgramTexture(const std::string &p, uint64_t id)
|
||||
{
|
||||
if (p.empty())
|
||||
return;
|
||||
|
||||
program_.setTexture(p, id);
|
||||
updateParameters();
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
///// //
|
||||
//// RESAMPLING FILTERS ///
|
||||
|
||||
@@ -27,11 +27,15 @@ class FilteringProgram
|
||||
// list of parameters : uniforms names and values
|
||||
std::map< std::string, float > parameters_;
|
||||
|
||||
// list of texture inputs : uniform sampler2D names and source id
|
||||
std::map< std::string, uint64_t > textures_;
|
||||
|
||||
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::string &filename = std::string());
|
||||
const std::map<std::string, float> ¶meters, const std::string &filename = std::string(),
|
||||
const std::map<std::string, uint64_t> &textures = std::map<std::string, uint64_t>() );
|
||||
FilteringProgram(const FilteringProgram &other);
|
||||
|
||||
FilteringProgram& operator= (const FilteringProgram& other);
|
||||
@@ -67,6 +71,18 @@ public:
|
||||
bool hasParameter(const std::string &p);
|
||||
void removeParameter(const std::string &p);
|
||||
|
||||
// set the list of textures
|
||||
inline void setTextures(const std::map< std::string, uint64_t > &textures) { textures_ = textures; }
|
||||
|
||||
// get the list of textures
|
||||
inline std::map< std::string, uint64_t > textures() const { return textures_; }
|
||||
|
||||
// get / set texture
|
||||
inline void clearTextures() { textures_.clear(); }
|
||||
inline void setTexture(const std::string &t, uint64_t id) { textures_[t] = id; }
|
||||
bool hasTexture(const std::string &t);
|
||||
void removeTexture(const std::string &t);
|
||||
|
||||
// globals
|
||||
static std::string getFilterCodeInputs();
|
||||
static std::string getFilterCodeDefault();
|
||||
@@ -95,6 +111,8 @@ public:
|
||||
|
||||
// list of uniforms to control shader
|
||||
std::map< std::string, float > uniforms_;
|
||||
// list of uniforms to control shader textures id
|
||||
std::map< std::string, uint > sampler2D_;
|
||||
bool uniforms_changed_;
|
||||
|
||||
ImageFilteringShader();
|
||||
@@ -131,6 +149,10 @@ public:
|
||||
void setProgramParameters(const std::map< std::string, float > ¶meters);
|
||||
void setProgramParameter(const std::string &p, float value);
|
||||
|
||||
// update textures of program
|
||||
void setProgramTextures(const std::map< std::string, uint64_t > &textures);
|
||||
void setProgramTexture(const std::string &t, uint64_t id);
|
||||
|
||||
// implementation of FrameBufferFilter
|
||||
Type type() const override { return FrameBufferFilter::FILTER_IMAGE; }
|
||||
uint texture () const override;
|
||||
|
||||
@@ -1555,6 +1555,23 @@ void SessionLoader::visit (AlphaFilter& f)
|
||||
f.setProgramParameters( get_parameters_(xmlCurrent_->FirstChildElement("parameters")) );
|
||||
}
|
||||
|
||||
std::map< std::string, uint64_t > get_textures_(XMLElement* textures)
|
||||
{
|
||||
std::map< std::string, uint64_t > filter_params;
|
||||
if (textures) {
|
||||
XMLElement* param = textures->FirstChildElement("sampler2D");
|
||||
for( ; param ; param = param->NextSiblingElement())
|
||||
{
|
||||
uint64_t val = 0.f;
|
||||
param->QueryUnsigned64Attribute("id", &val);
|
||||
const char * name;
|
||||
if ( param->QueryStringAttribute("name", &name) == XML_SUCCESS && name != NULL)
|
||||
filter_params[name] = val;
|
||||
}
|
||||
}
|
||||
return filter_params;
|
||||
}
|
||||
|
||||
void SessionLoader::visit (ImageFilter& f)
|
||||
{
|
||||
std::pair< std::string, std::string > filter_codes;
|
||||
@@ -1586,9 +1603,12 @@ void SessionLoader::visit (ImageFilter& f)
|
||||
// image filter parameters
|
||||
std::map< std::string, float > filter_params = get_parameters_(xmlCurrent_->FirstChildElement("parameters"));
|
||||
|
||||
// image filter textures
|
||||
std::map< std::string, uint64_t > filter_textures = get_textures_(xmlCurrent_->FirstChildElement("textures"));
|
||||
|
||||
// set image filter program and parameters
|
||||
f.setProgram( FilteringProgram(filter_name, filter_codes.first, filter_codes.second,
|
||||
filter_params, filter_filename) );
|
||||
filter_params, filter_filename, filter_textures) );
|
||||
|
||||
// set global iMouse
|
||||
XMLElement* imouse = xmlCurrent_->FirstChildElement("iMouse");
|
||||
|
||||
@@ -810,6 +810,20 @@ void SessionVisitor::visit (AlphaFilter& f)
|
||||
xmlCurrent_->InsertEndChild( list_parameters_(xmlDoc_, f.program().parameters()) );
|
||||
}
|
||||
|
||||
|
||||
XMLElement *list_textures_(tinyxml2::XMLDocument *doc, std::map< std::string, uint64_t > filter_params)
|
||||
{
|
||||
XMLElement *parameters = doc->NewElement( "textures" );
|
||||
for (auto p = filter_params.begin(); p != filter_params.end(); ++p)
|
||||
{
|
||||
XMLElement *param = doc->NewElement( "sampler2D" );
|
||||
param->SetAttribute("name", p->first.c_str() );
|
||||
param->SetAttribute("id", p->second );
|
||||
parameters->InsertEndChild(param);
|
||||
}
|
||||
return parameters;
|
||||
}
|
||||
|
||||
void SessionVisitor::visit (ImageFilter& f)
|
||||
{
|
||||
xmlCurrent_->SetAttribute("name", f.program().name().c_str() );
|
||||
@@ -834,6 +848,9 @@ void SessionVisitor::visit (ImageFilter& f)
|
||||
// image filter parameters
|
||||
xmlCurrent_->InsertEndChild( list_parameters_(xmlDoc_, f.program().parameters()) );
|
||||
|
||||
// image filter texture inputs
|
||||
xmlCurrent_->InsertEndChild( list_textures_(xmlDoc_, f.program().textures()) );
|
||||
|
||||
// global iMouse
|
||||
XMLElement *imouse = xmlDoc_->NewElement("iMouse");
|
||||
imouse->InsertEndChild( XMLElementFromGLM(xmlDoc_, FilteringProgram::iMouse) );
|
||||
|
||||
@@ -167,6 +167,7 @@ void ShaderEditWindow::BuildShader()
|
||||
|
||||
// set parameters
|
||||
filters_[current_].setParameters(current_->program().parameters());
|
||||
filters_[current_].setTextures(current_->program().textures());
|
||||
|
||||
// change the filter of the current image filter
|
||||
// => this triggers compilation of shader
|
||||
|
||||
Reference in New Issue
Block a user