BugFix Set Clone filter Uniform using callback for OSC

Async call to setProgramParameter is unsave (Issue  #149).
This commit is contained in:
Bruno Herbelin
2024-10-13 14:02:08 +02:00
parent 460fa6c8e6
commit c4ad80f3b9
3 changed files with 116 additions and 21 deletions

View File

@@ -961,7 +961,7 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
}
/// e.g. '/vimix/current/contents s text'
else if (attribute.compare(OSC_SOURCE_CONTENTS) == 0) {
// try by client name if given: remove all streams with that name
// get text
const char *label = nullptr;
arguments >> label >> osc::EndMessage;
TextSource *textsrc = dynamic_cast<TextSource *>(target);
@@ -971,27 +971,17 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
}
/// e.g. '/vimix/current/uniform sf var 0.5'
else if (attribute.compare(OSC_SOURCE_UNIFORM) == 0) {
std::string uniform_name;
float t = 0.f;
// get uniform name and value
float uniform_value = NAN;
// get uniform name
const char *str = nullptr;
arguments >> str;
if (str)
{
uniform_name = std::string(str);
// get uniform value
arguments >> uniform_value >> osc::EndMessage;
// apply to ImageFilter source only
CloneSource *clonesrc = dynamic_cast<CloneSource *>(target);
if (clonesrc) {
ImageFilter *f = dynamic_cast<ImageFilter *>(clonesrc->filter());
if (f) {
f->setProgramParameter(uniform_name, uniform_value);
}
}
arguments >> str >> uniform_value;
if (arguments.Eos())
arguments >> osc::EndMessage;
else
arguments >> t >> osc::EndMessage;
if (str && uniform_value != NAN) {
target->call(new SetFilterUniform(std::string(str), uniform_value, t), true);
}
}
/// e.g. '/vimix/current/filter sf blur 0.5'

View File

@@ -1334,3 +1334,83 @@ void SetFilter::accept(Visitor& v)
v.visit(*this);
}
SetFilterUniform::SetFilterUniform(const std::string &uniform, float value, float ms)
: SourceCallback()
, uniform_(uniform)
, target_(value)
, start_(0.f)
, duration_(ms)
{
imagefilter = nullptr;
}
void SetFilterUniform::update(Source *s, float dt)
{
SourceCallback::update(s, dt);
CloneSource *clonesrc = dynamic_cast<CloneSource *>(s);
if (s->locked() || !clonesrc)
status_ = FINISHED;
// set start on first time it is ready
if (status_ == READY) {
// by default it will finish if all tests below fail
status_ = FINISHED;
// if there is an image filter in the clone source
imagefilter = dynamic_cast<ImageFilter *>(clonesrc->filter());
if (imagefilter) {
// get the list of parameters
std::map<std::string, float> params = imagefilter->program().parameters();
// if there is a parameter named as given
auto p = params.find(uniform_);
if (p != params.end()) {
// set start value to the current value
start_ = p->second;
// if a valid target value is given
if (!std::isnan(target_))
// then activate for value update
status_ = ACTIVE;
}
else
Log::Info("Filter : unknown uniform '%s'", uniform_.c_str());
}
}
// set value
if (status_ == ACTIVE && imagefilter) {
// time passed since start
float progress = elapsed_ - delay_;
// time-out or instantaneous
if (!(ABS(duration_) > 0.f) || progress > duration_) {
// apply target value
imagefilter->setProgramParameter(uniform_, target_);
// done
status_ = FINISHED;
}
else {
// apply calculated intermediate value
imagefilter->setProgramParameter(uniform_,
glm::mix(start_, target_, progress / duration_));
}
}
}
void SetFilterUniform::multiply (float factor)
{
target_ *= factor;
}
SourceCallback *SetFilterUniform::clone() const
{
return new SetFilterUniform(uniform_, target_, duration_);
}
void SetFilterUniform::accept(Visitor& v)
{
SourceCallback::accept(v);
v.visit(*this);
}

View File

@@ -51,7 +51,8 @@ public:
CALLBACK_THRESHOLD,
CALLBACK_INVERT,
CALLBACK_POSTERIZE,
CALLBACK_FILTER
CALLBACK_FILTER,
CALLBACK_FILTER_UNIFORM
} CallbackType;
static SourceCallback *create(CallbackType type);
@@ -507,4 +508,28 @@ public:
void accept (Visitor& v) override;
};
class SetFilterUniform : public SourceCallback
{
std::string uniform_;
float target_;
float start_;
float duration_;
class ImageFilter *imagefilter;
public:
SetFilterUniform (const std::string &uniform = std::string(),
float value = NAN, float ms = 0.f);
float value () const { return target_; }
void setValue (float g) { target_ = g; }
float duration () const { return duration_; }
void setDuration (float ms) { duration_ = ms; }
void update (Source *s, float) override;
void multiply (float factor) override;
SourceCallback *clone () const override;
CallbackType type () const override { return CALLBACK_FILTER_UNIFORM; }
void accept (Visitor& v) override;
};
#endif // SOURCECALLBACK_H