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:
Bruno Herbelin
2022-03-07 00:23:24 +01:00
parent 83e77681d9
commit 39b61fe331
18 changed files with 689 additions and 478 deletions

View File

@@ -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)];

View File

@@ -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:

View File

@@ -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();

View File

@@ -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;
}; };

View File

@@ -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];
}

View File

@@ -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_;
}; };

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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)
} }

View File

@@ -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,

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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;
}; };

View File

@@ -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)
{ {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);