1 
2 
3 #include "toonz/fxdag.h"
4 
5 // TnzLib includes
6 #include "toonz/tcolumnfxset.h"
7 #include "toonz/tcolumnfx.h"
8 #include "tw/stringtable.h"
9 
10 // TnzBase includes
11 #include "tmacrofx.h"
12 #include "tfxattributes.h"
13 
14 // TnzCore includes
15 #include "tstream.h"
16 
17 // STD includes
18 //#include <cwctypes>
19 
20 //===================================================================
21 
FxDag()22 FxDag::FxDag()
23     : m_internalFxs(new TFxSet())
24     , m_terminalFxs(new TFxSet())
25     , m_groupIdCount(0)
26     , m_dagGridDimension(eSmall) {
27   TXsheetFx *xsheetFx = new TXsheetFx;
28   xsheetFx->setFxDag(this);
29   m_xsheetFx = xsheetFx;
30   m_xsheetFx->addRef();
31   m_xsheetFx->setNewIdentifier();
32   addOutputFx();
33   m_outputFxs[0]->getInputPort(0)->setFx(m_xsheetFx);
34 }
35 
36 //-------------------------------------------------------------------
37 
~FxDag()38 FxDag::~FxDag() {
39   delete m_internalFxs;
40   delete m_terminalFxs;
41   m_xsheetFx->release();
42   int i;
43   for (i = 0; i < (int)m_outputFxs.size(); i++) m_outputFxs[i]->release();
44 }
45 
46 //-------------------------------------------------------------------
47 
addOutputFx(TOutputFx * outputFx)48 TOutputFx *FxDag::addOutputFx(TOutputFx *outputFx) {
49   if (!outputFx) outputFx = new TOutputFx();
50   outputFx->addRef();
51   m_xsheetFx->setNewIdentifier();
52   assert(outputFx->getInputPortCount() == 1);
53   m_outputFxs.push_back(outputFx);
54   return outputFx;
55 }
56 
57 //-------------------------------------------------------------------
58 
removeOutputFx(TOutputFx * fx)59 void FxDag::removeOutputFx(TOutputFx *fx) {
60   assert(fx);
61   if (m_outputFxs.size() == 1) return;
62   if (std::find(m_outputFxs.begin(), m_outputFxs.end(), fx) ==
63       m_outputFxs.end())
64     return;
65   m_outputFxs.erase(std::remove(m_outputFxs.begin(), m_outputFxs.end(), fx),
66                     m_outputFxs.end());
67   fx->release();
68 }
69 
70 //-------------------------------------------------------------------
71 
getInternalFxs() const72 TFxSet *FxDag::getInternalFxs() const { return m_internalFxs; }
73 
74 //-------------------------------------------------------------------
75 
setCurrentOutputFx(TOutputFx * fx)76 void FxDag::setCurrentOutputFx(TOutputFx *fx) {
77   std::vector<TOutputFx *>::iterator it;
78   it = std::find(m_outputFxs.begin(), m_outputFxs.end(), fx);
79   if (it == m_outputFxs.end()) return;
80   if (it == m_outputFxs.begin()) return;
81   std::swap(*it, *m_outputFxs.begin());
82 }
83 
getCurrentOutputFx() const84 TOutputFx *FxDag::getCurrentOutputFx() const {
85   assert(!m_outputFxs.empty());
86   return m_outputFxs[0];
87 }
88 
89 //-------------------------------------------------------------------
90 
checkLoop(TFx * inputFx,TFx * fx)91 bool FxDag::checkLoop(TFx *inputFx, TFx *fx) {
92   if (inputFx == fx) return true;
93   if (dynamic_cast<TXsheetFx *>(inputFx)) {
94     TFxSet *terminals = getTerminalFxs();
95     for (int i = 0; i < terminals->getFxCount(); i++) {
96       TFx *tfx = terminals->getFx(i);
97       if (tfx && checkLoop(tfx, fx)) return true;
98     }
99   } else {
100     if (TZeraryColumnFx *zerary = dynamic_cast<TZeraryColumnFx *>(inputFx))
101       inputFx = zerary->getZeraryFx();
102     for (int i = 0; i < inputFx->getInputPortCount(); i++) {
103       TFx *ifx = inputFx->getInputPort(i)->getFx();
104       if (ifx && checkLoop(ifx, fx)) return true;
105     }
106   }
107   return false;
108 }
109 
110 //-------------------------------------------------------------------
111 
getTerminalFxs() const112 TFxSet *FxDag::getTerminalFxs() const { return m_terminalFxs; }
113 
114 //-------------------------------------------------------------------
115 
addToXsheet(TFx * fx)116 void FxDag::addToXsheet(TFx *fx) { m_terminalFxs->addFx(fx); }
117 
118 //-------------------------------------------------------------------
119 
removeFromXsheet(TFx * fx)120 void FxDag::removeFromXsheet(TFx *fx) { m_terminalFxs->removeFx(fx); }
121 
122 //-------------------------------------------------------------------
123 
124 namespace {
125 struct NotAlnum {
operator ()__anon6e8644f00111::NotAlnum126   bool operator()(wint_t val) const { return !iswalnum(val); }
127 };
128 }  // namespace
129 
assignUniqueId(TFx * fx)130 void FxDag::assignUniqueId(TFx *fx) {
131   struct locals {
132     static void eraseNonAlnums(std::wstring &str) {
133       str.erase(std::remove_if(str.begin(), str.end(), NotAlnum()), str.end());
134     }
135   };  // locals
136 
137   std::string type = fx->getFxType();
138   int count        = ++m_typeTable[type];
139 
140   fx->getAttributes()->setId(count);
141 
142   std::wstring name = TStringTable::translate(type);
143   locals::eraseNonAlnums(
144       name);  // fx ids are used as XML tag names - thus, we'll restrict
145               // the char set to alnums. Specifically, '/' must be ruled out.
146               // E.g.: "Erode/Dilate 1" must become "ErodeDilate1"
147   name = name + QString::number(count).rightJustified(2, '0').toStdWString();
148 
149   if (fx->getName() == L"") fx->setName(name);
150   fx->setFxId(name);
151   m_idTable[toLower(name)] = fx;
152 }
153 
154 //-------------------------------------------------------------------
155 
getFxById(std::wstring id) const156 TFx *FxDag::getFxById(std::wstring id) const {
157   std::map<std::wstring, TFx *>::const_iterator it = m_idTable.find(id);
158   if (it == m_idTable.end())
159     return 0;
160   else
161     return it->second;
162 }
163 //-------------------------------------------------------------------
164 
updateFxTypeTable(TFx * fx,int value)165 void FxDag::updateFxTypeTable(TFx *fx, int value) {
166   std::string type  = fx->getFxType();
167   m_typeTable[type] = value;
168 }
169 
170 //-------------------------------------------------------------------
171 
updateFxIdTable(TFx * fx)172 void FxDag::updateFxIdTable(TFx *fx) { m_idTable[toLower(fx->getFxId())] = fx; }
173 
174 //-------------------------------------------------------------------
175 
getFxTypeCount(TFx * fx)176 int FxDag::getFxTypeCount(TFx *fx) {
177   std::string type = fx->getFxType();
178   std::map<std::string, int>::iterator it = m_typeTable.find(type);
179   if (it == m_typeTable.end()) return 0;
180   return it->second;
181 }
182 
183 //-------------------------------------------------------------------
184 
getFxs(std::vector<TFx * > & fxs) const185 void FxDag::getFxs(std::vector<TFx *> &fxs) const {
186   std::set<TFx *> fxSet;
187   getInternalFxs()->getFxs(fxSet);
188   fxs.insert(fxs.end(), fxSet.begin(), fxSet.end());
189 }
190 
191 //-------------------------------------------------------------------
192 
isRendered(TFx * fx) const193 bool FxDag::isRendered(TFx *fx) const {
194   if (m_terminalFxs->containsFx(fx)) return true;
195   if (dynamic_cast<TOutputFx *>(fx)) return true;
196   int i;
197   for (i = 0; i < fx->getOutputConnectionCount(); i++) {
198     TFx *outFx = fx->getOutputConnection(i)->getOwnerFx();
199     if (outFx && isRendered(outFx)) return true;
200   }
201   return false;
202 }
203 
204 //-------------------------------------------------------------------
205 
isControl(TFx * fx) const206 bool FxDag::isControl(TFx *fx) const {
207   if (m_terminalFxs->containsFx(fx)) return false;
208   if (dynamic_cast<TOutputFx *>(fx)) return false;
209   int i;
210   for (i = 0; i < fx->getOutputConnectionCount(); i++) {
211     TFxPort *port = fx->getOutputConnection(i);
212     TFx *outFx    = port->getOwnerFx();
213     if (outFx) {
214       if (outFx->getInputPort(0) != port) return true;
215       if (isControl(outFx)) return true;
216     }
217   }
218   return false;
219 }
220 
221 //-------------------------------------------------------------------
222 
223 namespace {
search(const std::map<TFx *,TFx * > & table,TFx * fx)224 TFx *search(const std::map<TFx *, TFx *> &table, TFx *fx) {
225   std::map<TFx *, TFx *>::const_iterator it = table.find(fx);
226   return it == table.end() ? 0 : it->second;
227 }
228 }
229 
230 //-------------------------------------------------------------------
231 
saveData(TOStream & os,int occupiedColumnCount)232 void FxDag::saveData(TOStream &os, int occupiedColumnCount) {
233   if (getInternalFxs()->getFxCount() > 0) {
234     os.openChild("internal");
235     getInternalFxs()->saveData(os, occupiedColumnCount);
236     os.closeChild();
237   }
238   if (getTerminalFxs()->getFxCount() > 0) {
239     os.openChild("terminal");
240     getTerminalFxs()->saveData(os, occupiedColumnCount);
241     os.closeChild();
242   }
243   os.child("xsheet") << m_xsheetFx;
244   int k;
245   for (k = 0; k < (int)m_outputFxs.size(); k++)
246     os.child("output") << m_outputFxs[k];
247   os.child("grid_dimension") << (int)m_dagGridDimension;
248 }
249 
250 //-------------------------------------------------------------------
251 
loadData(TIStream & is)252 void FxDag::loadData(TIStream &is) {
253   VersionNumber tnzVersion = is.getVersion();
254   int k;
255   for (k = 0; k < (int)m_outputFxs.size(); k++) m_outputFxs[k]->release();
256   m_outputFxs.clear();
257   std::string tagName;
258   while (is.openChild(tagName)) {
259     if (tagName == "terminal") {
260       TFxSet *fxSet = getTerminalFxs();
261       fxSet->loadData(is);
262       int i;
263       for (i = 0; i < fxSet->getFxCount(); i++) {
264         TFx *fx = fxSet->getFx(i);
265         if (fx->getAttributes()->isGrouped() &&
266             m_groupIdCount < fx->getAttributes()->getGroupId())
267           m_groupIdCount = fx->getAttributes()->getGroupId();
268         if (TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx))
269           fx = zfx->getZeraryFx();
270         if (tnzVersion < VersionNumber(1, 16)) {
271           std::wstring app = fx->getName();
272           assignUniqueId(fx);
273           fx->setName(app);
274           continue;
275         }
276         int fxTypeCount = getFxTypeCount(fx);
277         int maxFxTypeId = std::max(fxTypeCount, fx->getAttributes()->getId());
278         updateFxTypeTable(fx, maxFxTypeId);
279         TMacroFx *macroFx = dynamic_cast<TMacroFx *>(fx);
280         if (macroFx) {
281           std::vector<TFxP> fxs = macroFx->getFxs();
282           int j;
283           for (j = 0; j < (int)fxs.size(); j++) {
284             TFxP inMacroFx = fxs[j];
285             fxTypeCount    = getFxTypeCount(inMacroFx.getPointer());
286             maxFxTypeId =
287                 std::max(fxTypeCount, inMacroFx->getAttributes()->getId());
288             updateFxTypeTable(inMacroFx.getPointer(), maxFxTypeId);
289             m_idTable[toLower(inMacroFx->getFxId())] = inMacroFx.getPointer();
290           }
291         }
292       }
293     } else if (tagName == "internal") {
294       TFxSet *fxSet = getInternalFxs();
295       fxSet->loadData(is);
296       int i;
297       for (i = 0; i < fxSet->getFxCount(); i++) {
298         TFx *fx = fxSet->getFx(i);
299         if (fx->getAttributes()->isGrouped() &&
300             m_groupIdCount < fx->getAttributes()->getGroupId())
301           m_groupIdCount = fx->getAttributes()->getGroupId();
302         if (TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx))
303           fx = zfx->getZeraryFx();
304         if (tnzVersion < VersionNumber(1, 16)) {
305           std::wstring app = fx->getName();
306           assignUniqueId(fx);
307           fx->setName(app);
308           continue;
309         }
310         int fxTypeCount = getFxTypeCount(fx);
311         int maxFxTypeId = std::max(fxTypeCount, fx->getAttributes()->getId());
312         updateFxTypeTable(fx, maxFxTypeId);
313         m_idTable[toLower(fx->getFxId())] = fx;
314       }
315     } else if (tagName == "xsheet" || tagName == "output") {
316       TPersist *p = 0;
317       is >> p;
318       TFx *fx = dynamic_cast<TFx *>(p);
319       if (!fx) throw TException("FxDag. unexpeced Fx");
320       fx->addRef();
321       fx->setNewIdentifier();
322       if (tagName == "xsheet") {
323         m_xsheetFx->release();
324         m_xsheetFx = fx;
325 
326         TXsheetFx *xsheetFx = dynamic_cast<TXsheetFx *>(fx);
327         if (xsheetFx) xsheetFx->setFxDag(this);
328       } else {
329         TOutputFx *outputFx = dynamic_cast<TOutputFx *>(fx);
330         if (outputFx) m_outputFxs.push_back(outputFx);
331       }
332     } else if (tagName == "grid_dimension") {
333       is >> m_dagGridDimension;
334     } else
335       throw TException("FxDag. unexpeced tag: " + tagName);
336     is.closeChild();
337   }
338 }
339