mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-14 11:49:59 +01:00
Source callbacks for Image Processing color correction
Added SourceCallback classes for brightness, contrast, saturation, etc. Added OSC interface to modify color corrections
This commit is contained in:
@@ -32,6 +32,7 @@
|
|||||||
#include "Mixer.h"
|
#include "Mixer.h"
|
||||||
#include "Source.h"
|
#include "Source.h"
|
||||||
#include "SourceCallback.h"
|
#include "SourceCallback.h"
|
||||||
|
#include "ImageProcessingShader.h"
|
||||||
#include "ActionManager.h"
|
#include "ActionManager.h"
|
||||||
#include "SystemToolkit.h"
|
#include "SystemToolkit.h"
|
||||||
#include "tinyxml2Toolkit.h"
|
#include "tinyxml2Toolkit.h"
|
||||||
@@ -659,7 +660,6 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
|||||||
/// e.g. '/vimix/current/resize ff 10.0 2.2'
|
/// e.g. '/vimix/current/resize ff 10.0 2.2'
|
||||||
else if ( attribute.compare(OSC_SOURCE_RESIZE) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_RESIZE) == 0) {
|
||||||
float x = 0.f, y = 0.f;
|
float x = 0.f, y = 0.f;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
arguments >> x;
|
arguments >> x;
|
||||||
}
|
}
|
||||||
@@ -696,13 +696,13 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
|||||||
}
|
}
|
||||||
/// e.g. '/vimix/current/turn f 1.0'
|
/// e.g. '/vimix/current/turn f 1.0'
|
||||||
else if ( attribute.compare(OSC_SOURCE_TURN) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_TURN) == 0) {
|
||||||
float x = 0.f, y = 0.f;
|
float x = 0.f, t = 0.f;
|
||||||
arguments >> x;
|
arguments >> x;
|
||||||
if (arguments.Eos())
|
if (arguments.Eos())
|
||||||
arguments >> osc::EndMessage;
|
arguments >> osc::EndMessage;
|
||||||
else // ignore second argument
|
else
|
||||||
arguments >> y >> osc::EndMessage;
|
arguments >> t >> osc::EndMessage;
|
||||||
target->call( new Turn( x, 0.f), true );
|
target->call( new Turn( x, t), true );
|
||||||
}
|
}
|
||||||
/// e.g. '/vimix/current/angle f 3.1416'
|
/// e.g. '/vimix/current/angle f 3.1416'
|
||||||
else if ( attribute.compare(OSC_SOURCE_ANGLE) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_ANGLE) == 0) {
|
||||||
@@ -717,7 +717,91 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
|||||||
else if ( attribute.compare(OSC_SOURCE_RESET) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_RESET) == 0) {
|
||||||
target->call( new ResetGeometry(), true );
|
target->call( new ResetGeometry(), true );
|
||||||
}
|
}
|
||||||
/// e.g. '/vimix/current/seek f 1.25'
|
/// e.g. '/vimix/current/brightness f 0.0'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_BRIGHTNESS) == 0) {
|
||||||
|
float val = 0.f, t = 0.f;
|
||||||
|
arguments >> val;
|
||||||
|
if (arguments.Eos())
|
||||||
|
arguments >> osc::EndMessage;
|
||||||
|
else
|
||||||
|
arguments >> t >> osc::EndMessage;
|
||||||
|
target->call( new SetBrightness( val, t ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/contrast f 0.0'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_CONTRAST) == 0) {
|
||||||
|
float val = 0.f, t = 0.f;
|
||||||
|
arguments >> val;
|
||||||
|
if (arguments.Eos())
|
||||||
|
arguments >> osc::EndMessage;
|
||||||
|
else
|
||||||
|
arguments >> t >> osc::EndMessage;
|
||||||
|
target->call( new SetContrast( val, t ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/saturation f 0.0'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_SATURATION) == 0) {
|
||||||
|
float val = 0.f, t = 0.f;
|
||||||
|
arguments >> val;
|
||||||
|
if (arguments.Eos())
|
||||||
|
arguments >> osc::EndMessage;
|
||||||
|
else
|
||||||
|
arguments >> t >> osc::EndMessage;
|
||||||
|
target->call( new SetSaturation( val, t ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/hue f 1.0'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_HUE) == 0) {
|
||||||
|
float val = 0.f, t = 0.f;
|
||||||
|
arguments >> val;
|
||||||
|
if (arguments.Eos())
|
||||||
|
arguments >> osc::EndMessage;
|
||||||
|
else
|
||||||
|
arguments >> t >> osc::EndMessage;
|
||||||
|
target->call( new SetHue( val, t ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/threshold f 1.0'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_THRESHOLD) == 0) {
|
||||||
|
float val = 0.f, t = 0.f;
|
||||||
|
arguments >> val;
|
||||||
|
if (arguments.Eos())
|
||||||
|
arguments >> osc::EndMessage;
|
||||||
|
else
|
||||||
|
arguments >> t >> osc::EndMessage;
|
||||||
|
target->call( new SetThreshold( val, t ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/gamma f 1.0'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_GAMMA) == 0) {
|
||||||
|
glm::vec4 g = target->processingShader()->gamma;
|
||||||
|
float t = 0.f;
|
||||||
|
arguments >> g.w;
|
||||||
|
if (arguments.Eos())
|
||||||
|
arguments >> osc::EndMessage;
|
||||||
|
else
|
||||||
|
arguments >> t >> osc::EndMessage;
|
||||||
|
target->call( new SetGamma( g, t ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/color fff 1.0 0.5 0.9'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_COLOR) == 0) {
|
||||||
|
glm::vec4 g = target->processingShader()->gamma;
|
||||||
|
float t = 0.f;
|
||||||
|
arguments >> g.x >> g.y >> g.z;
|
||||||
|
if (arguments.Eos())
|
||||||
|
arguments >> osc::EndMessage;
|
||||||
|
else
|
||||||
|
arguments >> t >> osc::EndMessage;
|
||||||
|
target->call( new SetGamma( g, t ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/invert f 1'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_INVERT) == 0) {
|
||||||
|
float v = 0.f;
|
||||||
|
arguments >> v >> osc::EndMessage;
|
||||||
|
target->call( new SetInvert( v ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/posterize f 1'
|
||||||
|
else if ( attribute.compare(OSC_SOURCE_POSTERIZE) == 0) {
|
||||||
|
float v = 0.f;
|
||||||
|
arguments >> v >> osc::EndMessage;
|
||||||
|
target->call( new SetPosterize( v ), true );
|
||||||
|
}
|
||||||
|
/// e.g. '/vimix/current/seek f 0.25'
|
||||||
else if ( attribute.compare(OSC_SOURCE_SEEK) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_SEEK) == 0) {
|
||||||
float t = 0.f;
|
float t = 0.f;
|
||||||
arguments >> t >> osc::EndMessage;
|
arguments >> t >> osc::EndMessage;
|
||||||
|
|||||||
@@ -47,6 +47,15 @@
|
|||||||
#define OSC_SOURCE_SIZE "/size"
|
#define OSC_SOURCE_SIZE "/size"
|
||||||
#define OSC_SOURCE_ANGLE "/angle"
|
#define OSC_SOURCE_ANGLE "/angle"
|
||||||
#define OSC_SOURCE_SEEK "/seek"
|
#define OSC_SOURCE_SEEK "/seek"
|
||||||
|
#define OSC_SOURCE_BRIGHTNESS "/brightness"
|
||||||
|
#define OSC_SOURCE_CONTRAST "/contrast"
|
||||||
|
#define OSC_SOURCE_SATURATION "/saturation"
|
||||||
|
#define OSC_SOURCE_HUE "/hue"
|
||||||
|
#define OSC_SOURCE_THRESHOLD "/threshold"
|
||||||
|
#define OSC_SOURCE_GAMMA "/gamma"
|
||||||
|
#define OSC_SOURCE_COLOR "/color"
|
||||||
|
#define OSC_SOURCE_POSTERIZE "/posterize"
|
||||||
|
#define OSC_SOURCE_INVERT "/invert"
|
||||||
|
|
||||||
#define OSC_SESSION "/session"
|
#define OSC_SESSION "/session"
|
||||||
#define OSC_SESSION_VERSION "/version"
|
#define OSC_SESSION_VERSION "/version"
|
||||||
|
|||||||
@@ -1347,6 +1347,21 @@ void SessionLoader::visit (SourceCallback &)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionLoader::visit (ValueSourceCallback &c)
|
||||||
|
{
|
||||||
|
float v = 0.f;
|
||||||
|
xmlCurrent_->QueryFloatAttribute("value", &v);
|
||||||
|
c.setValue(v);
|
||||||
|
|
||||||
|
float d = 0.f;
|
||||||
|
xmlCurrent_->QueryFloatAttribute("duration", &d);
|
||||||
|
c.setDuration(d);
|
||||||
|
|
||||||
|
bool b = false;
|
||||||
|
xmlCurrent_->QueryBoolAttribute("bidirectional", &b);
|
||||||
|
c.setBidirectional(b);
|
||||||
|
}
|
||||||
|
|
||||||
void SessionLoader::visit (Play &c)
|
void SessionLoader::visit (Play &c)
|
||||||
{
|
{
|
||||||
bool p = true;
|
bool p = true;
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public:
|
|||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
void visit (SourceCallback&) override;
|
void visit (SourceCallback&) override;
|
||||||
|
void visit (ValueSourceCallback&) override;
|
||||||
void visit (SetAlpha&) override;
|
void visit (SetAlpha&) override;
|
||||||
void visit (SetDepth&) override;
|
void visit (SetDepth&) override;
|
||||||
void visit (SetGeometry&) override;
|
void visit (SetGeometry&) override;
|
||||||
|
|||||||
@@ -889,6 +889,13 @@ void SessionVisitor::visit (SourceCallback &c)
|
|||||||
xmlCurrent_->SetAttribute("type", (uint) c.type());
|
xmlCurrent_->SetAttribute("type", (uint) c.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionVisitor::visit (ValueSourceCallback &c)
|
||||||
|
{
|
||||||
|
xmlCurrent_->SetAttribute("value", c.value());
|
||||||
|
xmlCurrent_->SetAttribute("duration", c.duration());
|
||||||
|
xmlCurrent_->SetAttribute("bidirectional", c.bidirectional());
|
||||||
|
}
|
||||||
|
|
||||||
void SessionVisitor::visit (Play &c)
|
void SessionVisitor::visit (Play &c)
|
||||||
{
|
{
|
||||||
xmlCurrent_->SetAttribute("play", c.value());
|
xmlCurrent_->SetAttribute("play", c.value());
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ public:
|
|||||||
|
|
||||||
// callbacks
|
// callbacks
|
||||||
void visit (SourceCallback&) override;
|
void visit (SourceCallback&) override;
|
||||||
|
void visit (ValueSourceCallback&) override;
|
||||||
void visit (SetAlpha&) override;
|
void visit (SetAlpha&) override;
|
||||||
void visit (SetDepth&) override;
|
void visit (SetDepth&) override;
|
||||||
void visit (SetGeometry&) override;
|
void visit (SetGeometry&) override;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "Source.h"
|
#include "Source.h"
|
||||||
|
#include "ImageProcessingShader.h"
|
||||||
#include "MediaSource.h"
|
#include "MediaSource.h"
|
||||||
#include "MediaPlayer.h"
|
#include "MediaPlayer.h"
|
||||||
#include "UpdateCallback.h"
|
#include "UpdateCallback.h"
|
||||||
@@ -66,6 +67,33 @@ SourceCallback *SourceCallback::create(CallbackType type)
|
|||||||
case SourceCallback::CALLBACK_LOCK:
|
case SourceCallback::CALLBACK_LOCK:
|
||||||
loadedcallback = new Lock;
|
loadedcallback = new Lock;
|
||||||
break;
|
break;
|
||||||
|
case SourceCallback::CALLBACK_SEEK:
|
||||||
|
loadedcallback = new Seek;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_BRIGHTNESS:
|
||||||
|
loadedcallback = new SetBrightness;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_CONTRAST:
|
||||||
|
loadedcallback = new SetContrast;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_SATURATION:
|
||||||
|
loadedcallback = new SetBrightness;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_HUE:
|
||||||
|
loadedcallback = new SetContrast;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_THRESHOLD:
|
||||||
|
loadedcallback = new SetThreshold;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_GAMMA:
|
||||||
|
loadedcallback = new SetGamma;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_INVERT:
|
||||||
|
loadedcallback = new SetInvert;
|
||||||
|
break;
|
||||||
|
case SourceCallback::CALLBACK_POSTERIZE:
|
||||||
|
loadedcallback = new SetPosterize;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -139,6 +167,81 @@ void SourceCallback::update (Source *s, float dt)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ValueSourceCallback::ValueSourceCallback(float target, float ms, bool revert) : SourceCallback(),
|
||||||
|
duration_(ms), start_(0.f), target_(target), bidirectional_(revert)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ValueSourceCallback::update(Source *s, float dt)
|
||||||
|
{
|
||||||
|
SourceCallback::update(s, dt);
|
||||||
|
|
||||||
|
// set start on first time it is ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
start_ = readValue(s);
|
||||||
|
status_ = ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update when active
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
|
||||||
|
// time passed since start
|
||||||
|
float progress = elapsed_ - delay_;
|
||||||
|
|
||||||
|
// time-out or instantaneous
|
||||||
|
if ( !(ABS(duration_) > 0.f) || progress > duration_ ) {
|
||||||
|
// apply target
|
||||||
|
writeValue(s, target_);
|
||||||
|
// done
|
||||||
|
status_ = FINISHED;
|
||||||
|
}
|
||||||
|
// perform iteration of interpolation
|
||||||
|
else {
|
||||||
|
// apply calculated intermediate
|
||||||
|
writeValue(s, glm::mix(start_, target_, progress/duration_) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueSourceCallback::multiply (float factor)
|
||||||
|
{
|
||||||
|
target_ *= factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceCallback *ValueSourceCallback::clone() const
|
||||||
|
{
|
||||||
|
SourceCallback *ret = SourceCallback::create(type());
|
||||||
|
ValueSourceCallback *vsc = static_cast<ValueSourceCallback *>(ret);
|
||||||
|
vsc->setValue( target_ );
|
||||||
|
vsc->setDuration( duration_ );
|
||||||
|
vsc->setBidirectional( bidirectional_ );
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceCallback *ValueSourceCallback::reverse(Source *s) const
|
||||||
|
{
|
||||||
|
SourceCallback *ret = nullptr;
|
||||||
|
if (bidirectional_) {
|
||||||
|
ret = SourceCallback::create(type());
|
||||||
|
ValueSourceCallback *vsc = static_cast<ValueSourceCallback *>(ret);
|
||||||
|
vsc->setValue( readValue(s) );
|
||||||
|
vsc->setDuration( duration_ );
|
||||||
|
vsc->setBidirectional( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ValueSourceCallback::accept(Visitor& v)
|
||||||
|
{
|
||||||
|
SourceCallback::accept(v);
|
||||||
|
v.visit(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ResetGeometry::update(Source *s, float dt)
|
void ResetGeometry::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
SourceCallback::update(s, dt);
|
SourceCallback::update(s, dt);
|
||||||
@@ -168,7 +271,7 @@ SourceCallback *ResetGeometry::clone() const
|
|||||||
SetAlpha::SetAlpha(float alpha, float ms, bool revert) : SourceCallback(),
|
SetAlpha::SetAlpha(float alpha, float ms, bool revert) : SourceCallback(),
|
||||||
duration_(ms), alpha_(alpha), bidirectional_(revert)
|
duration_(ms), alpha_(alpha), bidirectional_(revert)
|
||||||
{
|
{
|
||||||
alpha_ = CLAMP(alpha_, 0.f, 1.f);
|
alpha_ = glm::clamp(alpha_, 0.f, 1.f);
|
||||||
start_ = glm::vec2();
|
start_ = glm::vec2();
|
||||||
target_ = glm::vec2();
|
target_ = glm::vec2();
|
||||||
}
|
}
|
||||||
@@ -221,7 +324,7 @@ void SetAlpha::update(Source *s, float dt)
|
|||||||
|
|
||||||
// perform movement
|
// perform movement
|
||||||
if ( ABS(duration_) > 0.f)
|
if ( ABS(duration_) > 0.f)
|
||||||
s->group(View::MIXING)->translation_ = glm::vec3(start_ + (progress/duration_)*(target_ - start_), s->group(View::MIXING)->translation_.z);
|
s->group(View::MIXING)->translation_ = glm::vec3(glm::mix(start_, target_, progress/duration_), s->group(View::MIXING)->translation_.z);
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress > duration_ ) {
|
if ( progress > duration_ ) {
|
||||||
@@ -343,7 +446,7 @@ void Loom::accept(Visitor& v)
|
|||||||
SetDepth::SetDepth(float target, float ms, bool revert) : SourceCallback(),
|
SetDepth::SetDepth(float target, float ms, bool revert) : SourceCallback(),
|
||||||
duration_(ms), start_(0.f), target_(target), bidirectional_(revert)
|
duration_(ms), start_(0.f), target_(target), bidirectional_(revert)
|
||||||
{
|
{
|
||||||
target_ = CLAMP(target_, MIN_DEPTH, MAX_DEPTH);
|
target_ = glm::clamp(target_, MIN_DEPTH, MAX_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDepth::update(Source *s, float dt)
|
void SetDepth::update(Source *s, float dt)
|
||||||
@@ -365,7 +468,7 @@ void SetDepth::update(Source *s, float dt)
|
|||||||
|
|
||||||
// perform movement
|
// perform movement
|
||||||
if ( ABS(duration_) > 0.f)
|
if ( ABS(duration_) > 0.f)
|
||||||
s->group(View::LAYER)->translation_.z = start_ + (progress/duration_) * (target_ - start_);
|
s->group(View::LAYER)->translation_.z = glm::mix(start_, target_, progress/duration_);
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress > duration_ ) {
|
if ( progress > duration_ ) {
|
||||||
@@ -459,41 +562,40 @@ SourceCallback *RePlay::clone() const
|
|||||||
return new RePlay;
|
return new RePlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Seek::Seek(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
Seek::Seek(float time) : SourceCallback(), target_(time)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Seek::update(Source *s, float dt)
|
float Seek::readValue(Source *s) const
|
||||||
{
|
{
|
||||||
SourceCallback::update(s, dt);
|
double ret = 0.f;
|
||||||
|
// access media player if target source is a media source
|
||||||
|
MediaSource *ms = dynamic_cast<MediaSource *>(s);
|
||||||
|
if (ms != nullptr) {
|
||||||
|
GstClockTime media_duration = ms->mediaplayer()->timeline()->duration();
|
||||||
|
GstClockTime media_position = ms->mediaplayer()->position();
|
||||||
|
|
||||||
// perform seek when ready
|
if (GST_CLOCK_TIME_IS_VALID(media_duration) && media_duration > 0 &&
|
||||||
if ( status_ == READY ){
|
GST_CLOCK_TIME_IS_VALID(media_position) && media_position > 0){
|
||||||
|
ret = static_cast<double>(media_position) / static_cast<double>(media_duration);
|
||||||
// access media player if target source is a media source
|
|
||||||
MediaSource *ms = dynamic_cast<MediaSource *>(s);
|
|
||||||
if (ms != nullptr) {
|
|
||||||
GstClockTime duration = ms->mediaplayer()->timeline()->duration();
|
|
||||||
ms->mediaplayer()->seek( target_ * duration );
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
status_ = FINISHED;
|
return (float)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Seek::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
// access media player if target source is a media source
|
||||||
|
MediaSource *ms = dynamic_cast<MediaSource *>(s);
|
||||||
|
if (ms != nullptr) {
|
||||||
|
GstClockTime media_duration = ms->mediaplayer()->timeline()->duration();
|
||||||
|
double media_position = glm::clamp( (double) val, 0.0, 1.0);
|
||||||
|
if (GST_CLOCK_TIME_IS_VALID(media_duration))
|
||||||
|
ms->mediaplayer()->seek( media_position * media_duration );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceCallback *Seek::clone() const
|
|
||||||
{
|
|
||||||
return new Seek(target_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Seek::accept(Visitor& v)
|
|
||||||
{
|
|
||||||
SourceCallback::accept(v);
|
|
||||||
v.visit(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SetGeometry::SetGeometry(const Group *g, float ms, bool revert) : SourceCallback(),
|
SetGeometry::SetGeometry(const Group *g, float ms, bool revert) : SourceCallback(),
|
||||||
duration_(ms), bidirectional_(revert)
|
duration_(ms), bidirectional_(revert)
|
||||||
{
|
{
|
||||||
@@ -531,11 +633,10 @@ void SetGeometry::update(Source *s, float dt)
|
|||||||
|
|
||||||
// perform movement
|
// perform movement
|
||||||
if ( ABS(duration_) > 0.f){
|
if ( ABS(duration_) > 0.f){
|
||||||
float ratio = progress / duration_;
|
|
||||||
Group intermediate;
|
Group intermediate;
|
||||||
intermediate.translation_ = (1.f - ratio) * start_.translation_ + ratio * target_.translation_;
|
intermediate.translation_ = glm::mix(start_.translation_, target_.translation_, progress/duration_);
|
||||||
intermediate.scale_ = (1.f - ratio) * start_.scale_ + ratio * target_.scale_;
|
intermediate.scale_ = glm::mix(start_.scale_, target_.scale_, progress/duration_);
|
||||||
intermediate.rotation_ = (1.f - ratio) * start_.rotation_ + ratio * target_.rotation_;
|
intermediate.rotation_ = glm::mix(start_.rotation_, target_.rotation_, progress/duration_);
|
||||||
// apply geometry
|
// apply geometry
|
||||||
s->group(View::GEOMETRY)->copyTransform(&intermediate);
|
s->group(View::GEOMETRY)->copyTransform(&intermediate);
|
||||||
s->touch();
|
s->touch();
|
||||||
@@ -727,3 +828,178 @@ void Turn::accept(Visitor& v)
|
|||||||
SourceCallback::accept(v);
|
SourceCallback::accept(v);
|
||||||
v.visit(*this);
|
v.visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetBrightness::SetBrightness(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
|
{
|
||||||
|
target_ = glm::clamp(target_, -1.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SetBrightness::readValue(Source *s) const
|
||||||
|
{
|
||||||
|
return s->processingShader()->brightness;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetBrightness::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
if (s->imageProcessingEnabled())
|
||||||
|
s->processingShader()->brightness = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetContrast::SetContrast(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
|
{
|
||||||
|
target_ = glm::clamp(target_, -1.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SetContrast::readValue(Source *s) const
|
||||||
|
{
|
||||||
|
return s->processingShader()->contrast;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetContrast::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
if (s->imageProcessingEnabled())
|
||||||
|
s->processingShader()->contrast = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSaturation::SetSaturation(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
|
{
|
||||||
|
target_ = glm::clamp(target_, -1.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SetSaturation::readValue(Source *s) const
|
||||||
|
{
|
||||||
|
return s->processingShader()->saturation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSaturation::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
if (s->imageProcessingEnabled())
|
||||||
|
s->processingShader()->saturation = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetHue::SetHue(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
|
{
|
||||||
|
target_ = glm::clamp(target_, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SetHue::readValue(Source *s) const
|
||||||
|
{
|
||||||
|
return s->processingShader()->hueshift;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHue::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
if (s->imageProcessingEnabled())
|
||||||
|
s->processingShader()->hueshift = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetThreshold::SetThreshold(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
|
{
|
||||||
|
target_ = glm::clamp(target_, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SetThreshold::readValue(Source *s) const
|
||||||
|
{
|
||||||
|
return s->processingShader()->threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetThreshold::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
if (s->imageProcessingEnabled())
|
||||||
|
s->processingShader()->threshold = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SetInvert::SetInvert(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
|
{
|
||||||
|
target_ = glm::clamp(target_, 0.f, 2.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SetInvert::readValue(Source *s) const
|
||||||
|
{
|
||||||
|
return static_cast<float>(s->processingShader()->invert);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInvert::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
if (s->imageProcessingEnabled())
|
||||||
|
s->processingShader()->invert = static_cast<int>(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPosterize::SetPosterize(float v, float ms, bool r) : ValueSourceCallback(v, ms, r)
|
||||||
|
{
|
||||||
|
target_ = glm::clamp(target_, 0.f, 128.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float SetPosterize::readValue(Source *s) const
|
||||||
|
{
|
||||||
|
return static_cast<float>(s->processingShader()->nbColors);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPosterize::writeValue(Source *s, float val)
|
||||||
|
{
|
||||||
|
if (s->imageProcessingEnabled())
|
||||||
|
s->processingShader()->nbColors = static_cast<int>(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SetGamma::SetGamma(glm::vec4 g, float ms, bool revert) : SourceCallback(),
|
||||||
|
duration_(ms), start_(glm::vec4()), target_(g), bidirectional_(revert)
|
||||||
|
{
|
||||||
|
start_ = glm::clamp(start_, glm::vec4(0.f), glm::vec4(10.f));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetGamma::update(Source *s, float dt)
|
||||||
|
{
|
||||||
|
SourceCallback::update(s, dt);
|
||||||
|
|
||||||
|
if (!s->imageProcessingEnabled())
|
||||||
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
// set start on first time it is ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
start_ = s->processingShader()->gamma;
|
||||||
|
status_ = ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update when active
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
|
||||||
|
// time passed since start
|
||||||
|
float progress = elapsed_ - delay_;
|
||||||
|
|
||||||
|
// time-out or instantaneous
|
||||||
|
if ( !(ABS(duration_) > 0.f) || progress > duration_ ) {
|
||||||
|
// apply target
|
||||||
|
s->processingShader()->gamma = target_;
|
||||||
|
// done
|
||||||
|
status_ = FINISHED;
|
||||||
|
}
|
||||||
|
// perform iteration of interpolation
|
||||||
|
else {
|
||||||
|
// apply calculated intermediate
|
||||||
|
s->processingShader()->gamma = glm::mix(start_, target_, progress/duration_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetGamma::multiply (float factor)
|
||||||
|
{
|
||||||
|
target_ *= factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceCallback *SetGamma::clone() const
|
||||||
|
{
|
||||||
|
return new SetGamma(target_, duration_, bidirectional_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceCallback *SetGamma::reverse(Source *s) const
|
||||||
|
{
|
||||||
|
return bidirectional_ ? new SetGamma(s->processingShader()->gamma, duration_) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetGamma::accept(Visitor& v)
|
||||||
|
{
|
||||||
|
SourceCallback::accept(v);
|
||||||
|
v.visit(*this);
|
||||||
|
}
|
||||||
|
|||||||
194
SourceCallback.h
194
SourceCallback.h
@@ -7,25 +7,46 @@
|
|||||||
|
|
||||||
class Visitor;
|
class Visitor;
|
||||||
class Source;
|
class Source;
|
||||||
|
class ImageProcessingShader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The SourceCallback class defines operations on Sources that
|
||||||
|
* are applied at each update of Source. A SourceCallback is added to
|
||||||
|
* a source with; source->call( new SourceCallback );
|
||||||
|
*
|
||||||
|
* A source contains a list of SourceCallbacks. At each update(dt)
|
||||||
|
* a source calls the update on all its SourceCallbacks.
|
||||||
|
* The SourceCallback is created as PENDING, and becomes ACTIVE after
|
||||||
|
* the first update call.
|
||||||
|
* The SourceCallback is removed from the list when FINISHED.
|
||||||
|
*
|
||||||
|
*/
|
||||||
class SourceCallback
|
class SourceCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CALLBACK_GENERIC = 0,
|
CALLBACK_GENERIC = 0,
|
||||||
CALLBACK_ALPHA = 1,
|
CALLBACK_ALPHA,
|
||||||
CALLBACK_LOOM = 2,
|
CALLBACK_LOOM,
|
||||||
CALLBACK_GEOMETRY = 3,
|
CALLBACK_GEOMETRY,
|
||||||
CALLBACK_GRAB = 4,
|
CALLBACK_GRAB,
|
||||||
CALLBACK_RESIZE = 5,
|
CALLBACK_RESIZE,
|
||||||
CALLBACK_TURN = 6,
|
CALLBACK_TURN,
|
||||||
CALLBACK_DEPTH = 7,
|
CALLBACK_DEPTH,
|
||||||
CALLBACK_PLAY = 8,
|
CALLBACK_PLAY,
|
||||||
CALLBACK_REPLAY = 9,
|
CALLBACK_REPLAY,
|
||||||
CALLBACK_RESETGEO = 10,
|
CALLBACK_RESETGEO,
|
||||||
CALLBACK_LOCK = 11,
|
CALLBACK_LOCK,
|
||||||
CALLBACK_SEEK = 12
|
CALLBACK_SEEK,
|
||||||
|
CALLBACK_BRIGHTNESS,
|
||||||
|
CALLBACK_CONTRAST,
|
||||||
|
CALLBACK_SATURATION,
|
||||||
|
CALLBACK_HUE,
|
||||||
|
CALLBACK_THRESHOLD,
|
||||||
|
CALLBACK_GAMMA,
|
||||||
|
CALLBACK_INVERT,
|
||||||
|
CALLBACK_POSTERIZE
|
||||||
} CallbackType;
|
} CallbackType;
|
||||||
|
|
||||||
static SourceCallback *create(CallbackType type);
|
static SourceCallback *create(CallbackType type);
|
||||||
@@ -59,6 +80,43 @@ protected:
|
|||||||
float elapsed_;
|
float elapsed_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The ValueSourceCallback class is a generic type of
|
||||||
|
* callback which operates on a single float value of a source.
|
||||||
|
*
|
||||||
|
* ValueSourceCallback are practical for creating SourceCallbacks
|
||||||
|
* that change a single attribute of a source, that can be read
|
||||||
|
* and write on the source object.
|
||||||
|
*/
|
||||||
|
class ValueSourceCallback : public SourceCallback
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
float duration_;
|
||||||
|
float start_;
|
||||||
|
float target_;
|
||||||
|
bool bidirectional_;
|
||||||
|
|
||||||
|
virtual float readValue(Source *s) const = 0;
|
||||||
|
virtual void writeValue(Source *s, float val) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ValueSourceCallback (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
|
||||||
|
float value () const { return target_;}
|
||||||
|
void setValue (float v) { target_ = v; }
|
||||||
|
float duration () const { return duration_;}
|
||||||
|
void setDuration (float ms) { duration_ = ms; }
|
||||||
|
bool bidirectional () const { return bidirectional_;}
|
||||||
|
void setBidirectional (bool on) { bidirectional_ = on; }
|
||||||
|
|
||||||
|
void update (Source *s, float) override;
|
||||||
|
void multiply (float factor) override;
|
||||||
|
SourceCallback *clone () const override;
|
||||||
|
SourceCallback *reverse(Source *s) const override;
|
||||||
|
void accept (Visitor& v) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class SetAlpha : public SourceCallback
|
class SetAlpha : public SourceCallback
|
||||||
{
|
{
|
||||||
float duration_;
|
float duration_;
|
||||||
@@ -178,22 +236,6 @@ public:
|
|||||||
CallbackType type () const override { return CALLBACK_REPLAY; }
|
CallbackType type () const override { return CALLBACK_REPLAY; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Seek : public SourceCallback
|
|
||||||
{
|
|
||||||
float target_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Seek (float time = 0.f);
|
|
||||||
|
|
||||||
float value () const { return target_;}
|
|
||||||
void setValue (float t) { target_ = t; }
|
|
||||||
|
|
||||||
void update (Source *s, float dt) override;
|
|
||||||
SourceCallback *clone() const override;
|
|
||||||
CallbackType type () const override { return CALLBACK_SEEK; }
|
|
||||||
void accept (Visitor& v) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ResetGeometry : public SourceCallback
|
class ResetGeometry : public SourceCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -293,5 +335,101 @@ public:
|
|||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Seek : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
Seek (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_SEEK; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetBrightness : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
SetBrightness (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_BRIGHTNESS; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetContrast : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
SetContrast (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_CONTRAST; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetSaturation : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
SetSaturation (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_SATURATION; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetHue : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
SetHue (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_HUE; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetThreshold : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
SetThreshold (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_THRESHOLD; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetInvert : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
SetInvert (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_INVERT; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetPosterize : public ValueSourceCallback
|
||||||
|
{
|
||||||
|
float readValue(Source *s) const override;
|
||||||
|
void writeValue(Source *s, float val) override;
|
||||||
|
public:
|
||||||
|
SetPosterize (float v = 0.f, float ms = 0.f, bool revert = false);
|
||||||
|
CallbackType type () const override { return CALLBACK_POSTERIZE; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SetGamma : public SourceCallback
|
||||||
|
{
|
||||||
|
float duration_;
|
||||||
|
glm::vec4 start_;
|
||||||
|
glm::vec4 target_;
|
||||||
|
bool bidirectional_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SetGamma (glm::vec4 g = glm::vec4(), float ms = 0.f, bool revert = false);
|
||||||
|
|
||||||
|
glm::vec4 value () const { return target_; }
|
||||||
|
void setValue (glm::vec4 g) { target_ = g; }
|
||||||
|
float duration () const { return duration_; }
|
||||||
|
void setDuration (float ms) { duration_ = ms; }
|
||||||
|
bool bidirectional () const { return bidirectional_; }
|
||||||
|
void setBidirectional (bool on) { bidirectional_ = on; }
|
||||||
|
|
||||||
|
void update (Source *s, float) override;
|
||||||
|
void multiply (float factor) override;
|
||||||
|
SourceCallback *clone () const override;
|
||||||
|
SourceCallback *reverse(Source *s) const override;
|
||||||
|
CallbackType type () const override { return CALLBACK_GAMMA; }
|
||||||
|
void accept (Visitor& v) override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // SOURCECALLBACK_H
|
#endif // SOURCECALLBACK_H
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ class AlphaFilter;
|
|||||||
class ImageFilter;
|
class ImageFilter;
|
||||||
|
|
||||||
class SourceCallback;
|
class SourceCallback;
|
||||||
|
class ValueSourceCallback;
|
||||||
class SetAlpha;
|
class SetAlpha;
|
||||||
class SetDepth;
|
class SetDepth;
|
||||||
class SetGeometry;
|
class SetGeometry;
|
||||||
@@ -119,6 +120,7 @@ public:
|
|||||||
virtual void visit (ImageFilter&) {}
|
virtual void visit (ImageFilter&) {}
|
||||||
|
|
||||||
virtual void visit (SourceCallback&) {}
|
virtual void visit (SourceCallback&) {}
|
||||||
|
virtual void visit (ValueSourceCallback&) {}
|
||||||
virtual void visit (SetAlpha&) {}
|
virtual void visit (SetAlpha&) {}
|
||||||
virtual void visit (SetDepth&) {}
|
virtual void visit (SetDepth&) {}
|
||||||
virtual void visit (SetGeometry&) {}
|
virtual void visit (SetGeometry&) {}
|
||||||
|
|||||||
Reference in New Issue
Block a user