1 
2 
3 // TnzCore includes
4 #include "tconst.h"
5 #include "tutil.h"
6 #include "tstream.h"
7 
8 // TnzBase includes
9 #include "tparamcontainer.h"
10 #include "tfxattributes.h"
11 #include "texternfx.h"
12 #include "tpassivecachemanager.h"
13 
14 // STD includes
15 #include <set>
16 
17 #include "tfx.h"
18 
19 //==============================================================================
20 
operator >>(TIStream & in,TFxP & p)21 TIStream &operator>>(TIStream &in, TFxP &p) {
22   TPersist *tmp = 0;
23   in >> tmp;
24   p = TFxP(dynamic_cast<TFx *>(tmp));
25   return in;
26 }
27 
28 //==============================================================================
29 //
30 // namespace {}
31 //
32 //------------------------------------------------------------------------------
33 
34 namespace {
35 
36 //------------------------------------------------------------------------------
37 
38 typedef std::pair<std::string, TFxPort *> NamePort;
39 typedef std::map<std::string, TFxPort *> PortTable;
40 typedef std::vector<NamePort> PortArray;
41 
42 //------------------------------------------------------------------------------
43 
44 class PortNameEq {
45   std::string m_name;
46 
47 public:
PortNameEq(const std::string & name)48   PortNameEq(const std::string &name) : m_name(name) {}
~PortNameEq()49   ~PortNameEq() {}
operator ()(const NamePort & np)50   bool operator()(const NamePort &np) { return np.first == m_name; }
51 };
52 
53 //------------------------------------------------------------------------------
54 
skipChild(TIStream & is)55 void skipChild(TIStream &is) {
56   while (!is.eos()) {
57     std::string dummy = is.getString();
58     std::string tagName;
59     while (is.openChild(tagName)) {
60       skipChild(is);
61       if (is.isBeginEndTag()) is.matchTag(tagName);
62       is.closeChild();
63     }
64     if (is.isBeginEndTag()) is.matchTag(tagName);
65   }
66 }
67 
68 //------------------------------------------------------------------------------
69 
updateDagPosition(const TPointD & pos,const VersionNumber & tnzVersion)70 TPointD updateDagPosition(const TPointD &pos, const VersionNumber &tnzVersion) {
71   if (tnzVersion < VersionNumber(1, 16)) return TConst::nowhere;
72   return pos;
73 }
74 
75 }  // namespace
76 
77 //==============================================================================
78 //
79 // TFxParamChange
80 //
81 //------------------------------------------------------------------------------
82 
TFxParamChange(TFx * fx,double firstAffectedFrame,double lastAffectedFrame,bool dragging)83 TFxParamChange::TFxParamChange(TFx *fx, double firstAffectedFrame,
84                                double lastAffectedFrame, bool dragging)
85     : TFxChange(fx, firstAffectedFrame, lastAffectedFrame, dragging) {}
86 
87 //--------------------------------------------------
88 
TFxParamChange(TFx * fx,const TParamChange & src)89 TFxParamChange::TFxParamChange(TFx *fx, const TParamChange &src)
90     : TFxChange(fx, src.m_firstAffectedFrame, src.m_lastAffectedFrame,
91                 src.m_dragging) {}
92 
93 //==============================================================================
94 //
95 // TFxChange
96 //
97 //------------------------------------------------------------------------------
98 
99 double TFxChange::m_minFrame = -(std::numeric_limits<double>::max)();
100 double TFxChange::m_maxFrame = +(std::numeric_limits<double>::max)();
101 
102 //==============================================================================
103 //
104 // TFxPortDynamicGroup
105 //
106 //------------------------------------------------------------------------------
107 
TFxPortDynamicGroup(const std::string & prefix,int minSize)108 TFxPortDynamicGroup::TFxPortDynamicGroup(const std::string &prefix, int minSize)
109     : m_portsPrefix(prefix), m_minPortsCount(minSize) {}
110 
111 //--------------------------------------------------
112 
~TFxPortDynamicGroup()113 TFxPortDynamicGroup::~TFxPortDynamicGroup() { clear(); }
114 
115 //--------------------------------------------------
116 
addPort(TFxPort * port)117 void TFxPortDynamicGroup::addPort(TFxPort *port) { m_ports.push_back(port); }
118 
119 //--------------------------------------------------
120 
removePort(TFxPort * port)121 void TFxPortDynamicGroup::removePort(TFxPort *port) {
122   m_ports.resize(std::remove(m_ports.begin(), m_ports.end(), port) -
123                  m_ports.begin());
124   delete port;
125 }
126 
127 //--------------------------------------------------
128 
clear()129 void TFxPortDynamicGroup::clear() {
130   std::for_each(m_ports.begin(), m_ports.end(), TDeleteObjectFunctor());
131   m_ports.clear();
132 }
133 
134 //==============================================================================
135 //
136 // TFxImp
137 //
138 //------------------------------------------------------------------------------
139 
140 class TFxImp {
141 public:
142   TFx *m_fx;                //!< Fx back-pointer
143   TFxImp *m_prev, *m_next;  //!< Linked fxs
144 
145   std::wstring m_name;
146   std::wstring m_fxId;
147 
148   PortTable m_portTable;  //!< Name -> port  map
149   PortArray m_portArray;  //!< Ports container
150 
151   TParamContainer m_paramContainer;
152 
153   std::set<TFxPort *> m_outputPort;
154   TFxTimeRegion m_activeTimeRegion;
155   std::set<TFxObserver *> m_observers;
156 
157   TFxAttributes m_attributes;
158 
159   static unsigned long m_nextId;
160   unsigned long m_id;  //!< Unique fx identifier, per Toonz session.
161                        //!< It is intended to be used \b solely to build
162                        //!< an internal string description of the fx.
163 public:
TFxImp(TFx * fx)164   TFxImp(TFx *fx)
165       : m_fx(fx), m_activeTimeRegion(TFxTimeRegion::createUnlimited()), m_id() {
166     m_prev = m_next = this;
167   }
168 
~TFxImp()169   ~TFxImp() {
170     m_prev->m_next = m_next;
171     m_next->m_prev = m_prev;
172   }
173 
checkLinks() const174   bool checkLinks() const {
175     assert(m_prev);
176     assert(m_next);
177     assert(m_prev->m_next == this);
178     assert(m_next->m_prev == this);
179 
180     return true;
181   }
182 
183 private:
184   // not copyable
185   TFxImp(const TFxImp &);
186   TFxImp &operator=(const TFxImp &);
187 };
188 
189 //--------------------------------------------------
190 
191 unsigned long TFxImp::m_nextId = 0;
192 
193 //==============================================================================
194 //
195 // TFxFactory
196 //
197 //------------------------------------------------------------------------------
198 
199 class TFxFactory  // singleton
200 {
201   typedef std::map<std::string, std::pair<TFxInfo, TFxDeclaration *>> Table;
202 
203   Table m_table;
204   std::vector<std::string> m_map;
205 
TFxFactory()206   TFxFactory() {}
207 
208 public:
instance()209   static TFxFactory *instance() {
210     static TFxFactory _instance;
211     return &_instance;
212   }
213 
add(const TFxInfo & info,TFxDeclaration * decl)214   void add(const TFxInfo &info, TFxDeclaration *decl) {
215     // check for dups ???
216     std::pair<TFxInfo, TFxDeclaration *> p(info, decl);
217     m_table[info.m_name] = p;
218   }
219 
create(std::string name)220   TFx *create(std::string name) {
221     Table::iterator it = m_table.find(name);
222     if (it != m_table.end()) {
223       TFxDeclaration *decl = it->second.second;
224 
225       TPersist *obj = decl->create();
226       assert(obj);
227 
228       return dynamic_cast<TFx *>(obj);
229     } else
230       return TExternFx::create(name);
231   }
232 
getFxInfos(std::vector<TFxInfo> & info) const233   void getFxInfos(std::vector<TFxInfo> &info) const {
234     for (Table::const_iterator it = m_table.begin(); it != m_table.end(); ++it)
235       info.push_back(it->second.first);
236   }
237 
getFxInfo(const std::string & fxIdentifier) const238   TFxInfo getFxInfo(const std::string &fxIdentifier) const {
239     Table::const_iterator it = m_table.find(fxIdentifier);
240     return (it != m_table.end()) ? it->second.first : TFxInfo();
241   }
242 };
243 
244 //==============================================================================
245 //
246 // TFxDeclaration
247 //
248 //------------------------------------------------------------------------------
249 
TFxDeclaration(const TFxInfo & info)250 TFxDeclaration::TFxDeclaration(const TFxInfo &info)
251     : TPersistDeclaration(info.m_name) {
252   TFxFactory::instance()->add(info, this);
253 }
254 
255 //==============================================================================
256 //
257 // TFx
258 //
259 //------------------------------------------------------------------------------
260 
261 DEFINE_CLASS_CODE(TFx, 3)
262 
263 //------------------------------------------------------------------------------
264 
TFx()265 TFx::TFx()
266     : TSmartObject(m_classCode)  // TPersist(TFxImp::m_instances)
267     , m_imp(new TFxImp(this)) {}
268 
269 //--------------------------------------------------
270 
~TFx()271 TFx::~TFx() {
272   for (std::set<TFxPort *>::iterator it = m_imp->m_outputPort.begin();
273        it != m_imp->m_outputPort.end(); ++it) {
274     TFxPort *port = *it;
275     port->setFx(0);
276   }
277 
278   delete m_imp;
279 }
280 
281 //--------------------------------------------------
282 
getName() const283 std::wstring TFx::getName() const { return m_imp->m_name; }
284 
285 //--------------------------------------------------
286 
setName(std::wstring name)287 void TFx::setName(std::wstring name) { m_imp->m_name = name; }
288 
289 //--------------------------------------------------
290 
getFxId() const291 std::wstring TFx::getFxId() const { return m_imp->m_fxId; }
292 
293 //--------------------------------------------------
294 
setFxId(std::wstring id)295 void TFx::setFxId(std::wstring id) { m_imp->m_fxId = id; }
296 
297 //--------------------------------------------------
298 
getAttributes() const299 TFxAttributes *TFx::getAttributes() const { return &m_imp->m_attributes; }
300 
301 //--------------------------------------------------
302 
getParams() const303 const TParamContainer *TFx::getParams() const {
304   return &m_imp->m_paramContainer;
305 }
306 
307 //--------------------------------------------------
308 
getParams()309 TParamContainer *TFx::getParams() { return &m_imp->m_paramContainer; }
310 
311 //--------------------------------------------------
312 
clone(bool recursive) const313 TFx *TFx::clone(bool recursive) const {
314   TFx *fx = TFx::create(getFxType());
315   assert(fx);
316   return this->clone(fx, recursive);
317 }
318 
clone(TFx * fx,bool recursive) const319 TFx *TFx::clone(TFx *fx, bool recursive) const {
320   // Copy misc stuff
321 
322   fx->m_imp->m_activeTimeRegion = m_imp->m_activeTimeRegion;
323   fx->setIdentifier(getIdentifier());
324   fx->getParams()->copy(getParams());
325   fx->setFxId(getFxId());
326   fx->setName(getName());
327 
328   // Copy attributes
329   *fx->getAttributes() = *getAttributes();
330 
331   // Clone the dynamic ports pool
332   if (hasDynamicPortGroups()) {
333     int p, pCount = m_imp->m_portArray.size();
334     for (p = 0; p != pCount; ++p) {
335       const NamePort &namedPort = m_imp->m_portArray[p];
336 
337       int groupIdx = namedPort.second->getGroupIndex();
338       if (groupIdx >= 0 && !fx->getInputPort(namedPort.first))
339         fx->addInputPort(namedPort.first, new TRasterFxPort, groupIdx);
340     }
341 
342     assert(pCount == fx->getInputPortCount());
343   }
344 
345   // copia ricorsiva sulle porte
346   if (recursive) {
347     int p, pCount = getInputPortCount();
348     for (p = 0; p != pCount; ++p) {
349       TFxPort *port = getInputPort(p);
350       if (port->getFx())
351         fx->connect(getInputPortName(p), port->getFx()->clone(true));
352     }
353   }
354 
355   return fx;
356 }
357 
358 //--------------------------------------------------
359 
linkParams(TFx * fx)360 void TFx::linkParams(TFx *fx) {
361   if (this == fx) return;
362   getParams()->link(fx->getParams());
363   m_imp->m_activeTimeRegion = fx->m_imp->m_activeTimeRegion;
364 
365   // aggiorno i link
366   assert(m_imp->checkLinks());
367   assert(fx->m_imp->checkLinks());
368 
369   std::swap(m_imp->m_next, fx->m_imp->m_next);
370   std::swap(m_imp->m_next->m_prev, fx->m_imp->m_next->m_prev);
371 
372   assert(m_imp->checkLinks());
373   assert(fx->m_imp->checkLinks());
374 }
375 
376 //--------------------------------------------------
377 
unlinkParams()378 void TFx::unlinkParams() {
379   // clone dei parametri
380   getParams()->unlink();
381 
382   assert(m_imp->m_prev);
383   assert(m_imp->m_next);
384   assert(m_imp->m_prev->m_next == m_imp);
385   assert(m_imp->m_next->m_prev == m_imp);
386   m_imp->m_prev->m_next = m_imp->m_next;
387   m_imp->m_next->m_prev = m_imp->m_prev;
388   m_imp->m_next = m_imp->m_prev = m_imp;
389 
390   notify(TFxParamsUnlinked(this));
391 }
392 
393 //--------------------------------------------------
394 
addInputPort(const std::string & name,TFxPort & port)395 bool TFx::addInputPort(const std::string &name, TFxPort &port) {
396   PortTable::iterator it = m_imp->m_portTable.find(name);
397   if (it != m_imp->m_portTable.end()) return false;
398 
399   m_imp->m_portTable[name] = &port;
400   m_imp->m_portArray.push_back(NamePort(name, &port));
401   port.setOwnerFx(this);  // back pointer to the owner...
402 
403   return true;
404 }
405 
406 //--------------------------------------------------
407 
addInputPort(const std::string & name,TFxPort * port,int groupIndex)408 bool TFx::addInputPort(const std::string &name, TFxPort *port, int groupIndex) {
409   if (!port) {
410     assert(port);
411     return false;
412   }
413 
414   if (groupIndex >= dynamicPortGroupsCount()) {
415     assert(groupIndex < dynamicPortGroupsCount());
416     return false;
417   }
418 
419   if (!addInputPort(name, *port)) return false;
420 
421   // Assign the port to the associated group
422   port->m_groupIdx = groupIndex;
423 
424   TFxPortDG *group = const_cast<TFxPortDG *>(dynamicPortGroup(groupIndex));
425   group->addPort(port);
426 
427   assert(name.find(group->m_portsPrefix) == 0);
428 
429   return true;
430 }
431 
432 //--------------------------------------------------
433 
removeInputPort(const std::string & name)434 bool TFx::removeInputPort(const std::string &name) {
435   m_imp->m_portTable.erase(name);
436 
437   PortArray::iterator it = std::find_if(
438       m_imp->m_portArray.begin(), m_imp->m_portArray.end(), PortNameEq(name));
439   if (it == m_imp->m_portArray.end()) return false;
440 
441   TFxPort *port = it->second;
442   port->setOwnerFx(0);
443 
444   if (port->m_groupIdx >= 0) {
445     TFxPortDG *group =
446         const_cast<TFxPortDG *>(this->dynamicPortGroup(port->m_groupIdx));
447     group->removePort(port);  // The port is DELETED here
448   }
449 
450   m_imp->m_portArray.erase(it);
451   return true;
452 }
453 
454 //--------------------------------------------------
455 
456 namespace {
457 struct IsPrefix {
458   const std::string &m_prefix;
operator ()__anoncc7a1ab10211::IsPrefix459   bool operator()(const NamePort &nameport) {
460     return (strncmp(m_prefix.c_str(), nameport.first.c_str(),
461                     m_prefix.size()) == 0);
462   }
463 };
464 }  // namespace
465 
clearDynamicPortGroup(int g)466 void TFx::clearDynamicPortGroup(int g) {
467   TFxPortDG *dg = const_cast<TFxPortDG *>(this->dynamicPortGroup(g));
468 
469   const std::string &prefix = dg->portsPrefix();
470 
471   std::string prefixEnd = prefix;
472   ++prefixEnd[prefixEnd.size() - 1];
473 
474   {
475     // Delete all associated ports from the ports table
476     PortTable::iterator pBegin(m_imp->m_portTable.lower_bound(prefix));
477     PortTable::iterator pEnd(m_imp->m_portTable.lower_bound(prefixEnd));
478 
479     m_imp->m_portTable.erase(pBegin, pEnd);
480 
481     // Traverse the ports array and remove all ports in the group
482     IsPrefix func = {prefix};
483     m_imp->m_portArray.resize(std::remove_if(m_imp->m_portArray.begin(),
484                                              m_imp->m_portArray.end(), func) -
485                               m_imp->m_portArray.begin());
486   }
487 
488   dg->clear();  // Has ports ownership, so deletes them
489 }
490 
491 //--------------------------------------------------
492 
addOutputConnection(TFxPort * port)493 bool TFx::addOutputConnection(TFxPort *port) {
494   assert(port->getFx() == this);
495   return m_imp->m_outputPort.insert(port).second;
496 }
497 
498 //--------------------------------------------------
499 
removeOutputConnection(TFxPort * port)500 bool TFx::removeOutputConnection(TFxPort *port) {
501   std::set<TFxPort *>::iterator it = m_imp->m_outputPort.find(port);
502   if (it == m_imp->m_outputPort.end()) return false;
503 
504   m_imp->m_outputPort.erase(it);
505   return true;
506 }
507 
508 //--------------------------------------------------
509 
getOutputConnectionCount() const510 int TFx::getOutputConnectionCount() const { return m_imp->m_outputPort.size(); }
511 
512 //--------------------------------------------------
513 
getOutputConnection(int i) const514 TFxPort *TFx::getOutputConnection(int i) const {
515   assert(0 <= i && i <= (int)m_imp->m_outputPort.size());
516   std::set<TFxPort *>::iterator it = m_imp->m_outputPort.begin();
517   std::advance(it, i);
518   if (it == m_imp->m_outputPort.end()) return 0;
519   return *it;
520 }
521 
522 //--------------------------------------------------
523 
disconnect(const std::string & name)524 bool TFx::disconnect(const std::string &name) {
525   TFxPort *port = getInputPort(name);
526   if (!port) return false;
527 
528   port->setFx(0);
529   return true;
530 }
531 
532 //--------------------------------------------------
533 
connect(const std::string & name,TFx * fx)534 bool TFx::connect(const std::string &name, TFx *fx) {
535   TFxPort *port = getInputPort(name);
536   if (!port) return false;
537 
538   port->setFx(fx);
539   return true;
540 }
541 
542 //--------------------------------------------------
543 
getInputPortCount() const544 int TFx::getInputPortCount() const { return m_imp->m_portArray.size(); }
545 
546 //--------------------------------------------------
547 
getInputPort(int index) const548 TFxPort *TFx::getInputPort(int index) const {
549   assert(0 <= index && index < (int)m_imp->m_portArray.size());
550   return m_imp->m_portArray[index].second;
551 }
552 
553 //--------------------------------------------------
554 
getInputPortName(int index) const555 std::string TFx::getInputPortName(int index) const {
556   assert(0 <= index && index < (int)(m_imp->m_portArray.size()));
557   return m_imp->m_portArray[index].first;
558 }
559 
560 //--------------------------------------------------
561 
renamePort(const std::string & oldName,const std::string & newName)562 bool TFx::renamePort(const std::string &oldName, const std::string &newName) {
563   PortTable::iterator it = m_imp->m_portTable.find(oldName);
564   if (it == m_imp->m_portTable.end()) return false;
565 
566   TFxPort *port = it->second;
567   m_imp->m_portTable.erase(it);
568   m_imp->m_portTable[newName] = port;
569 
570   PortArray::iterator it2;
571   for (it2 = m_imp->m_portArray.begin(); it2 != m_imp->m_portArray.end();
572        ++it2) {
573     if (it2->first != oldName) continue;
574 
575     it2->first = newName;
576     break;
577   }
578 
579   return true;
580 }
581 
582 //--------------------------------------------------
583 
getInputPort(const std::string & name) const584 TFxPort *TFx::getInputPort(const std::string &name) const {
585   PortTable::iterator it = m_imp->m_portTable.find(name);
586   if (it == m_imp->m_portTable.end()) return 0;
587 
588   return m_imp->m_portTable[name];
589 }
590 
591 //--------------------------------------------------
592 
getReferenceColumnIndex() const593 int TFx::getReferenceColumnIndex() const {
594   if (!m_imp->m_portArray.empty()) {
595     TFx *fx = m_imp->m_portArray[0].second->getFx();
596     if (fx) return fx->getReferenceColumnIndex();
597   }
598   return -1;
599 }
600 
601 //--------------------------------------------------
602 
getTimeRegion() const603 TFxTimeRegion TFx::getTimeRegion() const {
604   if (m_imp->m_portTable.empty()) return TFxTimeRegion::createUnlimited();
605 
606   TFxTimeRegion tr((std::numeric_limits<double>::max)(),
607                    -(std::numeric_limits<double>::max)());
608 
609   PortTable::iterator it = m_imp->m_portTable.begin();
610   for (; it != m_imp->m_portTable.end(); ++it) {
611     TFxPort *port = it->second;
612     if (port && port->isConnected() && !port->isaControlPort()) {
613       TFx *fx = port->getFx();
614       assert(fx);
615       tr += fx->getTimeRegion();
616     }
617   }
618 
619   return tr;
620 }
621 
622 //--------------------------------------------------
623 
setActiveTimeRegion(const TFxTimeRegion & tr)624 void TFx::setActiveTimeRegion(const TFxTimeRegion &tr) {
625   m_imp->m_activeTimeRegion = tr;
626 }
627 
628 //--------------------------------------------------
629 
getActiveTimeRegion() const630 TFxTimeRegion TFx::getActiveTimeRegion() const {
631   return m_imp->m_activeTimeRegion;
632 }
633 
634 //--------------------------------------------------
635 
onChange(const TParamChange & c)636 void TFx::onChange(const TParamChange &c) {
637   TFxParamChange change(this, c);
638   notify(change);
639 }
640 
641 //--------------------------------------------------
642 
addObserver(TFxObserver * obs)643 void TFx::addObserver(TFxObserver *obs) { m_imp->m_observers.insert(obs); }
644 
645 //--------------------------------------------------
646 
removeObserver(TFxObserver * obs)647 void TFx::removeObserver(TFxObserver *obs) { m_imp->m_observers.erase(obs); }
648 
649 //--------------------------------------------------
650 
notify(const TFxChange & change)651 void TFx::notify(const TFxChange &change) {
652   for (std::set<TFxObserver *>::iterator it = m_imp->m_observers.begin();
653        it != m_imp->m_observers.end(); ++it)
654     (*it)->onChange(change);
655 }
656 
657 //--------------------------------------------------
658 
notify(const TFxPortAdded & change)659 void TFx::notify(const TFxPortAdded &change) {
660   for (std::set<TFxObserver *>::iterator it = m_imp->m_observers.begin();
661        it != m_imp->m_observers.end(); ++it)
662     (*it)->onChange(change);
663 }
664 
665 //--------------------------------------------------
666 
notify(const TFxPortRemoved & change)667 void TFx::notify(const TFxPortRemoved &change) {
668   for (std::set<TFxObserver *>::iterator it = m_imp->m_observers.begin();
669        it != m_imp->m_observers.end(); ++it)
670     (*it)->onChange(change);
671 }
672 
673 //--------------------------------------------------
674 
notify(const TFxParamAdded & change)675 void TFx::notify(const TFxParamAdded &change) {
676   for (std::set<TFxObserver *>::iterator it = m_imp->m_observers.begin();
677        it != m_imp->m_observers.end(); ++it)
678     (*it)->onChange(change);
679 }
680 
681 //--------------------------------------------------
682 
notify(const TFxParamRemoved & change)683 void TFx::notify(const TFxParamRemoved &change) {
684   for (std::set<TFxObserver *>::iterator it = m_imp->m_observers.begin();
685        it != m_imp->m_observers.end(); ++it)
686     (*it)->onChange(change);
687 }
688 
689 //--------------------------------------------------
690 
getIdentifier() const691 unsigned long TFx::getIdentifier() const { return m_imp->m_id; }
692 
693 //--------------------------------------------------
694 
setIdentifier(unsigned long id)695 void TFx::setIdentifier(unsigned long id) { m_imp->m_id = id; }
696 
697 //--------------------------------------------------
698 
setNewIdentifier()699 void TFx::setNewIdentifier() { m_imp->m_id = ++m_imp->m_nextId; }
700 
701 //--------------------------------------------------
702 
loadData(TIStream & is)703 void TFx::loadData(TIStream &is) {
704   // default version of fx is 1
705   setFxVersion(1);
706 
707   std::string tagName;
708   VersionNumber tnzVersion = is.getVersion();
709   // Prevent to load "params" tag under "super" tag on saving macro fx.
710   // For now "params" tag is no longer saved under "super" tag.
711   // This is for keeping compatibility with older versions.
712   bool isInSuperTag = (is.getCurrentTagName() == "super");
713   QList<int> groupIds;
714   QList<std::wstring> groupNames;
715   while (is.openChild(tagName)) {
716     if (tagName == "params") {
717       if (isInSuperTag) {  // skip loading "params" tag under "super" tag
718         is.skipCurrentTag();
719         continue;
720       }
721       while (!is.eos()) {
722         std::string paramName;
723         while (is.openChild(paramName)) {
724           TParamVar *paramVar = getParams()->getParamVar(paramName);
725           if (paramVar && paramVar->getParam()) {
726             paramVar->getParam()->loadData(is);
727             if (paramVar->isObsolete())
728               onObsoleteParamLoaded(paramVar->getParam()->getName());
729           } else  // il parametro non e' presente -> skip
730             skipChild(is);
731 
732           is.closeChild();
733         }
734       }
735     } else if (tagName == "paramsLinkedTo") {
736       TPersist *p = 0;
737       is >> p;
738       TFx *fx = dynamic_cast<TFx *>(p);
739       if (fx == 0) throw TException("Missing linkedSetRoot");
740       linkParams(fx);
741     } else if (tagName == "ports") {
742       std::string portName;
743       while (!is.eos()) {
744         while (is.openChild(portName)) {
745           VersionNumber version = is.getVersion();
746           compatibilityTranslatePort(version.first, version.second, portName);
747 
748           // Try to find the specified port
749           TFxPort *port = getInputPort(portName);
750           if (!port) {
751             // Scan dynamic port groups for a containing one - add a port there
752             // if found
753             int g, gCount = dynamicPortGroupsCount();
754             for (g = 0; g != gCount; ++g) {
755               TFxPortDG *group = const_cast<TFxPortDG *>(dynamicPortGroup(g));
756 
757               if (group->contains(portName)) {
758                 addInputPort(portName, port = new TRasterFxPort, g);
759                 break;
760               }
761             }
762           }
763 
764           // Could not find (or add) a port with the corresponding name - throw
765           if (!port)
766             throw TException(std::string("port '") + portName +
767                              "' is not present");
768 
769           if (!is.eos()) {
770             TPersist *p = 0;
771             is >> p;
772             TFx *fx = dynamic_cast<TFx *>(p);
773             port->setFx(fx);
774           }
775 
776           is.closeChild();
777         }
778       }
779     } else if (tagName == "dagNodePos") {
780       TPointD p;
781       is >> p.x >> p.y;
782       m_imp->m_attributes.setDagNodePos(updateDagPosition(p, tnzVersion));
783     } else if (tagName == "numberId") {
784       int numberId = 0;
785       is >> numberId;
786       m_imp->m_attributes.setId(numberId);
787     } else if (tagName == "passiveCacheId") {
788       int passiveCacheId = 0;
789       is >> passiveCacheId;
790 
791       assert(passiveCacheId > 0);
792       TPassiveCacheManager::instance()->declareCached(this, passiveCacheId);
793     } else if (tagName == "name") {
794       // passo attraverso un filepath solo per evitare i problemi di blank
795       // o caratteri strani dentro il nome (sospetto che tfilepath sia gestito
796       // correttamente mentre wstring no
797       TFilePath tmp;
798       is >> tmp;
799       setName(tmp.getWideName());
800     } else if (tagName == "fxId") {
801       TFilePath tmp;
802       is >> tmp;
803       setFxId(tmp.getWideName());
804     } else if (tagName == "enabled") {
805       int flag = 1;
806       is >> flag;
807       m_imp->m_attributes.enable(flag != 0);
808     } else if (tagName == "opened") {
809       int opened = 1;
810       is >> opened;
811       m_imp->m_attributes.setIsOpened(opened);
812     } else if (tagName == "groupIds") {
813       int groupId;
814       while (!is.eos()) {
815         is >> groupId;
816         groupIds.append(groupId);
817       }
818     } else if (tagName == "groupNames") {
819       std::wstring groupName;
820       while (!is.eos()) {
821         is >> groupName;
822         groupNames.append(groupName);
823       }
824     } else if (tagName == "fxVersion") {
825       int version = 1;
826       is >> version;
827       setFxVersion(version);
828     } else {
829       throw TException("Unknown tag!");
830     }
831     is.closeChild();
832   }
833   if (!groupIds.isEmpty()) {
834     assert(groupIds.size() == groupNames.size());
835     int i;
836     for (i = 0; i < groupIds.size(); i++) {
837       m_imp->m_attributes.setGroupId(groupIds[i]);
838       m_imp->m_attributes.setGroupName(groupNames[i]);
839     }
840   }
841 }
842 
843 //--------------------------------------------------
844 
saveData(TOStream & os)845 void TFx::saveData(TOStream &os) {
846   // Prevent to save "params" tag under "super" tag on saving macro fx.
847   // Parameters for macro fx are saved in "nodes" tag and corrected upon
848   // loading. Therefore, "params" tag is not needed and even causes crash if
849   // macrofx contains CurveFx (See the issue #2424)
850   bool isInSuperTag  = (os.getCurrentTagName() == "super");
851   TFx *linkedSetRoot = this;
852   if (m_imp->m_next != m_imp) {
853     TFxImp *imp = m_imp->m_next;
854     int guard   = 0;
855     while (guard++ < 1000 && imp != m_imp) {
856       if (imp->m_fx < linkedSetRoot) linkedSetRoot = imp->m_fx;
857       imp = imp->m_next;
858     }
859     assert(imp == m_imp);
860     assert(linkedSetRoot);
861   }
862   if (linkedSetRoot == this) {
863     if (!isInSuperTag) {  // skip saving "params" tag under "super" tag
864       os.openChild("params");
865       for (int i = 0; i < getParams()->getParamCount(); i++) {
866         std::string paramName     = getParams()->getParamName(i);
867         const TParamVar *paramVar = getParams()->getParamVar(i);
868         // skip saving for the obsolete parameters
869         if (paramVar->isObsolete()) continue;
870         os.openChild(paramName);
871         paramVar->getParam()->saveData(os);
872         os.closeChild();
873       }
874       os.closeChild();
875     }
876   } else {
877     os.openChild("paramsLinkedTo");
878     os << linkedSetRoot;
879     os.closeChild();
880   }
881 
882   os.openChild("ports");
883   for (auto &namePort : m_imp->m_portArray) {
884     os.openChild(namePort.first);
885     if (namePort.second->isConnected())
886       os << TFxP(namePort.second->getFx()).getPointer();
887     os.closeChild();
888   }
889   os.closeChild();
890 
891   TPointD p = m_imp->m_attributes.getDagNodePos();
892   if (p != TConst::nowhere) os.child("dagNodePos") << p.x << p.y;
893   int numberId = m_imp->m_attributes.getId();
894   os.child("numberId") << numberId;
895   bool cacheEnabled = TPassiveCacheManager::instance()->cacheEnabled(this);
896   if (cacheEnabled)
897     os.child("passiveCacheId")
898         << TPassiveCacheManager::instance()->getPassiveCacheId(this);
899   std::wstring name = getName();
900   if (name != L"") os.child("name") << TFilePath(name);
901   std::wstring fxId = getFxId();
902   os.child("fxId") << fxId;
903   if (!m_imp->m_attributes.isEnabled()) os.child("enabled") << 0;
904   os.child("opened") << (int)m_imp->m_attributes.isOpened();
905   if (m_imp->m_attributes.isGrouped()) {
906     os.openChild("groupIds");
907     QStack<int> groupIdStack = m_imp->m_attributes.getGroupIdStack();
908     int i;
909     for (i = 0; i < groupIdStack.size(); i++) os << groupIdStack[i];
910     os.closeChild();
911     os.openChild("groupNames");
912     QStack<std::wstring> groupNameStack =
913         m_imp->m_attributes.getGroupNameStack();
914     for (i = 0; i < groupNameStack.size(); i++) os << groupNameStack[i];
915     os.closeChild();
916   }
917   if (getFxVersion() != 1) os.child("fxVersion") << getFxVersion();
918 }
919 
920 //--------------------------------------------------
921 
loadPreset(TIStream & is)922 void TFx::loadPreset(TIStream &is) {
923   std::string tagName;
924   while (is.openChild(tagName)) {
925     if (tagName == "dvpreset") {
926       std::string fxId = is.getTagAttribute("fxId");
927       if (fxId != getFxType())
928         throw TException("Preset doesn't match the fx type");
929     } else if (tagName == "params") {
930       while (!is.eos()) {
931         std::string paramName;
932         while (is.openChild(paramName)) {
933           try {
934             TParamP param = getParams()->getParam(paramName);
935             param->loadData(is);
936           } catch (TException &) { /*skip*/
937           }                        // il parametro non e' presente
938           is.closeChild();
939         }
940       }
941     } else {
942       throw TException("Fx preset unknown tag!");
943     }
944   }
945 }
946 
947 //--------------------------------------------------
948 
savePreset(TOStream & os)949 void TFx::savePreset(TOStream &os) {
950   std::map<std::string, std::string> attributes;
951   attributes.insert(std::make_pair(std::string("ver"), std::string("1.0")));
952   attributes.insert(std::make_pair(std::string("fxId"), getFxType()));
953 
954   os.openChild("dvpreset", attributes);
955 
956   os.openChild("params");
957   for (int i = 0; i < getParams()->getParamCount(); i++) {
958     std::string paramName = getParams()->getParamName(i);
959     TParam *param         = getParams()->getParam(i);
960     os.openChild(paramName);
961     param->saveData(os);
962     os.closeChild();
963   }
964   os.closeChild();
965 
966   os.closeChild();
967 }
968 
969 //--------------------------------------------------
970 
disconnectAll()971 void TFx::disconnectAll() {
972   int p, pCount = getInputPortCount();
973   for (p = 0; p != pCount; ++p) getInputPort(p)->setFx(0);
974 }
975 
976 //--------------------------------------------------
977 
create(std::string name)978 TFx *TFx::create(std::string name) {
979   return TFxFactory::instance()->create(name);
980 }
981 
982 //--------------------------------------------------
983 
listFxs(std::vector<TFxInfo> & info)984 void TFx::listFxs(std::vector<TFxInfo> &info) {
985   TFxFactory::instance()->getFxInfos(info);
986 }
987 
988 //--------------------------------------------------
989 
getFxInfo(const std::string & fxIdentifier)990 TFxInfo TFx::getFxInfo(const std::string &fxIdentifier) {
991   return TFxFactory::instance()->getFxInfo(fxIdentifier);
992 }
993 
994 //--------------------------------------------------
995 
getLinkedFx() const996 TFx *TFx::getLinkedFx() const {
997   assert(m_imp->m_next);
998   assert(m_imp->m_next->m_prev == m_imp);
999   assert(m_imp->m_next->m_fx != 0);
1000   return m_imp->m_next->m_fx;
1001 }
1002 
1003 //--------------------------------------------------
1004 
setFxVersion(int v)1005 void TFx::setFxVersion(int v) { m_imp->m_attributes.setFxVersion(v); }
1006 
1007 //--------------------------------------------------
1008 
getFxVersion() const1009 int TFx::getFxVersion() const { return m_imp->m_attributes.getFxVersion(); }
1010 
1011 //===================================================
1012 //
1013 // TFxTimeRegion
1014 //
1015 //--------------------------------------------------
1016 
1017 //! Creates an unlimited time region.
TFxTimeRegion()1018 TFxTimeRegion::TFxTimeRegion()
1019     : m_start((std::numeric_limits<double>::max)())
1020     , m_end(-(std::numeric_limits<double>::max)()) {}
1021 
1022 //--------------------------------------------------
1023 
1024 //! Creates a time region with specified start (included) and end (\b excluded).
TFxTimeRegion(double start,double end)1025 TFxTimeRegion::TFxTimeRegion(double start, double end)
1026     : m_start(start), m_end(end) {}
1027 
1028 //--------------------------------------------------
1029 
createUnlimited()1030 TFxTimeRegion TFxTimeRegion::createUnlimited() {
1031   return TFxTimeRegion(-(std::numeric_limits<double>::max)(),
1032                        (std::numeric_limits<double>::max)());
1033 }
1034 
1035 //--------------------------------------------------
1036 
contains(double time) const1037 bool TFxTimeRegion::contains(double time) const {
1038   return (m_start <= time && time < m_end);
1039 }
1040 
1041 //--------------------------------------------------
1042 
isUnlimited() const1043 bool TFxTimeRegion::isUnlimited() const {
1044   return (m_start == -(std::numeric_limits<double>::max)() ||
1045           m_end == (std::numeric_limits<double>::max)());
1046 }
1047 
1048 //--------------------------------------------------
1049 
isEmpty() const1050 bool TFxTimeRegion::isEmpty() const { return (m_end <= m_start); }
1051 
1052 //--------------------------------------------------
1053 
getFrameCount(int & count) const1054 bool TFxTimeRegion::getFrameCount(int &count) const {
1055   if (isUnlimited()) return false;
1056   count = tfloor(m_end) - tceil(m_start);
1057   return true;
1058 }
1059 
1060 //--------------------------------------------------
1061 
getFirstFrame() const1062 int TFxTimeRegion::getFirstFrame() const { return tceil(m_start); }
1063 
1064 //--------------------------------------------------
1065 
getLastFrame() const1066 int TFxTimeRegion::getLastFrame() const {
1067   if (m_end == (std::numeric_limits<double>::max)())
1068     return (std::numeric_limits<int>::max)();
1069   else
1070     return tceil(m_end) - 1;
1071 }
1072 
1073 //===================================================
1074