mirror of
https://github.com/brunoherbelin/vimix.git
synced 2025-12-11 18:34:58 +01:00
Reimplementation of SourceInputCallbacks into Session
Session should be the object holding the list of inputs parameters (e.g. synchrony) and the list of source callbacks. This also avoids mixing input when copying sources. Code could be improved but is operational.
This commit is contained in:
@@ -35,6 +35,7 @@
|
|||||||
#include "ActionManager.h"
|
#include "ActionManager.h"
|
||||||
#include "SystemToolkit.h"
|
#include "SystemToolkit.h"
|
||||||
#include "tinyxml2Toolkit.h"
|
#include "tinyxml2Toolkit.h"
|
||||||
|
#include "Metronome.h"
|
||||||
|
|
||||||
#include "UserInterfaceManager.h"
|
#include "UserInterfaceManager.h"
|
||||||
#include "RenderingManager.h"
|
#include "RenderingManager.h"
|
||||||
@@ -588,7 +589,7 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
|||||||
else if ( attribute.compare(OSC_SOURCE_LOOM) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_LOOM) == 0) {
|
||||||
float x = 1.f;
|
float x = 1.f;
|
||||||
arguments >> x >> osc::EndMessage;
|
arguments >> x >> osc::EndMessage;
|
||||||
target->call( new Loom(x), true );
|
target->call( new Loom(x, 0.f), true );
|
||||||
// this will require to send feedback status about source
|
// this will require to send feedback status about source
|
||||||
send_feedback = true;
|
send_feedback = true;
|
||||||
}
|
}
|
||||||
@@ -608,13 +609,13 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
|||||||
else if ( attribute.compare(OSC_SOURCE_GRAB) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_GRAB) == 0) {
|
||||||
float x = 0.f, y = 0.f;
|
float x = 0.f, y = 0.f;
|
||||||
arguments >> x >> y >> osc::EndMessage;
|
arguments >> x >> y >> osc::EndMessage;
|
||||||
target->call( new Grab( x, y), true );
|
target->call( new Grab( x, y, 0.f), true );
|
||||||
}
|
}
|
||||||
/// e.g. '/vimix/current/scale ff 10.0 2.2'
|
/// e.g. '/vimix/current/scale 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;
|
||||||
arguments >> x >> y >> osc::EndMessage;
|
arguments >> x >> y >> osc::EndMessage;
|
||||||
target->call( new Resize( x, y), true );
|
target->call( new Resize( x, y, 0.f), true );
|
||||||
}
|
}
|
||||||
/// 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) {
|
||||||
@@ -624,7 +625,7 @@ bool Control::receiveSourceAttribute(Source *target, const std::string &attribut
|
|||||||
arguments >> osc::EndMessage;
|
arguments >> osc::EndMessage;
|
||||||
else // ignore second argument
|
else // ignore second argument
|
||||||
arguments >> y >> osc::EndMessage;
|
arguments >> y >> osc::EndMessage;
|
||||||
target->call( new Turn( x ), true );
|
target->call( new Turn( x, 0.f), true );
|
||||||
}
|
}
|
||||||
/// e.g. '/vimix/current/reset'
|
/// e.g. '/vimix/current/reset'
|
||||||
else if ( attribute.compare(OSC_SOURCE_RESET) == 0) {
|
else if ( attribute.compare(OSC_SOURCE_RESET) == 0) {
|
||||||
@@ -871,6 +872,7 @@ void Control::sendOutputStatus(const IpEndpointName &remoteEndpoint)
|
|||||||
socket.Send( p.Data(), p.Size() );
|
socket.Send( p.Data(), p.Size() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Control::keyboardCalback(GLFWwindow* window, int key, int, int action, int mods)
|
void Control::keyboardCalback(GLFWwindow* window, int key, int, int action, int mods)
|
||||||
{
|
{
|
||||||
if (UserInterface::manager().keyboardAvailable() && !mods )
|
if (UserInterface::manager().keyboardAvailable() && !mods )
|
||||||
@@ -894,7 +896,7 @@ void Control::keyboardCalback(GLFWwindow* window, int key, int, int action, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Control::inputActive(uint id)
|
bool Control::inputActive (uint id)
|
||||||
{
|
{
|
||||||
input_access_.lock();
|
input_access_.lock();
|
||||||
const bool ret = input_active[MIN(id,INPUT_MAX)];
|
const bool ret = input_active[MIN(id,INPUT_MAX)];
|
||||||
@@ -903,7 +905,7 @@ bool Control::inputActive(uint id)
|
|||||||
return ret && !Settings::application.mapping.disabled;
|
return ret && !Settings::application.mapping.disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
float Control::inputValue(uint id)
|
float Control::inputValue (uint id)
|
||||||
{
|
{
|
||||||
input_access_.lock();
|
input_access_.lock();
|
||||||
const float ret = input_values[MIN(id,INPUT_MAX)];
|
const float ret = input_values[MIN(id,INPUT_MAX)];
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ public:
|
|||||||
|
|
||||||
bool inputActive (uint id);
|
bool inputActive (uint id);
|
||||||
float inputValue (uint id);
|
float inputValue (uint id);
|
||||||
|
float inputDelay (uint id);
|
||||||
static std::string inputLabel(uint id);
|
static std::string inputLabel(uint id);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -247,6 +247,23 @@ void Metronome::executeAtPhase( std::function<void()> f )
|
|||||||
std::thread( delay, f, timeToPhase() ).detach();
|
std::thread( delay, f, timeToPhase() ).detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Metronome::timeToSync(Synchronicity sync)
|
||||||
|
{
|
||||||
|
float ret = 0.f;
|
||||||
|
if ( sync > Metronome::SYNC_BEAT ) {
|
||||||
|
// SYNC TO PHASE
|
||||||
|
std::chrono::duration<float, std::milli> fp_ms = Metronome::manager().timeToPhase();
|
||||||
|
ret = fp_ms.count();
|
||||||
|
}
|
||||||
|
else if ( sync > Metronome::SYNC_NONE ) {
|
||||||
|
// SYNC TO BEAT
|
||||||
|
std::chrono::duration<float, std::milli> fp_ms = Metronome::manager().timeToBeat();
|
||||||
|
ret = fp_ms.count();
|
||||||
|
}
|
||||||
|
// SYNC NONE
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
size_t Metronome::peers() const
|
size_t Metronome::peers() const
|
||||||
{
|
{
|
||||||
return link_.numPeers();
|
return link_.numPeers();
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ public:
|
|||||||
std::chrono::microseconds timeToPhase();
|
std::chrono::microseconds timeToPhase();
|
||||||
void executeAtPhase( std::function<void()> f );
|
void executeAtPhase( std::function<void()> f );
|
||||||
|
|
||||||
|
// get time to sync, in milisecond
|
||||||
|
float timeToSync(Synchronicity sync);
|
||||||
|
|
||||||
|
// get number of connected peers
|
||||||
size_t peers () const;
|
size_t peers () const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
217
Session.cpp
217
Session.cpp
@@ -31,6 +31,8 @@
|
|||||||
#include "SessionSource.h"
|
#include "SessionSource.h"
|
||||||
#include "RenderSource.h"
|
#include "RenderSource.h"
|
||||||
#include "MixingGroup.h"
|
#include "MixingGroup.h"
|
||||||
|
#include "ControlManager.h"
|
||||||
|
#include "SourceCallback.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#include "Session.h"
|
#include "Session.h"
|
||||||
@@ -62,6 +64,8 @@ Session::Session() : active_(true), activation_threshold_(MIXING_MIN_THRESHOLD),
|
|||||||
config_[View::TEXTURE]->scale_ = Settings::application.views[View::TEXTURE].default_scale;
|
config_[View::TEXTURE]->scale_ = Settings::application.views[View::TEXTURE].default_scale;
|
||||||
config_[View::TEXTURE]->translation_ = Settings::application.views[View::TEXTURE].default_translation;
|
config_[View::TEXTURE]->translation_ = Settings::application.views[View::TEXTURE].default_translation;
|
||||||
|
|
||||||
|
input_sync_.resize(INPUT_MAX, Metronome::SYNC_NONE);
|
||||||
|
|
||||||
snapshots_.xmlDoc_ = new tinyxml2::XMLDocument;
|
snapshots_.xmlDoc_ = new tinyxml2::XMLDocument;
|
||||||
start_time_ = gst_util_get_timestamp ();
|
start_time_ = gst_util_get_timestamp ();
|
||||||
}
|
}
|
||||||
@@ -82,6 +86,15 @@ Session::~Session()
|
|||||||
it = deleteSource(*it);
|
it = deleteSource(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// delete all callbacks
|
||||||
|
for (auto iter = input_callbacks_.begin(); iter != input_callbacks_.end();
|
||||||
|
iter = input_callbacks_.erase(iter)) {
|
||||||
|
if ( iter->second.model_ != nullptr)
|
||||||
|
delete iter->second.model_;
|
||||||
|
if ( iter->second.reverse_ != nullptr)
|
||||||
|
delete iter->second.reverse_;
|
||||||
|
}
|
||||||
|
|
||||||
delete config_[View::RENDERING];
|
delete config_[View::RENDERING];
|
||||||
delete config_[View::GEOMETRY];
|
delete config_[View::GEOMETRY];
|
||||||
delete config_[View::LAYER];
|
delete config_[View::LAYER];
|
||||||
@@ -114,6 +127,50 @@ void Session::update(float dt)
|
|||||||
if ( render_.frame() == nullptr )
|
if ( render_.frame() == nullptr )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// listen to inputs
|
||||||
|
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||||
|
{
|
||||||
|
// get if the input is activated (e.g. key pressed)
|
||||||
|
bool input_active = Control::manager().inputActive(k->first);
|
||||||
|
|
||||||
|
// get the callback model for each input
|
||||||
|
if ( k->second.model_ != nullptr) {
|
||||||
|
|
||||||
|
// if the value referenced as pressed changed state
|
||||||
|
// or repeat key if there is no reverse callback
|
||||||
|
if ( input_active != k->second.active_ || k->second.reverse_ == nullptr) {
|
||||||
|
|
||||||
|
// ON PRESS
|
||||||
|
if (input_active) {
|
||||||
|
// delete the reverse if was not released
|
||||||
|
if (k->second.reverse_ != nullptr)
|
||||||
|
delete k->second.reverse_;
|
||||||
|
|
||||||
|
// generate a new callback from the model
|
||||||
|
SourceCallback *C = k->second.model_->clone();
|
||||||
|
// apply value multiplyer from input
|
||||||
|
C->multiply( Control::manager().inputValue(k->first) );
|
||||||
|
// add delay
|
||||||
|
C->delay( Metronome::manager().timeToSync( (Metronome::Synchronicity) input_sync_[k->first] ) );
|
||||||
|
// add callback to the source (force override)
|
||||||
|
k->second.source_->call( C, true );
|
||||||
|
// get the reverse if the callback, and remember it (can be null)
|
||||||
|
k->second.reverse_ = C->reverse(k->second.source_);
|
||||||
|
}
|
||||||
|
// ON RELEASE
|
||||||
|
else {
|
||||||
|
// call the reverse (NB: invalid value tested in call)
|
||||||
|
k->second.source_->call( k->second.reverse_, true );
|
||||||
|
// do not keep reference to reverse: will be deleted when terminated
|
||||||
|
k->second.reverse_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remember state of callback
|
||||||
|
k->second.active_ = input_active;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pre-render all sources
|
// pre-render all sources
|
||||||
failedSource_ = nullptr;
|
failedSource_ = nullptr;
|
||||||
bool ready = true;
|
bool ready = true;
|
||||||
@@ -132,6 +189,8 @@ void Session::update(float dt)
|
|||||||
else {
|
else {
|
||||||
if ( !(*it)->ready() )
|
if ( !(*it)->ready() )
|
||||||
ready = false;
|
ready = false;
|
||||||
|
// set inputs
|
||||||
|
|
||||||
// update the source
|
// update the source
|
||||||
(*it)->setActive(activation_threshold_);
|
(*it)->setActive(activation_threshold_);
|
||||||
(*it)->update(dt);
|
(*it)->update(dt);
|
||||||
@@ -640,3 +699,161 @@ std::string Session::save(const std::string& filename, Session *session, const s
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Session::assignSourceCallback(uint input, Source *source, SourceCallback *callback)
|
||||||
|
{
|
||||||
|
// find if this callback is already assigned
|
||||||
|
auto k = input_callbacks_.begin();
|
||||||
|
for (; k != input_callbacks_.end(); ++k)
|
||||||
|
{
|
||||||
|
// yes, then just change the source pointer
|
||||||
|
if ( k->second.model_ == callback) {
|
||||||
|
if (k->second.reverse_)
|
||||||
|
delete k->second.reverse_;
|
||||||
|
k->second.source_ = source;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if this callback is not assigned yet (looped until end)
|
||||||
|
if ( k == input_callbacks_.end() ) {
|
||||||
|
// create new entry
|
||||||
|
std::multimap<uint, InputSourceCallback>::iterator added = input_callbacks_.emplace(input, InputSourceCallback() );
|
||||||
|
added->second.model_ = callback;
|
||||||
|
added->second.source_ = source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::swapSourceCallback(uint from, uint to)
|
||||||
|
{
|
||||||
|
std::multimap<uint, InputSourceCallback> swapped_callbacks_;
|
||||||
|
|
||||||
|
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||||
|
{
|
||||||
|
if ( k->first == from )
|
||||||
|
swapped_callbacks_.emplace( to, k->second);
|
||||||
|
else
|
||||||
|
swapped_callbacks_.emplace( k->first, k->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
input_callbacks_.swap(swapped_callbacks_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::copySourceCallback(uint from, uint to)
|
||||||
|
{
|
||||||
|
if ( input_callbacks_.count(from) > 0 ) {
|
||||||
|
auto result = input_callbacks_.equal_range(from);
|
||||||
|
for (auto it = result.first; it != result.second; ++it) {
|
||||||
|
assignSourceCallback(to, it->second.source_, it->second.model_->clone() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list< std::pair<Source *, SourceCallback *> > Session::getSourceCallbacks(uint input)
|
||||||
|
{
|
||||||
|
std::list< std::pair<Source *, SourceCallback*> > ret;
|
||||||
|
|
||||||
|
if ( input_callbacks_.count(input) > 0 ) {
|
||||||
|
auto result = input_callbacks_.equal_range(input);
|
||||||
|
for (auto it = result.first; it != result.second; ++it)
|
||||||
|
ret.push_back( std::pair<Source *, SourceCallback*>(it->second.source_, it->second.model_) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::deleteSourceCallback(SourceCallback *callback)
|
||||||
|
{
|
||||||
|
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
||||||
|
{
|
||||||
|
if ( k->second.model_ == callback) {
|
||||||
|
delete callback;
|
||||||
|
if (k->second.reverse_)
|
||||||
|
delete k->second.reverse_;
|
||||||
|
input_callbacks_.erase(k);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::deleteSourceCallbacks(uint input)
|
||||||
|
{
|
||||||
|
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end();)
|
||||||
|
{
|
||||||
|
if ( k->first == input) {
|
||||||
|
if (k->second.model_)
|
||||||
|
delete k->second.model_;
|
||||||
|
if (k->second.reverse_)
|
||||||
|
delete k->second.reverse_;
|
||||||
|
input_callbacks_.erase(k);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::deleteSourceCallbacks(Source *source)
|
||||||
|
{
|
||||||
|
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end();)
|
||||||
|
{
|
||||||
|
if ( k->second.source_ == source) {
|
||||||
|
if (k->second.model_)
|
||||||
|
delete k->second.model_;
|
||||||
|
if (k->second.reverse_)
|
||||||
|
delete k->second.reverse_;
|
||||||
|
input_callbacks_.erase(k);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
++k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Session::clearSourceCallbacks()
|
||||||
|
{
|
||||||
|
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); )
|
||||||
|
{
|
||||||
|
if (k->second.model_)
|
||||||
|
delete k->second.model_;
|
||||||
|
if (k->second.reverse_)
|
||||||
|
delete k->second.reverse_;
|
||||||
|
|
||||||
|
k = input_callbacks_.erase(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<uint> Session::assignedInputs()
|
||||||
|
{
|
||||||
|
std::list<uint> inputs;
|
||||||
|
|
||||||
|
// fill with list of keys
|
||||||
|
for(const auto& [key, value] : input_callbacks_) {
|
||||||
|
inputs.push_back(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove duplicates
|
||||||
|
inputs.unique();
|
||||||
|
|
||||||
|
return inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Session::inputAssigned(uint input)
|
||||||
|
{
|
||||||
|
return input_callbacks_.find(input) != input_callbacks_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::setInputSynchrony(uint input, Metronome::Synchronicity sync)
|
||||||
|
{
|
||||||
|
input_sync_[input] = sync;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Metronome::Synchronicity> Session::getInputSynchrony()
|
||||||
|
{
|
||||||
|
return input_sync_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Metronome::Synchronicity Session::inputSynchrony(uint input)
|
||||||
|
{
|
||||||
|
return input_sync_[input];
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
32
Session.h
32
Session.h
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "SourceList.h"
|
#include "SourceList.h"
|
||||||
#include "RenderView.h"
|
#include "RenderView.h"
|
||||||
|
#include "Metronome.h"
|
||||||
|
|
||||||
namespace tinyxml2 {
|
namespace tinyxml2 {
|
||||||
class XMLDocument;
|
class XMLDocument;
|
||||||
@@ -151,6 +152,22 @@ public:
|
|||||||
void removeFromPlayGroup(size_t i, Source *s);
|
void removeFromPlayGroup(size_t i, Source *s);
|
||||||
std::vector<SourceIdList> getPlayGroups() { return play_groups_; }
|
std::vector<SourceIdList> getPlayGroups() { return play_groups_; }
|
||||||
|
|
||||||
|
// callbacks associated to inputs
|
||||||
|
void assignSourceCallback(uint input, Source *source, SourceCallback *callback);
|
||||||
|
std::list< std::pair<Source *, SourceCallback*> > getSourceCallbacks(uint input);
|
||||||
|
void deleteSourceCallback (SourceCallback *callback);
|
||||||
|
void deleteSourceCallbacks(Source *source);
|
||||||
|
void deleteSourceCallbacks(uint input);
|
||||||
|
void clearSourceCallbacks ();
|
||||||
|
std::list<uint> assignedInputs();
|
||||||
|
bool inputAssigned(uint input);
|
||||||
|
void swapSourceCallback(uint from, uint to);
|
||||||
|
void copySourceCallback(uint from, uint to);
|
||||||
|
|
||||||
|
void setInputSynchrony(uint input, Metronome::Synchronicity sync);
|
||||||
|
std::vector<Metronome::Synchronicity> getInputSynchrony();
|
||||||
|
Metronome::Synchronicity inputSynchrony(uint input);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool active_;
|
bool active_;
|
||||||
float activation_threshold_;
|
float activation_threshold_;
|
||||||
@@ -186,7 +203,20 @@ protected:
|
|||||||
};
|
};
|
||||||
Fading fading_;
|
Fading fading_;
|
||||||
|
|
||||||
// std::map<uint64_t,
|
struct InputSourceCallback {
|
||||||
|
bool active_;
|
||||||
|
SourceCallback *model_;
|
||||||
|
SourceCallback *reverse_;
|
||||||
|
Source *source_;
|
||||||
|
InputSourceCallback() {
|
||||||
|
active_ = false;
|
||||||
|
model_ = nullptr;
|
||||||
|
reverse_ = nullptr;
|
||||||
|
source_ = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::multimap<uint, InputSourceCallback> input_callbacks_;
|
||||||
|
std::vector<Metronome::Synchronicity> input_sync_;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,9 @@ void SessionCreator::load(const std::string& filename)
|
|||||||
// load playlists
|
// load playlists
|
||||||
loadPlayGroups( xmlDoc_.FirstChildElement("PlayGroups") );
|
loadPlayGroups( xmlDoc_.FirstChildElement("PlayGroups") );
|
||||||
|
|
||||||
|
// load input callbacks
|
||||||
|
loadInputCallbacks( xmlDoc_.FirstChildElement("InputCallbacks") );
|
||||||
|
|
||||||
// thumbnail
|
// thumbnail
|
||||||
const XMLElement *thumbnailelement = sessionNode->FirstChildElement("Thumbnail");
|
const XMLElement *thumbnailelement = sessionNode->FirstChildElement("Thumbnail");
|
||||||
// if there is a user-defined thumbnail, get it
|
// if there is a user-defined thumbnail, get it
|
||||||
@@ -193,6 +196,62 @@ void SessionCreator::loadSnapshots(XMLElement *snapshotsNode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SessionCreator::loadInputCallbacks(tinyxml2::XMLElement *inputsNode)
|
||||||
|
{
|
||||||
|
if (inputsNode != nullptr && session_ != nullptr) {
|
||||||
|
|
||||||
|
// read all 'Callback' nodes
|
||||||
|
xmlCurrent_ = inputsNode->FirstChildElement("Callback");
|
||||||
|
for ( ; xmlCurrent_ ; xmlCurrent_ = xmlCurrent_->NextSiblingElement()) {
|
||||||
|
// what key triggers the callback ?
|
||||||
|
uint input = 0;
|
||||||
|
xmlCurrent_->QueryUnsignedAttribute("input", &input);
|
||||||
|
if (input > 0) {
|
||||||
|
// what id is the source ?
|
||||||
|
uint64_t id = 0;
|
||||||
|
xmlCurrent_->QueryUnsigned64Attribute("id", &id);
|
||||||
|
if (id > 0) {
|
||||||
|
// what type is the callback ?
|
||||||
|
uint type = 0;
|
||||||
|
xmlCurrent_->QueryUnsignedAttribute("type", &type);
|
||||||
|
// instanciate the callback of that type
|
||||||
|
SourceCallback *loadedcallback = SourceCallback::create((SourceCallback::CallbackType)type);
|
||||||
|
// successfully created a callback of saved type
|
||||||
|
if (loadedcallback) {
|
||||||
|
// apply specific parameters
|
||||||
|
loadedcallback->accept(*this);
|
||||||
|
// find the source with the given id
|
||||||
|
SourceList::iterator sit = session_->find(id);
|
||||||
|
if (sit != session_->end()) {
|
||||||
|
// assign to source in session
|
||||||
|
session_->assignSourceCallback(input, *sit, loadedcallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read array of synchronyzation mode for all inputs (CSV)
|
||||||
|
xmlCurrent_ = inputsNode->FirstChildElement("Synchrony");
|
||||||
|
if (xmlCurrent_) {
|
||||||
|
const char *text = xmlCurrent_->GetText();
|
||||||
|
if (text) {
|
||||||
|
std::istringstream iss(text);
|
||||||
|
std::string token;
|
||||||
|
uint i = 0;
|
||||||
|
while(std::getline(iss, token, ';')) {
|
||||||
|
if (token.compare("1") == 0)
|
||||||
|
session_->setInputSynchrony(i, Metronome::SYNC_BEAT);
|
||||||
|
else if (token.compare("2") == 0)
|
||||||
|
session_->setInputSynchrony(i, Metronome::SYNC_PHASE);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SessionCreator::loadNotes(XMLElement *notesNode)
|
void SessionCreator::loadNotes(XMLElement *notesNode)
|
||||||
{
|
{
|
||||||
if (notesNode != nullptr && session_ != nullptr) {
|
if (notesNode != nullptr && session_ != nullptr) {
|
||||||
@@ -900,30 +959,6 @@ void SessionLoader::visit (Source& s)
|
|||||||
groups_sources_id_.push_back(idlist);
|
groups_sources_id_.push_back(idlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
XMLElement* callbacksNode = sourceNode->FirstChildElement("Callbacks");
|
|
||||||
if (callbacksNode) {
|
|
||||||
// Loop over 'Callback' nodes
|
|
||||||
xmlCurrent_ = callbacksNode->FirstChildElement("Callback");
|
|
||||||
for ( ; xmlCurrent_ ; xmlCurrent_ = xmlCurrent_->NextSiblingElement()) {
|
|
||||||
// what key triggers the callback ?
|
|
||||||
uint input = 0;
|
|
||||||
xmlCurrent_->QueryUnsignedAttribute("input", &input);
|
|
||||||
// what type is the callback ?
|
|
||||||
uint type = 0;
|
|
||||||
xmlCurrent_->QueryUnsignedAttribute("type", &type);
|
|
||||||
// instanciate the callback of that type
|
|
||||||
SourceCallback *loadedcallback = SourceCallback::create((SourceCallback::CallbackType)type);
|
|
||||||
// successfully created a callback of saved type
|
|
||||||
if (loadedcallback) {
|
|
||||||
// apply specific parameters
|
|
||||||
loadedcallback->accept(*this);
|
|
||||||
// add callback to source
|
|
||||||
s.addInputCallback(input, loadedcallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// restore current
|
// restore current
|
||||||
xmlCurrent_ = sourceNode;
|
xmlCurrent_ = sourceNode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ class SessionCreator : public SessionLoader {
|
|||||||
void loadNotes(tinyxml2::XMLElement *notesNode);
|
void loadNotes(tinyxml2::XMLElement *notesNode);
|
||||||
void loadPlayGroups(tinyxml2::XMLElement *playlistsNode);
|
void loadPlayGroups(tinyxml2::XMLElement *playlistsNode);
|
||||||
void loadSnapshots(tinyxml2::XMLElement *snapshotNode);
|
void loadSnapshots(tinyxml2::XMLElement *snapshotNode);
|
||||||
|
void loadInputCallbacks(tinyxml2::XMLElement *inputsNode);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SessionCreator(int recursion = 0);
|
SessionCreator(int recursion = 0);
|
||||||
|
|||||||
@@ -110,6 +110,9 @@ bool SessionVisitor::saveSession(const std::string& filename, Session *session)
|
|||||||
// 5. optional playlists
|
// 5. optional playlists
|
||||||
savePlayGroups( &xmlDoc, session );
|
savePlayGroups( &xmlDoc, session );
|
||||||
|
|
||||||
|
// 5. optional playlists
|
||||||
|
saveInputCallbacks( &xmlDoc, session );
|
||||||
|
|
||||||
// save file to disk
|
// save file to disk
|
||||||
return ( XMLSaveDoc(&xmlDoc, filename) );
|
return ( XMLSaveDoc(&xmlDoc, filename) );
|
||||||
}
|
}
|
||||||
@@ -202,6 +205,47 @@ void SessionVisitor::savePlayGroups(tinyxml2::XMLDocument *doc, Session *session
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SessionVisitor::saveInputCallbacks(tinyxml2::XMLDocument *doc, Session *session)
|
||||||
|
{
|
||||||
|
// invalid inputs
|
||||||
|
if (doc != nullptr && session != nullptr)
|
||||||
|
{
|
||||||
|
// create node
|
||||||
|
XMLElement *inputsNode = doc->NewElement("InputCallbacks");
|
||||||
|
doc->InsertEndChild(inputsNode);
|
||||||
|
|
||||||
|
// list of inputs assigned in the session
|
||||||
|
std::list<uint> inputs = session->assignedInputs();
|
||||||
|
if (!inputs.empty()) {
|
||||||
|
// loop over list of inputs
|
||||||
|
for (auto i = inputs.begin(); i != inputs.end(); ++i) {
|
||||||
|
// get all callbacks for this input
|
||||||
|
auto result = session->getSourceCallbacks(*i);
|
||||||
|
for (auto kit = result.cbegin(); kit != result.cend(); ++kit) {
|
||||||
|
// create node for this callback
|
||||||
|
XMLElement *cbNode = doc->NewElement("Callback");
|
||||||
|
cbNode->SetAttribute("input", *i);
|
||||||
|
cbNode->SetAttribute("id", kit->first->id());
|
||||||
|
inputsNode->InsertEndChild(cbNode);
|
||||||
|
// launch visitor to complete attributes
|
||||||
|
SessionVisitor sv(doc, cbNode);
|
||||||
|
kit->second->accept(sv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save array of synchronyzation mode for all inputs (CSV)
|
||||||
|
std::ostringstream oss;
|
||||||
|
std::vector<Metronome::Synchronicity> synch = session->getInputSynchrony();
|
||||||
|
for (auto token = synch.begin(); token != synch.end(); ++token)
|
||||||
|
oss << (int) *token << ';';
|
||||||
|
XMLElement *syncNode = doc->NewElement("Synchrony");
|
||||||
|
XMLText *text = doc->NewText( oss.str().c_str() );
|
||||||
|
syncNode->InsertEndChild(text);
|
||||||
|
inputsNode->InsertEndChild(syncNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SessionVisitor::SessionVisitor(tinyxml2::XMLDocument *doc,
|
SessionVisitor::SessionVisitor(tinyxml2::XMLDocument *doc,
|
||||||
tinyxml2::XMLElement *root,
|
tinyxml2::XMLElement *root,
|
||||||
bool recursive) : Visitor(), recursive_(recursive), xmlCurrent_(root)
|
bool recursive) : Visitor(), recursive_(recursive), xmlCurrent_(root)
|
||||||
@@ -580,22 +624,6 @@ void SessionVisitor::visit (Source& s)
|
|||||||
s.mixingGroup()->accept(*this);
|
s.mixingGroup()->accept(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<uint> inputs = s.callbackInputs();
|
|
||||||
if (!inputs.empty()) {
|
|
||||||
// list of callbacks
|
|
||||||
XMLElement *callbackselement = xmlDoc_->NewElement( "Callbacks" );
|
|
||||||
sourceNode->InsertEndChild(callbackselement);
|
|
||||||
for (auto i = inputs.begin(); i != inputs.end(); ++i) {
|
|
||||||
std::list<SourceCallback *> callbacks = s.inputCallbacks(*i);
|
|
||||||
for (auto c = callbacks.begin(); c != callbacks.end(); ++c) {
|
|
||||||
xmlCurrent_ = xmlDoc_->NewElement( "Callback" );
|
|
||||||
callbackselement->InsertEndChild(xmlCurrent_);
|
|
||||||
xmlCurrent_->SetAttribute("input", *i);
|
|
||||||
(*c)->accept(*this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xmlCurrent_ = sourceNode; // parent for next visits (other subtypes of Source)
|
xmlCurrent_ = sourceNode; // parent for next visits (other subtypes of Source)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class SessionVisitor : public Visitor {
|
|||||||
static void saveSnapshots(tinyxml2::XMLDocument *doc, Session *session);
|
static void saveSnapshots(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
static void saveNotes(tinyxml2::XMLDocument *doc, Session *session);
|
static void saveNotes(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
static void savePlayGroups(tinyxml2::XMLDocument *doc, Session *session);
|
static void savePlayGroups(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
|
static void saveInputCallbacks(tinyxml2::XMLDocument *doc, Session *session);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SessionVisitor(tinyxml2::XMLDocument *doc = nullptr,
|
SessionVisitor(tinyxml2::XMLDocument *doc = nullptr,
|
||||||
|
|||||||
131
Source.cpp
131
Source.cpp
@@ -34,6 +34,7 @@
|
|||||||
#include "BaseToolkit.h"
|
#include "BaseToolkit.h"
|
||||||
#include "SystemToolkit.h"
|
#include "SystemToolkit.h"
|
||||||
#include "MixingGroup.h"
|
#include "MixingGroup.h"
|
||||||
|
#include "Metronome.h"
|
||||||
#include "ControlManager.h"
|
#include "ControlManager.h"
|
||||||
#include "SourceCallback.h"
|
#include "SourceCallback.h"
|
||||||
|
|
||||||
@@ -360,16 +361,6 @@ Source::~Source()
|
|||||||
delete callback;
|
delete callback;
|
||||||
}
|
}
|
||||||
access_callbacks_.unlock();
|
access_callbacks_.unlock();
|
||||||
|
|
||||||
// clear and delete key_callbacks
|
|
||||||
for (auto iter = input_callbacks_.begin(); iter != input_callbacks_.end();
|
|
||||||
iter = input_callbacks_.erase(iter)) {
|
|
||||||
if ( iter->second.model_ != nullptr)
|
|
||||||
delete iter->second.model_;
|
|
||||||
if ( iter->second.reverse_ != nullptr)
|
|
||||||
delete iter->second.reverse_;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::setName (const std::string &name)
|
void Source::setName (const std::string &name)
|
||||||
@@ -678,125 +669,8 @@ void Source::call(SourceCallback *callback, bool override)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Source::addInputCallback(uint input, SourceCallback *callback)
|
|
||||||
{
|
|
||||||
std::multimap<uint, InputCallback>::iterator added = input_callbacks_.emplace(input, InputCallback() );
|
|
||||||
added->second.model_ = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Source::swapInputCallback(uint from, uint to)
|
|
||||||
{
|
|
||||||
std::multimap<uint, InputCallback> swapped_callbacks_;
|
|
||||||
|
|
||||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
|
||||||
{
|
|
||||||
if ( k->first == from )
|
|
||||||
swapped_callbacks_.emplace( to, k->second);
|
|
||||||
else
|
|
||||||
swapped_callbacks_.emplace( k->first, k->second);
|
|
||||||
}
|
|
||||||
|
|
||||||
input_callbacks_.swap(swapped_callbacks_);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Source::removeInputCallback(SourceCallback *callback)
|
|
||||||
{
|
|
||||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
|
||||||
{
|
|
||||||
if ( k->second.model_ == callback) {
|
|
||||||
delete callback;
|
|
||||||
if (k->second.reverse_)
|
|
||||||
delete k->second.reverse_;
|
|
||||||
input_callbacks_.erase(k);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Source::clearInputCallbacks()
|
|
||||||
{
|
|
||||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); )
|
|
||||||
{
|
|
||||||
if (k->second.model_)
|
|
||||||
delete k->second.model_;
|
|
||||||
if (k->second.reverse_)
|
|
||||||
delete k->second.reverse_;
|
|
||||||
|
|
||||||
k = input_callbacks_.erase(k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<SourceCallback *> Source::inputCallbacks(uint input)
|
|
||||||
{
|
|
||||||
std::list<SourceCallback *> ret;
|
|
||||||
|
|
||||||
if ( input_callbacks_.count(input) > 0 ) {
|
|
||||||
auto result = input_callbacks_.equal_range(input);
|
|
||||||
for (auto it = result.first; it != result.second; ++it)
|
|
||||||
ret.push_back( it->second.model_ );
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::list<uint> Source::callbackInputs()
|
|
||||||
{
|
|
||||||
std::list<uint> inputs;
|
|
||||||
|
|
||||||
// fill with list of keys
|
|
||||||
for(const auto& [key, value] : input_callbacks_) {
|
|
||||||
inputs.push_back(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove duplicates
|
|
||||||
inputs.unique();
|
|
||||||
|
|
||||||
return inputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Source::updateCallbacks(float dt)
|
void Source::updateCallbacks(float dt)
|
||||||
{
|
{
|
||||||
// add callbacks from listener
|
|
||||||
for (auto k = input_callbacks_.begin(); k != input_callbacks_.end(); ++k)
|
|
||||||
{
|
|
||||||
// if the Reaction is valid
|
|
||||||
if ( k->second.model_ != nullptr) {
|
|
||||||
|
|
||||||
bool activate = Control::manager().inputActive(k->first);
|
|
||||||
|
|
||||||
// if the value referenced as pressed changed state
|
|
||||||
// or repeat key if there is no reverse callback
|
|
||||||
if ( activate != k->second.active_ || k->second.reverse_ == nullptr) {
|
|
||||||
|
|
||||||
// ON PRESS
|
|
||||||
if (activate) {
|
|
||||||
// generate a new callback from the model
|
|
||||||
SourceCallback *C = k->second.model_->clone();
|
|
||||||
// apply value multiplyer from input
|
|
||||||
C->multiply( Control::manager().inputValue(k->first) );
|
|
||||||
// add callback to the source (force override)
|
|
||||||
call( C, true );
|
|
||||||
// delete the reverse if was not released
|
|
||||||
if (k->second.reverse_ != nullptr)
|
|
||||||
delete k->second.reverse_;
|
|
||||||
// get the reverse if the callback, and remember it (can be null)
|
|
||||||
k->second.reverse_ = C->reverse(this);
|
|
||||||
}
|
|
||||||
// ON RELEASE
|
|
||||||
else {
|
|
||||||
// call the reverse (NB: invalid value tested in call)
|
|
||||||
call( k->second.reverse_, true );
|
|
||||||
// do not keep reference to reverse: will be deleted when terminated
|
|
||||||
k->second.reverse_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
k->second.active_ = activate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock access to callbacks list
|
// lock access to callbacks list
|
||||||
access_callbacks_.lock();
|
access_callbacks_.lock();
|
||||||
// call callback functions
|
// call callback functions
|
||||||
@@ -819,6 +693,7 @@ void Source::updateCallbacks(float dt)
|
|||||||
}
|
}
|
||||||
// release access to callbacks list
|
// release access to callbacks list
|
||||||
access_callbacks_.unlock();
|
access_callbacks_.unlock();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CloneSource *Source::clone(uint64_t id)
|
CloneSource *Source::clone(uint64_t id)
|
||||||
@@ -838,7 +713,7 @@ void Source::update(float dt)
|
|||||||
// if update is possible
|
// if update is possible
|
||||||
if (renderbuffer_ && mixingsurface_ && maskbuffer_)
|
if (renderbuffer_ && mixingsurface_ && maskbuffer_)
|
||||||
{
|
{
|
||||||
// react to input and call active callbacks
|
// call active callbacks
|
||||||
updateCallbacks(dt);
|
updateCallbacks(dt);
|
||||||
|
|
||||||
// update nodes if needed
|
// update nodes if needed
|
||||||
|
|||||||
19
Source.h
19
Source.h
@@ -148,14 +148,6 @@ public:
|
|||||||
// add callback to each update
|
// add callback to each update
|
||||||
void call(SourceCallback *callback, bool override = false);
|
void call(SourceCallback *callback, bool override = false);
|
||||||
|
|
||||||
// callbacks associated to keys
|
|
||||||
void addInputCallback(uint input, SourceCallback *callback);
|
|
||||||
void removeInputCallback(SourceCallback *callback);
|
|
||||||
std::list<SourceCallback *> inputCallbacks(uint input);
|
|
||||||
std::list<uint> callbackInputs();
|
|
||||||
void swapInputCallback(uint from, uint to);
|
|
||||||
void clearInputCallbacks();
|
|
||||||
|
|
||||||
// update mode
|
// update mode
|
||||||
inline bool active () const { return active_; }
|
inline bool active () const { return active_; }
|
||||||
virtual void setActive (bool on);
|
virtual void setActive (bool on);
|
||||||
@@ -325,17 +317,6 @@ protected:
|
|||||||
// callbacks
|
// callbacks
|
||||||
std::list<SourceCallback *> update_callbacks_;
|
std::list<SourceCallback *> update_callbacks_;
|
||||||
std::mutex access_callbacks_;
|
std::mutex access_callbacks_;
|
||||||
struct InputCallback {
|
|
||||||
bool active_;
|
|
||||||
SourceCallback *model_;
|
|
||||||
SourceCallback *reverse_;
|
|
||||||
InputCallback() {
|
|
||||||
active_ = false;
|
|
||||||
model_ = nullptr;
|
|
||||||
reverse_ = nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
std::multimap<uint, InputCallback> input_callbacks_;
|
|
||||||
void updateCallbacks(float dt);
|
void updateCallbacks(float dt);
|
||||||
|
|
||||||
// clones
|
// clones
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ bool SourceCallback::overlap( SourceCallback *a, SourceCallback *b)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceCallback::SourceCallback(): finished_(false), initialized_(false)
|
SourceCallback::SourceCallback(): status_(PENDING), delay_(0.f), elapsed_(0.f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,14 +122,39 @@ void SourceCallback::accept(Visitor& v)
|
|||||||
v.visit(*this);
|
v.visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetGeometry::update(Source *s, float)
|
void SourceCallback::update (Source *s, float dt)
|
||||||
{
|
{
|
||||||
s->group(View::GEOMETRY)->scale_ = glm::vec3(1.f);
|
if (s != nullptr) {
|
||||||
s->group(View::GEOMETRY)->rotation_.z = 0;
|
// time passed
|
||||||
s->group(View::GEOMETRY)->crop_ = glm::vec3(1.f);
|
elapsed_ += dt;
|
||||||
s->group(View::GEOMETRY)->translation_ = glm::vec3(0.f);
|
// wait for delay to start
|
||||||
s->touch();
|
if ( status_ == PENDING && elapsed_ > delay_ )
|
||||||
finished_ = true;
|
status_ = READY;
|
||||||
|
}
|
||||||
|
// invalid
|
||||||
|
else
|
||||||
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetGeometry::update(Source *s, float dt)
|
||||||
|
{
|
||||||
|
SourceCallback::update(s, dt);
|
||||||
|
|
||||||
|
if (s->locked())
|
||||||
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
// apply when ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
|
||||||
|
s->group(View::GEOMETRY)->scale_ = glm::vec3(1.f);
|
||||||
|
s->group(View::GEOMETRY)->rotation_.z = 0;
|
||||||
|
s->group(View::GEOMETRY)->crop_ = glm::vec3(1.f);
|
||||||
|
s->group(View::GEOMETRY)->translation_ = glm::vec3(0.f);
|
||||||
|
s->touch();
|
||||||
|
|
||||||
|
status_ = FINISHED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceCallback *ResetGeometry::clone() const
|
SourceCallback *ResetGeometry::clone() const
|
||||||
@@ -137,8 +162,9 @@ SourceCallback *ResetGeometry::clone() const
|
|||||||
return new ResetGeometry;
|
return new ResetGeometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SetAlpha::SetAlpha(float alpha, float ms, bool revert) : SourceCallback(),
|
SetAlpha::SetAlpha(float alpha, float ms, bool revert) : SourceCallback(),
|
||||||
duration_(ms), progress_(0.f), alpha_(alpha), bidirectional_(revert)
|
duration_(ms), alpha_(alpha), bidirectional_(revert)
|
||||||
{
|
{
|
||||||
alpha_ = CLAMP(alpha_, 0.f, 1.f);
|
alpha_ = CLAMP(alpha_, 0.f, 1.f);
|
||||||
start_ = glm::vec2();
|
start_ = glm::vec2();
|
||||||
@@ -147,60 +173,63 @@ SetAlpha::SetAlpha(float alpha, float ms, bool revert) : SourceCallback(),
|
|||||||
|
|
||||||
void SetAlpha::update(Source *s, float dt)
|
void SetAlpha::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && !s->locked()) {
|
SourceCallback::update(s, dt);
|
||||||
// set start position on first run or upon call of reset()
|
|
||||||
if (!initialized_){
|
|
||||||
// initial mixing view position
|
|
||||||
start_ = glm::vec2(s->group(View::MIXING)->translation_);
|
|
||||||
|
|
||||||
// step in diagonal by default
|
if (s->locked())
|
||||||
glm::vec2 step = glm::normalize(glm::vec2(1.f, 1.f));
|
status_ = FINISHED;
|
||||||
// step in direction of source translation if possible
|
|
||||||
if ( glm::length(start_) > DELTA_ALPHA)
|
|
||||||
step = glm::normalize(start_);
|
|
||||||
//
|
|
||||||
// target mixing view position
|
|
||||||
//
|
|
||||||
// special case Alpha = 0
|
|
||||||
if (alpha_ < DELTA_ALPHA) {
|
|
||||||
target_ = step;
|
|
||||||
}
|
|
||||||
// special case Alpha = 1
|
|
||||||
else if (alpha_ > 1.f - DELTA_ALPHA) {
|
|
||||||
target_ = step * 0.005f;
|
|
||||||
}
|
|
||||||
// general case
|
|
||||||
else {
|
|
||||||
// converge to reduce the difference of alpha using dichotomic algorithm
|
|
||||||
target_ = start_;
|
|
||||||
float delta = 1.f;
|
|
||||||
do {
|
|
||||||
target_ += step * (delta / 2.f);
|
|
||||||
delta = SourceCore::alphaFromCordinates(target_.x, target_.y) - alpha_;
|
|
||||||
} while (glm::abs(delta) > DELTA_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
initialized_ = true;
|
// set start position on first time it is ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
// initial mixing view position
|
||||||
|
start_ = glm::vec2(s->group(View::MIXING)->translation_);
|
||||||
|
|
||||||
|
// step in diagonal by default
|
||||||
|
glm::vec2 step = glm::normalize(glm::vec2(1.f, 1.f));
|
||||||
|
// step in direction of source translation if possible
|
||||||
|
if ( glm::length(start_) > DELTA_ALPHA)
|
||||||
|
step = glm::normalize(start_);
|
||||||
|
//
|
||||||
|
// target mixing view position
|
||||||
|
//
|
||||||
|
// special case Alpha = 0
|
||||||
|
if (alpha_ < DELTA_ALPHA) {
|
||||||
|
target_ = step;
|
||||||
|
}
|
||||||
|
// special case Alpha = 1
|
||||||
|
else if (alpha_ > 1.f - DELTA_ALPHA) {
|
||||||
|
target_ = step * 0.005f;
|
||||||
|
}
|
||||||
|
// general case
|
||||||
|
else {
|
||||||
|
// converge to reduce the difference of alpha using dichotomic algorithm
|
||||||
|
target_ = start_;
|
||||||
|
float delta = 1.f;
|
||||||
|
do {
|
||||||
|
target_ += step * (delta / 2.f);
|
||||||
|
delta = SourceCore::alphaFromCordinates(target_.x, target_.y) - alpha_;
|
||||||
|
} while (glm::abs(delta) > DELTA_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
// time passed
|
status_ = ACTIVE;
|
||||||
progress_ += dt;
|
}
|
||||||
|
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
// time passed since start
|
||||||
|
float progress = elapsed_ - delay_;
|
||||||
|
|
||||||
// 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(start_ + (progress/duration_)*(target_ - start_), s->group(View::MIXING)->translation_.z);
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress_ > duration_ ) {
|
if ( progress > duration_ ) {
|
||||||
// apply alpha to target
|
// apply alpha to target
|
||||||
s->group(View::MIXING)->translation_ = glm::vec3(target_, s->group(View::MIXING)->translation_.z);
|
s->group(View::MIXING)->translation_ = glm::vec3(target_, s->group(View::MIXING)->translation_.z);
|
||||||
// done
|
// done
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetAlpha::multiply (float factor)
|
void SetAlpha::multiply (float factor)
|
||||||
@@ -233,7 +262,7 @@ void Lock::update(Source *s, float)
|
|||||||
if (s)
|
if (s)
|
||||||
s->setLocked(lock_);
|
s->setLocked(lock_);
|
||||||
|
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceCallback *Lock::clone() const
|
SourceCallback *Lock::clone() const
|
||||||
@@ -243,7 +272,7 @@ SourceCallback *Lock::clone() const
|
|||||||
|
|
||||||
|
|
||||||
Loom::Loom(float speed, float ms) : SourceCallback(),
|
Loom::Loom(float speed, float ms) : SourceCallback(),
|
||||||
speed_(speed), duration_(ms), progress_(0.f)
|
speed_(speed), duration_(ms)
|
||||||
{
|
{
|
||||||
pos_ = glm::vec2();
|
pos_ = glm::vec2();
|
||||||
step_ = glm::normalize(glm::vec2(1.f, 1.f)); // step in diagonal by default
|
step_ = glm::normalize(glm::vec2(1.f, 1.f)); // step in diagonal by default
|
||||||
@@ -251,22 +280,24 @@ Loom::Loom(float speed, float ms) : SourceCallback(),
|
|||||||
|
|
||||||
void Loom::update(Source *s, float dt)
|
void Loom::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && !s->locked()) {
|
SourceCallback::update(s, dt);
|
||||||
// reset on first run or upon call of reset()
|
|
||||||
if (!initialized_){
|
|
||||||
// start animation
|
|
||||||
progress_ = 0.f;
|
|
||||||
// initial position
|
|
||||||
pos_ = glm::vec2(s->group(View::MIXING)->translation_);
|
|
||||||
// step in direction of source translation if possible
|
|
||||||
if ( glm::length(pos_) > DELTA_ALPHA)
|
|
||||||
step_ = glm::normalize(pos_);
|
|
||||||
|
|
||||||
initialized_ = true;
|
if (s->locked())
|
||||||
}
|
status_ = FINISHED;
|
||||||
|
|
||||||
// time passed
|
// set start on first time it is ready
|
||||||
progress_ += dt;
|
if ( status_ == READY ){
|
||||||
|
// initial position
|
||||||
|
pos_ = glm::vec2(s->group(View::MIXING)->translation_);
|
||||||
|
// step in direction of source translation if possible
|
||||||
|
if ( glm::length(pos_) > DELTA_ALPHA)
|
||||||
|
step_ = glm::normalize(pos_);
|
||||||
|
status_ = ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
// time passed since start
|
||||||
|
float progress = elapsed_ - delay_;
|
||||||
|
|
||||||
// move target by speed vector (in the direction of step_, amplitude of speed * time (in second))
|
// move target by speed vector (in the direction of step_, amplitude of speed * time (in second))
|
||||||
pos_ -= step_ * ( speed_ * dt * 0.001f );
|
pos_ -= step_ * ( speed_ * dt * 0.001f );
|
||||||
@@ -275,15 +306,14 @@ void Loom::update(Source *s, float dt)
|
|||||||
float l = glm::length( pos_ );
|
float l = glm::length( pos_ );
|
||||||
if ( (l > 0.01f && speed_ > 0.f ) || (l < MIXING_MIN_THRESHOLD && speed_ < 0.f ) )
|
if ( (l > 0.01f && speed_ > 0.f ) || (l < MIXING_MIN_THRESHOLD && speed_ < 0.f ) )
|
||||||
s->group(View::MIXING)->translation_ = glm::vec3(pos_, s->group(View::MIXING)->translation_.z);
|
s->group(View::MIXING)->translation_ = glm::vec3(pos_, s->group(View::MIXING)->translation_.z);
|
||||||
|
else
|
||||||
|
status_ = FINISHED;
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress_ > duration_ ) {
|
if ( progress > duration_ )
|
||||||
// done
|
// done
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Loom::multiply (float factor)
|
void Loom::multiply (float factor)
|
||||||
@@ -296,6 +326,11 @@ SourceCallback *Loom::clone() const
|
|||||||
return new Loom(speed_, duration_);
|
return new Loom(speed_, duration_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceCallback *Loom::reverse(Source *) const
|
||||||
|
{
|
||||||
|
return new Loom(speed_, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
void Loom::accept(Visitor& v)
|
void Loom::accept(Visitor& v)
|
||||||
{
|
{
|
||||||
SourceCallback::accept(v);
|
SourceCallback::accept(v);
|
||||||
@@ -303,42 +338,43 @@ 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), progress_(0.f), start_(0.f), target_(target), bidirectional_(revert)
|
duration_(ms), start_(0.f), target_(target), bidirectional_(revert)
|
||||||
{
|
{
|
||||||
target_ = CLAMP(target_, MIN_DEPTH, MAX_DEPTH);
|
target_ = CLAMP(target_, MIN_DEPTH, MAX_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDepth::update(Source *s, float dt)
|
void SetDepth::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && !s->locked()) {
|
SourceCallback::update(s, dt);
|
||||||
// set start position on first run or upon call of reset()
|
|
||||||
if (!initialized_){
|
|
||||||
start_ = s->group(View::LAYER)->translation_.z;
|
|
||||||
progress_ = 0.f;
|
|
||||||
initialized_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// time passed
|
if (s->locked())
|
||||||
progress_ += dt;
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
// set start position on first time it is ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
start_ = s->group(View::LAYER)->translation_.z;
|
||||||
|
status_ = ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
// time passed since start
|
||||||
|
float progress = elapsed_ - delay_;
|
||||||
|
|
||||||
// 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 = start_ + (progress/duration_) * (target_ - start_);
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress_ > duration_ ) {
|
if ( progress > duration_ ) {
|
||||||
// apply depth to target
|
// apply depth to target
|
||||||
s->group(View::LAYER)->translation_.z = target_;
|
s->group(View::LAYER)->translation_.z = target_;
|
||||||
// ensure reordering of view
|
// ensure reordering of view
|
||||||
++View::need_deep_update_;
|
++View::need_deep_update_;
|
||||||
// done
|
// done
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetDepth::multiply (float factor)
|
void SetDepth::multiply (float factor)
|
||||||
@@ -366,14 +402,20 @@ Play::Play(bool on, bool revert) : SourceCallback(), play_(on), bidirectional_(r
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Play::update(Source *s, float)
|
void Play::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && s->playing() != play_) {
|
SourceCallback::update(s, dt);
|
||||||
// call play function
|
|
||||||
s->play(play_);
|
// toggle play status when ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
|
||||||
|
if (s->playing() != play_)
|
||||||
|
// call play function
|
||||||
|
s->play(play_);
|
||||||
|
|
||||||
|
status_ = FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceCallback *Play::clone() const
|
SourceCallback *Play::clone() const
|
||||||
@@ -396,14 +438,18 @@ RePlay::RePlay() : SourceCallback()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void RePlay::update(Source *s, float)
|
void RePlay::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s) {
|
SourceCallback::update(s, dt);
|
||||||
|
|
||||||
|
// apply when ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
|
||||||
// call replay function
|
// call replay function
|
||||||
s->replay();
|
s->replay();
|
||||||
}
|
|
||||||
|
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceCallback *RePlay::clone() const
|
SourceCallback *RePlay::clone() const
|
||||||
@@ -413,7 +459,7 @@ SourceCallback *RePlay::clone() const
|
|||||||
|
|
||||||
|
|
||||||
SetGeometry::SetGeometry(const Group *g, float ms, bool revert) : SourceCallback(),
|
SetGeometry::SetGeometry(const Group *g, float ms, bool revert) : SourceCallback(),
|
||||||
duration_(ms), progress_(0.f), bidirectional_(revert)
|
duration_(ms), bidirectional_(revert)
|
||||||
{
|
{
|
||||||
setTarget(g);
|
setTarget(g);
|
||||||
}
|
}
|
||||||
@@ -432,20 +478,24 @@ void SetGeometry::setTarget (const Group *g)
|
|||||||
|
|
||||||
void SetGeometry::update(Source *s, float dt)
|
void SetGeometry::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && !s->locked()) {
|
SourceCallback::update(s, dt);
|
||||||
// set start position on first run or upon call of reset()
|
|
||||||
if (!initialized_){
|
|
||||||
start_.copyTransform(s->group(View::GEOMETRY));
|
|
||||||
progress_ = 0.f;
|
|
||||||
initialized_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// time passed
|
if (s->locked())
|
||||||
progress_ += dt;
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
// set start position on first time it is ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
start_.copyTransform(s->group(View::GEOMETRY));
|
||||||
|
status_ = ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
// time passed since start
|
||||||
|
float progress = elapsed_ - delay_;
|
||||||
|
|
||||||
// perform movement
|
// perform movement
|
||||||
if ( ABS(duration_) > 0.f){
|
if ( ABS(duration_) > 0.f){
|
||||||
float ratio = progress_ / duration_;
|
float ratio = progress / duration_;
|
||||||
Group intermediate;
|
Group intermediate;
|
||||||
intermediate.translation_ = (1.f - ratio) * start_.translation_ + ratio * target_.translation_;
|
intermediate.translation_ = (1.f - ratio) * start_.translation_ + ratio * target_.translation_;
|
||||||
intermediate.scale_ = (1.f - ratio) * start_.scale_ + ratio * target_.scale_;
|
intermediate.scale_ = (1.f - ratio) * start_.scale_ + ratio * target_.scale_;
|
||||||
@@ -456,22 +506,19 @@ void SetGeometry::update(Source *s, float dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress_ > duration_ ) {
|
if ( progress > duration_ ) {
|
||||||
// apply target
|
// apply target
|
||||||
s->group(View::GEOMETRY)->copyTransform(&target_);
|
s->group(View::GEOMETRY)->copyTransform(&target_);
|
||||||
s->touch();
|
s->touch();
|
||||||
// done
|
// done
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetGeometry::multiply (float factor)
|
void SetGeometry::multiply (float factor)
|
||||||
{
|
{
|
||||||
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceCallback *SetGeometry::clone() const
|
SourceCallback *SetGeometry::clone() const
|
||||||
@@ -493,37 +540,35 @@ void SetGeometry::accept(Visitor& v)
|
|||||||
|
|
||||||
|
|
||||||
Grab::Grab(float dx, float dy, float ms) : SourceCallback(),
|
Grab::Grab(float dx, float dy, float ms) : SourceCallback(),
|
||||||
speed_(glm::vec2(dx, dy)), duration_(ms), progress_(0.f)
|
speed_(glm::vec2(dx, dy)), duration_(ms)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Grab::update(Source *s, float dt)
|
void Grab::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && !s->locked()) {
|
SourceCallback::update(s, dt);
|
||||||
// reset on first run or upon call of reset()
|
|
||||||
if (!initialized_){
|
|
||||||
// start animation
|
|
||||||
progress_ = 0.f;
|
|
||||||
// initial position
|
|
||||||
start_ = glm::vec2(s->group(View::GEOMETRY)->translation_);
|
|
||||||
initialized_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// time passed
|
if (s->locked())
|
||||||
progress_ += dt;
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
// set start on first time it is ready
|
||||||
|
if ( status_ == READY ) {
|
||||||
|
// initial position
|
||||||
|
pos_ = glm::vec2(s->group(View::GEOMETRY)->translation_);
|
||||||
|
status_ = ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
|
||||||
// move target by speed vector * time (in second)
|
// move target by speed vector * time (in second)
|
||||||
glm::vec2 pos = start_ + speed_ * ( dt * 0.001f);
|
pos_ += speed_ * ( dt * 0.001f);
|
||||||
s->group(View::GEOMETRY)->translation_ = glm::vec3(pos, s->group(View::GEOMETRY)->translation_.z);
|
s->group(View::GEOMETRY)->translation_ = glm::vec3(pos_, s->group(View::GEOMETRY)->translation_.z);
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress_ > duration_ ) {
|
if ( (elapsed_ - delay_) > duration_ )
|
||||||
// done
|
// done
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Grab::multiply (float factor)
|
void Grab::multiply (float factor)
|
||||||
@@ -536,6 +581,11 @@ SourceCallback *Grab::clone() const
|
|||||||
return new Grab(speed_.x, speed_.y, duration_);
|
return new Grab(speed_.x, speed_.y, duration_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceCallback *Grab::reverse(Source *) const
|
||||||
|
{
|
||||||
|
return new Grab(speed_.x, speed_.y, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
void Grab::accept(Visitor& v)
|
void Grab::accept(Visitor& v)
|
||||||
{
|
{
|
||||||
SourceCallback::accept(v);
|
SourceCallback::accept(v);
|
||||||
@@ -543,37 +593,29 @@ void Grab::accept(Visitor& v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Resize::Resize(float dx, float dy, float ms) : SourceCallback(),
|
Resize::Resize(float dx, float dy, float ms) : SourceCallback(),
|
||||||
speed_(glm::vec2(dx, dy)), duration_(ms), progress_(0.f)
|
speed_(glm::vec2(dx, dy)), duration_(ms)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resize::update(Source *s, float dt)
|
void Resize::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && !s->locked()) {
|
SourceCallback::update(s, dt);
|
||||||
// reset on first run or upon call of reset()
|
|
||||||
if (!initialized_){
|
|
||||||
// start animation
|
|
||||||
progress_ = 0.f;
|
|
||||||
// initial position
|
|
||||||
start_ = glm::vec2(s->group(View::GEOMETRY)->scale_);
|
|
||||||
initialized_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// time passed
|
if (s->locked())
|
||||||
progress_ += dt;
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
if ( status_ == READY )
|
||||||
|
status_ = ACTIVE;
|
||||||
|
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
// move target by speed vector * time (in second)
|
// move target by speed vector * time (in second)
|
||||||
glm::vec2 scale = start_ + speed_ * ( dt * 0.001f);
|
glm::vec2 scale = glm::vec2(s->group(View::GEOMETRY)->scale_) + speed_ * ( dt * 0.001f );
|
||||||
s->group(View::GEOMETRY)->scale_ = glm::vec3(scale, s->group(View::GEOMETRY)->scale_.z);
|
s->group(View::GEOMETRY)->scale_ = glm::vec3(scale, s->group(View::GEOMETRY)->scale_.z);
|
||||||
|
|
||||||
// time-out
|
// time-out
|
||||||
if ( progress_ > duration_ ) {
|
if ( (elapsed_ - delay_) > duration_ )
|
||||||
// done
|
status_ = FINISHED;
|
||||||
finished_ = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Resize::multiply (float factor)
|
void Resize::multiply (float factor)
|
||||||
@@ -586,6 +628,11 @@ SourceCallback *Resize::clone() const
|
|||||||
return new Resize(speed_.x, speed_.y, duration_);
|
return new Resize(speed_.x, speed_.y, duration_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceCallback *Resize::reverse(Source *) const
|
||||||
|
{
|
||||||
|
return new Resize(speed_.x, speed_.y, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
void Resize::accept(Visitor& v)
|
void Resize::accept(Visitor& v)
|
||||||
{
|
{
|
||||||
SourceCallback::accept(v);
|
SourceCallback::accept(v);
|
||||||
@@ -593,36 +640,35 @@ void Resize::accept(Visitor& v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Turn::Turn(float speed, float ms) : SourceCallback(),
|
Turn::Turn(float speed, float ms) : SourceCallback(),
|
||||||
speed_(speed), duration_(ms), progress_(0.f)
|
speed_(speed), duration_(ms)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Turn::update(Source *s, float dt)
|
void Turn::update(Source *s, float dt)
|
||||||
{
|
{
|
||||||
if (s && !s->locked()) {
|
SourceCallback::update(s, dt);
|
||||||
// reset on first run or upon call of reset()
|
|
||||||
if (!initialized_){
|
|
||||||
// start animation
|
|
||||||
progress_ = 0.f;
|
|
||||||
// initial position
|
|
||||||
start_ = s->group(View::GEOMETRY)->rotation_.z;
|
|
||||||
initialized_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate amplitude of movement
|
if (s->locked())
|
||||||
progress_ += dt;
|
status_ = FINISHED;
|
||||||
|
|
||||||
|
// set start on first time it is ready
|
||||||
|
if ( status_ == READY ){
|
||||||
|
// initial position
|
||||||
|
angle_ = s->group(View::GEOMETRY)->rotation_.z;
|
||||||
|
status_ = ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( status_ == ACTIVE ) {
|
||||||
|
|
||||||
// perform movement
|
// perform movement
|
||||||
s->group(View::GEOMETRY)->rotation_.z = start_ - speed_ * ( dt * 0.001f );
|
angle_ -= speed_ * ( dt * 0.001f );
|
||||||
|
s->group(View::GEOMETRY)->rotation_.z = angle_;
|
||||||
|
|
||||||
// timeout
|
// timeout
|
||||||
if ( progress_ > duration_ ) {
|
if ( (elapsed_ - delay_) > duration_ )
|
||||||
// done
|
// done
|
||||||
finished_ = true;
|
status_ = FINISHED;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
finished_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Turn::multiply (float factor)
|
void Turn::multiply (float factor)
|
||||||
@@ -635,6 +681,11 @@ SourceCallback *Turn::clone() const
|
|||||||
return new Turn(speed_, duration_);
|
return new Turn(speed_, duration_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceCallback *Turn::reverse(Source *) const
|
||||||
|
{
|
||||||
|
return new Turn(speed_, 0.f);
|
||||||
|
}
|
||||||
|
|
||||||
void Turn::accept(Visitor& v)
|
void Turn::accept(Visitor& v)
|
||||||
{
|
{
|
||||||
SourceCallback::accept(v);
|
SourceCallback::accept(v);
|
||||||
|
|||||||
@@ -33,25 +33,34 @@ public:
|
|||||||
SourceCallback();
|
SourceCallback();
|
||||||
virtual ~SourceCallback() {}
|
virtual ~SourceCallback() {}
|
||||||
|
|
||||||
virtual void update (Source *, float) = 0;
|
virtual void update (Source *, float);
|
||||||
virtual void multiply (float) {};
|
virtual void multiply (float) {};
|
||||||
virtual SourceCallback *clone () const = 0;
|
virtual SourceCallback *clone () const = 0;
|
||||||
virtual SourceCallback *reverse (Source *) const { return nullptr; }
|
virtual SourceCallback *reverse (Source *) const { return nullptr; }
|
||||||
virtual CallbackType type () const { return CALLBACK_GENERIC; }
|
virtual CallbackType type () const { return CALLBACK_GENERIC; }
|
||||||
virtual void accept (Visitor& v);
|
virtual void accept (Visitor& v);
|
||||||
|
|
||||||
inline bool finished () const { return finished_; }
|
inline bool finished () const { return status_ > ACTIVE; }
|
||||||
inline void reset () { initialized_ = false; }
|
inline void reset () { status_ = PENDING; }
|
||||||
|
inline void delay (float milisec) { delay_ = milisec;}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool finished_;
|
|
||||||
bool initialized_;
|
typedef enum {
|
||||||
|
PENDING = 0,
|
||||||
|
READY,
|
||||||
|
ACTIVE,
|
||||||
|
FINISHED
|
||||||
|
} state;
|
||||||
|
|
||||||
|
state status_;
|
||||||
|
float delay_;
|
||||||
|
float elapsed_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SetAlpha : public SourceCallback
|
class SetAlpha : public SourceCallback
|
||||||
{
|
{
|
||||||
float duration_;
|
float duration_;
|
||||||
float progress_;
|
|
||||||
float alpha_;
|
float alpha_;
|
||||||
glm::vec2 start_;
|
glm::vec2 start_;
|
||||||
glm::vec2 target_;
|
glm::vec2 target_;
|
||||||
@@ -81,10 +90,9 @@ class Loom : public SourceCallback
|
|||||||
glm::vec2 pos_;
|
glm::vec2 pos_;
|
||||||
glm::vec2 step_;
|
glm::vec2 step_;
|
||||||
float duration_;
|
float duration_;
|
||||||
float progress_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Loom (float speed = 0.f, float ms = 0.f);
|
Loom (float speed = 0.f, float ms = FLT_MAX);
|
||||||
|
|
||||||
float value () const { return speed_; }
|
float value () const { return speed_; }
|
||||||
void setValue (float d) { speed_ = d; }
|
void setValue (float d) { speed_ = d; }
|
||||||
@@ -94,6 +102,7 @@ public:
|
|||||||
void update (Source *s, float) override;
|
void update (Source *s, float) override;
|
||||||
void multiply (float factor) override;
|
void multiply (float factor) override;
|
||||||
SourceCallback *clone() const override;
|
SourceCallback *clone() const override;
|
||||||
|
SourceCallback *reverse(Source *) const override;
|
||||||
CallbackType type () const override { return CALLBACK_LOOM; }
|
CallbackType type () const override { return CALLBACK_LOOM; }
|
||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
};
|
};
|
||||||
@@ -116,7 +125,6 @@ public:
|
|||||||
class SetDepth : public SourceCallback
|
class SetDepth : public SourceCallback
|
||||||
{
|
{
|
||||||
float duration_;
|
float duration_;
|
||||||
float progress_;
|
|
||||||
float start_;
|
float start_;
|
||||||
float target_;
|
float target_;
|
||||||
bool bidirectional_;
|
bool bidirectional_;
|
||||||
@@ -152,7 +160,7 @@ public:
|
|||||||
bool bidirectional () const { return bidirectional_;}
|
bool bidirectional () const { return bidirectional_;}
|
||||||
void setBidirectional (bool on) { bidirectional_ = on; }
|
void setBidirectional (bool on) { bidirectional_ = on; }
|
||||||
|
|
||||||
void update (Source *s, float) override;
|
void update (Source *s, float dt) override;
|
||||||
SourceCallback *clone() const override;
|
SourceCallback *clone() const override;
|
||||||
SourceCallback *reverse(Source *s) const override;
|
SourceCallback *reverse(Source *s) const override;
|
||||||
CallbackType type () const override { return CALLBACK_PLAY; }
|
CallbackType type () const override { return CALLBACK_PLAY; }
|
||||||
@@ -164,7 +172,7 @@ class RePlay : public SourceCallback
|
|||||||
public:
|
public:
|
||||||
RePlay();
|
RePlay();
|
||||||
|
|
||||||
void update(Source *s, float) override;
|
void update(Source *s, float dt) override;
|
||||||
SourceCallback *clone() const override;
|
SourceCallback *clone() const override;
|
||||||
CallbackType type () const override { return CALLBACK_REPLAY; }
|
CallbackType type () const override { return CALLBACK_REPLAY; }
|
||||||
};
|
};
|
||||||
@@ -173,7 +181,7 @@ class ResetGeometry : public SourceCallback
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ResetGeometry () : SourceCallback() {}
|
ResetGeometry () : SourceCallback() {}
|
||||||
void update (Source *s, float) override;
|
void update (Source *s, float dt) override;
|
||||||
SourceCallback *clone () const override;
|
SourceCallback *clone () const override;
|
||||||
CallbackType type () const override { return CALLBACK_RESETGEO; }
|
CallbackType type () const override { return CALLBACK_RESETGEO; }
|
||||||
};
|
};
|
||||||
@@ -181,7 +189,6 @@ public:
|
|||||||
class SetGeometry : public SourceCallback
|
class SetGeometry : public SourceCallback
|
||||||
{
|
{
|
||||||
float duration_;
|
float duration_;
|
||||||
float progress_;
|
|
||||||
Group start_;
|
Group start_;
|
||||||
Group target_;
|
Group target_;
|
||||||
bool bidirectional_;
|
bool bidirectional_;
|
||||||
@@ -207,12 +214,11 @@ public:
|
|||||||
class Grab : public SourceCallback
|
class Grab : public SourceCallback
|
||||||
{
|
{
|
||||||
glm::vec2 speed_;
|
glm::vec2 speed_;
|
||||||
glm::vec2 start_;
|
glm::vec2 pos_;
|
||||||
float duration_;
|
float duration_;
|
||||||
float progress_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Grab(float dx = 0.f, float dy = 0.f, float ms = 0.f);
|
Grab(float dx = 0.f, float dy = 0.f, float ms = FLT_MAX);
|
||||||
|
|
||||||
glm::vec2 value () const { return speed_; }
|
glm::vec2 value () const { return speed_; }
|
||||||
void setValue (glm::vec2 d) { speed_ = d; }
|
void setValue (glm::vec2 d) { speed_ = d; }
|
||||||
@@ -222,6 +228,7 @@ public:
|
|||||||
void update (Source *s, float) override;
|
void update (Source *s, float) override;
|
||||||
void multiply (float factor) override;
|
void multiply (float factor) override;
|
||||||
SourceCallback *clone () const override;
|
SourceCallback *clone () const override;
|
||||||
|
SourceCallback *reverse(Source *) const override;
|
||||||
CallbackType type () const override { return CALLBACK_GRAB; }
|
CallbackType type () const override { return CALLBACK_GRAB; }
|
||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
};
|
};
|
||||||
@@ -229,12 +236,10 @@ public:
|
|||||||
class Resize : public SourceCallback
|
class Resize : public SourceCallback
|
||||||
{
|
{
|
||||||
glm::vec2 speed_;
|
glm::vec2 speed_;
|
||||||
glm::vec2 start_;
|
|
||||||
float duration_;
|
float duration_;
|
||||||
float progress_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Resize(float dx = 0.f, float dy = 0.f, float ms = 0.f);
|
Resize(float dx = 0.f, float dy = 0.f, float ms = FLT_MAX);
|
||||||
|
|
||||||
glm::vec2 value () const { return speed_; }
|
glm::vec2 value () const { return speed_; }
|
||||||
void setValue (glm::vec2 d) { speed_ = d; }
|
void setValue (glm::vec2 d) { speed_ = d; }
|
||||||
@@ -244,6 +249,7 @@ public:
|
|||||||
void update (Source *s, float) override;
|
void update (Source *s, float) override;
|
||||||
void multiply (float factor) override;
|
void multiply (float factor) override;
|
||||||
SourceCallback *clone () const override;
|
SourceCallback *clone () const override;
|
||||||
|
SourceCallback *reverse(Source *) const override;
|
||||||
CallbackType type () const override { return CALLBACK_RESIZE; }
|
CallbackType type () const override { return CALLBACK_RESIZE; }
|
||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
};
|
};
|
||||||
@@ -251,12 +257,11 @@ public:
|
|||||||
class Turn : public SourceCallback
|
class Turn : public SourceCallback
|
||||||
{
|
{
|
||||||
float speed_;
|
float speed_;
|
||||||
float start_;
|
float angle_;
|
||||||
float duration_;
|
float duration_;
|
||||||
float progress_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Turn(float speed = 0.f, float ms = 0.f);
|
Turn(float speed = 0.f, float ms = FLT_MAX);
|
||||||
|
|
||||||
float value () const { return speed_; }
|
float value () const { return speed_; }
|
||||||
void setValue (float d) { speed_ = d; }
|
void setValue (float d) { speed_ = d; }
|
||||||
@@ -266,6 +271,7 @@ public:
|
|||||||
void update (Source *s, float) override;
|
void update (Source *s, float) override;
|
||||||
void multiply (float factor) override;
|
void multiply (float factor) override;
|
||||||
SourceCallback *clone () const override;
|
SourceCallback *clone () const override;
|
||||||
|
SourceCallback *reverse(Source *) const override;
|
||||||
CallbackType type () const override { return CALLBACK_TURN; }
|
CallbackType type () const override { return CALLBACK_TURN; }
|
||||||
void accept (Visitor& v) override;
|
void accept (Visitor& v) override;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -151,7 +151,10 @@ SourceList join (const SourceList &first, const SourceList &second)
|
|||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SourceLink::SourceLink(uint64_t id, Session *se): host_(nullptr), target_(nullptr), id_(0)
|
||||||
|
{
|
||||||
|
connect(id, se);
|
||||||
|
}
|
||||||
|
|
||||||
SourceLink::SourceLink(Source *s): host_(nullptr), target_(nullptr), id_(0)
|
SourceLink::SourceLink(Source *s): host_(nullptr), target_(nullptr), id_(0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ class SourceLink {
|
|||||||
public:
|
public:
|
||||||
SourceLink(): host_(nullptr), target_(nullptr), id_(0) { }
|
SourceLink(): host_(nullptr), target_(nullptr), id_(0) { }
|
||||||
SourceLink(const SourceLink &);
|
SourceLink(const SourceLink &);
|
||||||
|
SourceLink(uint64_t id, Session *se);
|
||||||
SourceLink(Source *s);
|
SourceLink(Source *s);
|
||||||
~SourceLink();
|
~SourceLink();
|
||||||
|
|
||||||
|
|||||||
@@ -4587,26 +4587,6 @@ void InputMappingInterface::SliderParametersCallback(SourceCallback *callback, S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputMappingInterface::readInputSource()
|
|
||||||
{
|
|
||||||
// clear
|
|
||||||
input_sources_callbacks.clear();
|
|
||||||
memset(input_assigned, 0, sizeof(input_assigned));
|
|
||||||
|
|
||||||
// loop over sources of the session
|
|
||||||
Session *ses = Mixer::manager().session();
|
|
||||||
for (auto sit = ses->begin(); sit != ses->end(); ++sit) {
|
|
||||||
// loop over registered keys
|
|
||||||
std::list<uint> inputs = (*sit)->callbackInputs();
|
|
||||||
for (auto k = inputs.begin(); k != inputs.end(); ++k) {
|
|
||||||
// add entry in input map
|
|
||||||
std::list<SourceCallback *> callbacks = (*sit)->inputCallbacks(*k);
|
|
||||||
for (auto c = callbacks.begin(); c != callbacks.end(); ++c )
|
|
||||||
input_sources_callbacks.emplace( *k, std::pair<Source *, SourceCallback*>(*sit, *c) );
|
|
||||||
input_assigned[*k] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InputMappingInterface::Render()
|
void InputMappingInterface::Render()
|
||||||
{
|
{
|
||||||
@@ -4630,8 +4610,8 @@ void InputMappingInterface::Render()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update internal data structures
|
// short variable to refer to session
|
||||||
readInputSource();
|
Session *S = Mixer::manager().session();
|
||||||
|
|
||||||
// menu (no title bar)
|
// menu (no title bar)
|
||||||
if (ImGui::BeginMenuBar())
|
if (ImGui::BeginMenuBar())
|
||||||
@@ -4645,11 +4625,8 @@ void InputMappingInterface::Render()
|
|||||||
ImGui::MenuItem( ICON_FA_BAN " Disable", nullptr, &Settings::application.mapping.disabled);
|
ImGui::MenuItem( ICON_FA_BAN " Disable", nullptr, &Settings::application.mapping.disabled);
|
||||||
|
|
||||||
// Clear all
|
// Clear all
|
||||||
if ( ImGui::MenuItem( ICON_FA_BACKSPACE " Clear all" ) ){
|
if ( ImGui::MenuItem( ICON_FA_BACKSPACE " Clear all" ) )
|
||||||
Session *ses = Mixer::manager().session();
|
S->clearSourceCallbacks();
|
||||||
for (auto sit = ses->begin(); sit != ses->end(); ++sit)
|
|
||||||
(*sit)->clearInputCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
// output manager menu
|
// output manager menu
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
@@ -4684,29 +4661,24 @@ void InputMappingInterface::Render()
|
|||||||
const std::string keymenu = ICON_FA_HAND_POINT_RIGHT " Input " + Control::manager().inputLabel(current_input_);
|
const std::string keymenu = ICON_FA_HAND_POINT_RIGHT " Input " + Control::manager().inputLabel(current_input_);
|
||||||
if (ImGui::BeginMenu(keymenu.c_str()) )
|
if (ImGui::BeginMenu(keymenu.c_str()) )
|
||||||
{
|
{
|
||||||
if ( ImGui::MenuItem( ICON_FA_WINDOW_CLOSE " Reset mapping", NULL, false, input_assigned[current_input_] ) ){
|
if ( ImGui::MenuItem( ICON_FA_WINDOW_CLOSE " Reset mapping", NULL, false, S->inputAssigned(current_input_) ) )
|
||||||
// remove all source callback of this input
|
// remove all source callback of this input
|
||||||
auto current_source_callback = input_sources_callbacks.equal_range(current_input_);
|
S->deleteSourceCallbacks(current_input_);
|
||||||
for (auto kit = current_source_callback.first; kit != current_source_callback.second; ++kit)
|
|
||||||
kit->second.first->removeInputCallback(kit->second.second);
|
|
||||||
// internal data structure changed
|
|
||||||
readInputSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome", input_assigned[current_input_]))
|
if (ImGui::BeginMenu(ICON_FA_CLOCK " Metronome", S->inputAssigned(current_input_)))
|
||||||
{
|
{
|
||||||
Metronome::Synchronicity sync = Metronome::SYNC_NONE;
|
Metronome::Synchronicity sync = S->inputSynchrony(current_input_);
|
||||||
bool active = sync == Metronome::SYNC_NONE;
|
bool active = sync == Metronome::SYNC_NONE;
|
||||||
if (ImGuiToolkit::MenuItemIcon(5, 13, " Not synchronized", active )){
|
if (ImGuiToolkit::MenuItemIcon(5, 13, " Not synchronized", active )){
|
||||||
|
S->setInputSynchrony(current_input_, Metronome::SYNC_NONE);
|
||||||
}
|
}
|
||||||
active = sync == Metronome::SYNC_BEAT;
|
active = sync == Metronome::SYNC_BEAT;
|
||||||
if (ImGuiToolkit::MenuItemIcon(6, 13, " Sync to beat", active )){
|
if (ImGuiToolkit::MenuItemIcon(6, 13, " Sync to beat", active )){
|
||||||
|
S->setInputSynchrony(current_input_, Metronome::SYNC_BEAT);
|
||||||
}
|
}
|
||||||
active = sync == Metronome::SYNC_PHASE;
|
active = sync == Metronome::SYNC_PHASE;
|
||||||
if (ImGuiToolkit::MenuItemIcon(7, 13, " Sync to phase", active )){
|
if (ImGuiToolkit::MenuItemIcon(7, 13, " Sync to phase", active )){
|
||||||
|
S->setInputSynchrony(current_input_, Metronome::SYNC_PHASE);
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
@@ -4716,17 +4688,13 @@ void InputMappingInterface::Render()
|
|||||||
// static var for the copy-paste mechanism
|
// static var for the copy-paste mechanism
|
||||||
static uint _copy_current_input = INPUT_UNDEFINED;
|
static uint _copy_current_input = INPUT_UNDEFINED;
|
||||||
// 2) Copy (if there are callbacks assigned)
|
// 2) Copy (if there are callbacks assigned)
|
||||||
if (ImGui::MenuItem("Copy", NULL, false, input_assigned[current_input_] ))
|
if (ImGui::MenuItem("Copy", NULL, false, S->inputAssigned(current_input_) ))
|
||||||
// Remember the index of the input to copy
|
// Remember the index of the input to copy
|
||||||
_copy_current_input = current_input_;
|
_copy_current_input = current_input_;
|
||||||
// 3) Paste (if copied input index is assigned)
|
// 3) Paste (if copied input index is assigned)
|
||||||
if (ImGui::MenuItem("Paste", NULL, false, input_assigned[_copy_current_input] )) {
|
if (ImGui::MenuItem("Paste", NULL, false, S->inputAssigned(current_input_) )) {
|
||||||
// create source callbacks at current input cloning those of the copied index
|
// copy source callbacks from rememberd index to current input index
|
||||||
auto copy_source_callback = input_sources_callbacks.equal_range(_copy_current_input);
|
S->copySourceCallback(_copy_current_input, current_input_);
|
||||||
for (auto kit = copy_source_callback.first; kit != copy_source_callback.second; ++kit)
|
|
||||||
kit->second.first->addInputCallback(current_input_, kit->second.second->clone());
|
|
||||||
// internal data structure changed
|
|
||||||
readInputSource();
|
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
@@ -4768,13 +4736,14 @@ void InputMappingInterface::Render()
|
|||||||
}
|
}
|
||||||
// draw key button
|
// draw key button
|
||||||
ImGui::PushID(ik);
|
ImGui::PushID(ik);
|
||||||
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), input_assigned[ik], 0, keyLetterIconSize)) {
|
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), S->inputAssigned(ik), 0, keyLetterIconSize)) {
|
||||||
current_input_ = ik;
|
current_input_ = ik;
|
||||||
|
// TODO SET VAR current input assigned??
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
// if user clics and drags an assigned key icon...
|
// if user clics and drags an assigned key icon...
|
||||||
if (input_assigned[ik] && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
if (S->inputAssigned(ik) && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||||
ImGui::SetDragDropPayload("DND_KEYBOARD", &ik, sizeof(uint));
|
ImGui::SetDragDropPayload("DND_KEYBOARD", &ik, sizeof(uint));
|
||||||
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ik).c_str());
|
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ik).c_str());
|
||||||
ImGui::EndDragDropSource();
|
ImGui::EndDragDropSource();
|
||||||
@@ -4785,10 +4754,8 @@ void InputMappingInterface::Render()
|
|||||||
if ( payload->DataSize == sizeof(uint) ) {
|
if ( payload->DataSize == sizeof(uint) ) {
|
||||||
// drop means change key of input callbacks
|
// drop means change key of input callbacks
|
||||||
uint previous_input_key = *(const int*)payload->Data;
|
uint previous_input_key = *(const int*)payload->Data;
|
||||||
// index of current source changed;
|
// swap
|
||||||
auto result = input_sources_callbacks.equal_range(previous_input_key);
|
S->swapSourceCallback(previous_input_key, ik);
|
||||||
for (auto kit = result.first; kit != result.second; ++kit)
|
|
||||||
kit->second.first->swapInputCallback(previous_input_key, ik);
|
|
||||||
// switch to this key
|
// switch to this key
|
||||||
current_input_ = ik;
|
current_input_ = ik;
|
||||||
}
|
}
|
||||||
@@ -4848,12 +4815,12 @@ void InputMappingInterface::Render()
|
|||||||
}
|
}
|
||||||
// draw key button
|
// draw key button
|
||||||
ImGui::PushID(ik);
|
ImGui::PushID(ik);
|
||||||
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), input_assigned[ik], 0, iconsize)) {
|
if (ImGui::Selectable(Control::manager().inputLabel(ik).c_str(), S->inputAssigned(ik), 0, iconsize)) {
|
||||||
current_input_ = ik;
|
current_input_ = ik;
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
// if user clics and drags an assigned key icon...
|
// if user clics and drags an assigned key icon...
|
||||||
if (input_assigned[ik] && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
if (S->inputAssigned(ik) && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||||
ImGui::SetDragDropPayload("DND_NUMPAD", &ik, sizeof(uint));
|
ImGui::SetDragDropPayload("DND_NUMPAD", &ik, sizeof(uint));
|
||||||
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ik).c_str());
|
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ik).c_str());
|
||||||
ImGui::EndDragDropSource();
|
ImGui::EndDragDropSource();
|
||||||
@@ -4864,10 +4831,8 @@ void InputMappingInterface::Render()
|
|||||||
if ( payload->DataSize == sizeof(uint) ) {
|
if ( payload->DataSize == sizeof(uint) ) {
|
||||||
// drop means change key of input callbacks
|
// drop means change key of input callbacks
|
||||||
uint previous_input_key = *(const int*)payload->Data;
|
uint previous_input_key = *(const int*)payload->Data;
|
||||||
// index of current source changed;
|
// swap
|
||||||
auto result = input_sources_callbacks.equal_range(previous_input_key);
|
S->swapSourceCallback(previous_input_key, ik);
|
||||||
for (auto kit = result.first; kit != result.second; ++kit)
|
|
||||||
kit->second.first->swapInputCallback(previous_input_key, ik);
|
|
||||||
// switch to this key
|
// switch to this key
|
||||||
current_input_ = ik;
|
current_input_ = ik;
|
||||||
}
|
}
|
||||||
@@ -4924,10 +4889,12 @@ void InputMappingInterface::Render()
|
|||||||
|
|
||||||
// draw key button
|
// draw key button
|
||||||
ImGui::PushID(it);
|
ImGui::PushID(it);
|
||||||
if (ImGui::Selectable(" ", input_assigned[it], 0, keyNumpadIconSize))
|
if (ImGui::Selectable(" ", S->inputAssigned(it), 0, keyNumpadIconSize))
|
||||||
current_input_ = it;
|
current_input_ = it;
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
|
// TODO DragN DROP
|
||||||
|
|
||||||
// 4 elements in a row
|
// 4 elements in a row
|
||||||
if ((t % 4) < 3) ImGui::SameLine();
|
if ((t % 4) < 3) ImGui::SameLine();
|
||||||
|
|
||||||
@@ -4997,12 +4964,12 @@ void InputMappingInterface::Render()
|
|||||||
}
|
}
|
||||||
// draw key button
|
// draw key button
|
||||||
ImGui::PushID(ig);
|
ImGui::PushID(ig);
|
||||||
if (ImGui::Selectable(gamepad_labels[b].c_str(), input_assigned[ig], 0, keyLetterIconSize))
|
if (ImGui::Selectable(gamepad_labels[b].c_str(), S->inputAssigned(ig), 0, keyLetterIconSize))
|
||||||
current_input_ = ig;
|
current_input_ = ig;
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
||||||
// if user clics and drags an assigned key icon...
|
// if user clics and drags an assigned key icon...
|
||||||
if (input_assigned[ig] && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
if (S->inputAssigned(ig) && ImGui::BeginDragDropSource(ImGuiDragDropFlags_None)) {
|
||||||
ImGui::SetDragDropPayload("DND_GAMEPAD", &ig, sizeof(uint));
|
ImGui::SetDragDropPayload("DND_GAMEPAD", &ig, sizeof(uint));
|
||||||
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ig).c_str());
|
ImGui::Text( ICON_FA_CUBE " %s ", Control::manager().inputLabel(ig).c_str());
|
||||||
ImGui::EndDragDropSource();
|
ImGui::EndDragDropSource();
|
||||||
@@ -5013,10 +4980,8 @@ void InputMappingInterface::Render()
|
|||||||
if ( payload->DataSize == sizeof(uint) ) {
|
if ( payload->DataSize == sizeof(uint) ) {
|
||||||
// drop means change key of input callbacks
|
// drop means change key of input callbacks
|
||||||
uint previous_input_key = *(const int*)payload->Data;
|
uint previous_input_key = *(const int*)payload->Data;
|
||||||
// index of current source changed;
|
// swap
|
||||||
auto result = input_sources_callbacks.equal_range(previous_input_key);
|
S->swapSourceCallback(previous_input_key, ig);
|
||||||
for (auto kit = result.first; kit != result.second; ++kit)
|
|
||||||
kit->second.first->swapInputCallback(previous_input_key, ig);
|
|
||||||
// switch to this key
|
// switch to this key
|
||||||
current_input_ = ig;
|
current_input_ = ig;
|
||||||
}
|
}
|
||||||
@@ -5054,7 +5019,7 @@ void InputMappingInterface::Render()
|
|||||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS), axis_bar_size);
|
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS), axis_bar_size);
|
||||||
// Draw button to assign the axis to an action
|
// Draw button to assign the axis to an action
|
||||||
ImGui::SetCursorScreenPos( pos );
|
ImGui::SetCursorScreenPos( pos );
|
||||||
if (ImGui::Selectable("LX", input_assigned[INPUT_JOYSTICK_FIRST_AXIS], 0, axis_icon_size))
|
if (ImGui::Selectable("LX", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS), 0, axis_icon_size))
|
||||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS;
|
current_input_ = INPUT_JOYSTICK_FIRST_AXIS;
|
||||||
// Draw frame around current gamepad axis
|
// Draw frame around current gamepad axis
|
||||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS)
|
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS)
|
||||||
@@ -5064,7 +5029,7 @@ void InputMappingInterface::Render()
|
|||||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+1), axis_bar_size);
|
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+1), axis_bar_size);
|
||||||
ImGui::SetCursorScreenPos( pos );
|
ImGui::SetCursorScreenPos( pos );
|
||||||
if (ImGui::Selectable("LY", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+1], 0, axis_icon_size))
|
if (ImGui::Selectable("LY", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+1), 0, axis_icon_size))
|
||||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+1;
|
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+1;
|
||||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+1)
|
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+1)
|
||||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||||
@@ -5073,7 +5038,7 @@ void InputMappingInterface::Render()
|
|||||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+2), axis_bar_size);
|
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+2), axis_bar_size);
|
||||||
ImGui::SetCursorScreenPos( pos );
|
ImGui::SetCursorScreenPos( pos );
|
||||||
if (ImGui::Selectable("L2", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+2], 0, axis_icon_size))
|
if (ImGui::Selectable("L2", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+2), 0, axis_icon_size))
|
||||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+2;
|
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+2;
|
||||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+2)
|
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+2)
|
||||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||||
@@ -5088,7 +5053,7 @@ void InputMappingInterface::Render()
|
|||||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+3), axis_bar_size);
|
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+3), axis_bar_size);
|
||||||
ImGui::SetCursorScreenPos( pos );
|
ImGui::SetCursorScreenPos( pos );
|
||||||
if (ImGui::Selectable("RX", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+3], 0, axis_icon_size))
|
if (ImGui::Selectable("RX", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+3), 0, axis_icon_size))
|
||||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+3;
|
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+3;
|
||||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+3)
|
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+3)
|
||||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||||
@@ -5097,7 +5062,7 @@ void InputMappingInterface::Render()
|
|||||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+4), axis_bar_size);
|
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+4), axis_bar_size);
|
||||||
ImGui::SetCursorScreenPos( pos );
|
ImGui::SetCursorScreenPos( pos );
|
||||||
if (ImGui::Selectable("RY", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+4], 0, axis_icon_size))
|
if (ImGui::Selectable("RY", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+4), 0, axis_icon_size))
|
||||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+4;
|
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+4;
|
||||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+4)
|
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+4)
|
||||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||||
@@ -5106,7 +5071,7 @@ void InputMappingInterface::Render()
|
|||||||
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
ImGui::SetCursorScreenPos( pos + axis_bar_pos);
|
||||||
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+5), axis_bar_size);
|
ImGuiToolkit::ValueBar(Control::manager().inputValue(INPUT_JOYSTICK_FIRST_AXIS+5), axis_bar_size);
|
||||||
ImGui::SetCursorScreenPos( pos );
|
ImGui::SetCursorScreenPos( pos );
|
||||||
if (ImGui::Selectable("R2", input_assigned[INPUT_JOYSTICK_FIRST_AXIS+5], 0, axis_icon_size))
|
if (ImGui::Selectable("R2", S->inputAssigned(INPUT_JOYSTICK_FIRST_AXIS+5), 0, axis_icon_size))
|
||||||
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+5;
|
current_input_ = INPUT_JOYSTICK_FIRST_AXIS+5;
|
||||||
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+5)
|
if (current_input_ == INPUT_JOYSTICK_FIRST_AXIS+5)
|
||||||
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
draw_list->AddRect(pos, pos + axis_icon_size, ImGui::GetColorU32(ImGuiCol_Text), 6.f, ImDrawCornerFlags_All, 3.f);
|
||||||
@@ -5126,20 +5091,20 @@ void InputMappingInterface::Render()
|
|||||||
|
|
||||||
float w = ImGui::GetWindowWidth() *0.25f;
|
float w = ImGui::GetWindowWidth() *0.25f;
|
||||||
|
|
||||||
if (input_assigned[current_input_]) {
|
if (S->inputAssigned(current_input_)) {
|
||||||
|
|
||||||
auto result = input_sources_callbacks.equal_range(current_input_);
|
auto result = S->getSourceCallbacks(current_input_);
|
||||||
for (auto kit = result.first; kit != result.second; ++kit) {
|
for (auto kit = result.cbegin(); kit != result.cend(); ++kit) {
|
||||||
|
|
||||||
Source *source = kit->second.first;
|
Source *source = kit->first;
|
||||||
SourceCallback *callback = kit->second.second;
|
SourceCallback *callback = kit->second;
|
||||||
|
|
||||||
// push ID because we repeat the same UI
|
// push ID because we repeat the same UI
|
||||||
ImGui::PushID( (void*) callback);
|
ImGui::PushID( (void*) callback);
|
||||||
|
|
||||||
// Delete interface
|
// Delete interface
|
||||||
if (ImGuiToolkit::IconButton(ICON_FA_MINUS, "Remove") ){
|
if (ImGuiToolkit::IconButton(ICON_FA_MINUS, "Remove") ){
|
||||||
source->removeInputCallback(callback);
|
S->deleteSourceCallback(callback);
|
||||||
// reload
|
// reload
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
break;
|
break;
|
||||||
@@ -5148,12 +5113,10 @@ void InputMappingInterface::Render()
|
|||||||
// Select Source
|
// Select Source
|
||||||
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
ImGui::SameLine(0, IMGUI_SAME_LINE);
|
||||||
ImGui::SetNextItemWidth(w);
|
ImGui::SetNextItemWidth(w);
|
||||||
Source *select = ComboSelectSource(source);
|
Source *selected_source = ComboSelectSource(source);
|
||||||
if (select != nullptr) {
|
if (selected_source != nullptr) {
|
||||||
// copy callback to other source
|
// reassign the callback to newly selected source
|
||||||
select->addInputCallback(current_input_, callback->clone());
|
S->assignSourceCallback(current_input_, selected_source, callback);
|
||||||
// remove previous callback
|
|
||||||
source->removeInputCallback(callback);
|
|
||||||
// reload
|
// reload
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
break;
|
break;
|
||||||
@@ -5165,9 +5128,9 @@ void InputMappingInterface::Render()
|
|||||||
uint type = ComboSelectCallback( callback->type() );
|
uint type = ComboSelectCallback( callback->type() );
|
||||||
if (type > 0) {
|
if (type > 0) {
|
||||||
// remove previous callback
|
// remove previous callback
|
||||||
source->removeInputCallback(callback);
|
S->deleteSourceCallback(callback);
|
||||||
// add callback
|
// assign callback
|
||||||
source->addInputCallback(current_input_, SourceCallback::create((SourceCallback::CallbackType)type) );
|
S->assignSourceCallback(current_input_, source, SourceCallback::create((SourceCallback::CallbackType)type) );
|
||||||
// reload
|
// reload
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
break;
|
break;
|
||||||
@@ -5222,7 +5185,7 @@ void InputMappingInterface::Render()
|
|||||||
// user selected a callback type
|
// user selected a callback type
|
||||||
if (temp_new_callback > 0) {
|
if (temp_new_callback > 0) {
|
||||||
// step 4 : create new callback and add it to source
|
// step 4 : create new callback and add it to source
|
||||||
temp_new_source->addInputCallback(current_input_, SourceCallback::create((SourceCallback::CallbackType)temp_new_callback) );
|
S->assignSourceCallback(current_input_, temp_new_source, SourceCallback::create((SourceCallback::CallbackType)temp_new_callback) );
|
||||||
// done
|
// done
|
||||||
temp_new_source = nullptr;
|
temp_new_source = nullptr;
|
||||||
temp_new_callback = 0;
|
temp_new_callback = 0;
|
||||||
|
|||||||
@@ -368,13 +368,8 @@ class InputMappingInterface : public WorkspaceWindow
|
|||||||
{
|
{
|
||||||
std::array< std::string, 4 > input_mode;
|
std::array< std::string, 4 > input_mode;
|
||||||
std::array< uint, 4 > current_input_for_mode;
|
std::array< uint, 4 > current_input_for_mode;
|
||||||
|
|
||||||
// data structures more adapted for display
|
|
||||||
std::multimap< uint, std::pair<Source *, SourceCallback*> > input_sources_callbacks;
|
|
||||||
bool input_assigned[100]{};
|
|
||||||
uint current_input_;
|
uint current_input_;
|
||||||
|
|
||||||
void readInputSource();
|
|
||||||
Source *ComboSelectSource(Source *current = nullptr);
|
Source *ComboSelectSource(Source *current = nullptr);
|
||||||
uint ComboSelectCallback(uint current);
|
uint ComboSelectCallback(uint current);
|
||||||
void SliderParametersCallback(SourceCallback *callback, Source *source);
|
void SliderParametersCallback(SourceCallback *callback, Source *source);
|
||||||
|
|||||||
Reference in New Issue
Block a user