1
2
3 #include "tmacrofx.h"
4
5 // TnzBase includes
6 #include "tparamcontainer.h"
7 #include "tfxattributes.h"
8
9 // TnzCore includes
10 #include "tstream.h"
11
12 //--------------------------------------------------
13
14 namespace {
15
16 class MatchesFx {
17 public:
MatchesFx(const TFxP & fx)18 MatchesFx(const TFxP &fx) : m_fx(fx) {}
19
operator ()(const TFxP & fx)20 bool operator()(const TFxP &fx) {
21 return m_fx.getPointer() == fx.getPointer();
22 }
23
24 TFxP m_fx;
25 };
26
27 //--------------------------------------------------
28
pushParents(const TFxP & root,std::vector<TFxP> & fxs,const std::vector<TFxP> & selectedFxs)29 void pushParents(const TFxP &root, std::vector<TFxP> &fxs,
30 const std::vector<TFxP> &selectedFxs) {
31 int i, count = root->getInputPortCount();
32 if (count == 0) {
33 std::vector<TFxP>::const_iterator found =
34 std::find_if(fxs.begin(), fxs.end(), MatchesFx(root));
35 if (found == fxs.end()) fxs.push_back(root);
36 return;
37 }
38 for (i = 0; i < count; i++) {
39 TFxP inutFx = root->getInputPort(i)->getFx();
40 std::vector<TFxP>::const_iterator found =
41 std::find_if(selectedFxs.begin(), selectedFxs.end(), MatchesFx(inutFx));
42 if (found != selectedFxs.end()) pushParents(inutFx, fxs, selectedFxs);
43 }
44 std::vector<TFxP>::const_iterator found =
45 std::find_if(fxs.begin(), fxs.end(), MatchesFx(root));
46 if (found == fxs.end()) fxs.push_back(root);
47 }
48
49 //--------------------------------------------------
50
sortFxs(const std::vector<TFxP> & fxs)51 std::vector<TFxP> sortFxs(const std::vector<TFxP> &fxs) {
52 std::vector<TFxP> app;
53 std::vector<TFxP> roots;
54 // find fxs that could be in back of the vector.
55 int i;
56 for (i = 0; i < (int)fxs.size(); i++) {
57 TFxP fx = fxs[i];
58 int j, count = (int)fx->getOutputConnectionCount();
59 if (count == 0) {
60 roots.push_back(fx);
61 continue;
62 }
63 for (j = 0; j < count; j++) {
64 TFxP connectedFx = fx->getOutputConnection(j)->getOwnerFx();
65 std::vector<TFxP>::const_iterator found =
66 std::find_if(fxs.begin(), fxs.end(), MatchesFx(connectedFx));
67 if (found == fxs.end()) {
68 roots.push_back(fx);
69 break;
70 }
71 }
72 }
73 for (i = 0; i < (int)roots.size(); i++) pushParents(roots[i], app, fxs);
74 assert(fxs.size() == app.size());
75 return app;
76 }
77
78 //--------------------------------------------------
79
80 // raccoglie tutti i parametri dai vari TFx e li assegna anche alla macro
collectParams(TMacroFx * macroFx)81 void collectParams(TMacroFx *macroFx) {
82 int k;
83 for (k = 0; k < (int)macroFx->m_fxs.size(); k++) {
84 TFxP fx = macroFx->m_fxs[k];
85 int j;
86 for (j = 0; j < fx->getParams()->getParamCount(); j++)
87 macroFx->getParams()->add(fx->getParams()->getParamVar(j)->clone());
88 }
89 }
90
91 } // anonymous namespace
92
93 //--------------------------------------------------
94
analyze(const std::vector<TFxP> & fxs,TFxP & root,std::vector<TFxP> & roots,std::vector<TFxP> & leafs)95 bool TMacroFx::analyze(const std::vector<TFxP> &fxs, TFxP &root,
96 std::vector<TFxP> &roots, std::vector<TFxP> &leafs) {
97 if (fxs.size() == 1)
98 return false;
99 else {
100 leafs.clear();
101 roots.clear();
102 std::vector<TFxP>::const_iterator it = fxs.begin();
103 for (; it != fxs.end(); ++it) {
104 TFxP fx = *it;
105 int inputInternalConnection = 0;
106 int inputExternalConnection = 0;
107 int outputInternalConnection = 0;
108 int outputExternalConnection = 0;
109
110 int i;
111
112 // calcola se ci sono connessioni in input dall'esterno
113 // verso l'interno e/o internamente a orderedFxs
114 int inputPortCount = fx->getInputPortCount();
115 for (i = 0; i < inputPortCount; ++i) {
116 TFxPort *inputPort = fx->getInputPort(i);
117 TFx *inputPortFx = inputPort->getFx();
118 if (inputPortFx) {
119 if (std::find_if(fxs.begin(), fxs.end(), MatchesFx(inputPortFx)) !=
120 fxs.end())
121 ++inputInternalConnection;
122 else
123 ++inputExternalConnection;
124 }
125 }
126
127 // calcola se ci sono connessioni in output dall'interno
128 // verso l'esterno e/o internamente a orderedFxs
129 int outputPortCount = fx->getOutputConnectionCount();
130 for (i = 0; i < outputPortCount; ++i) {
131 TFxPort *outputPort = fx->getOutputConnection(i);
132 TFx *outputFx = outputPort->getOwnerFx();
133 if (outputFx) {
134 if (std::find_if(fxs.begin(), fxs.end(), MatchesFx(outputFx)) !=
135 fxs.end())
136 ++outputInternalConnection;
137 else
138 ++outputExternalConnection;
139 }
140 }
141
142 // se fx e' una radice
143 if ((outputExternalConnection > 0) ||
144 (outputExternalConnection == 0 && outputInternalConnection == 0)) {
145 root = fx;
146 roots.push_back(fx);
147 }
148
149 // se fx e' una foglia
150 if (inputExternalConnection > 0 || fx->getInputPortCount() == 0 ||
151 (inputExternalConnection == 0 &&
152 inputInternalConnection < fx->getInputPortCount())) {
153 leafs.push_back(fx);
154 }
155 }
156
157 if (roots.size() != 1)
158 return false;
159 else {
160 if (leafs.size() == 0) return false;
161 }
162
163 return true;
164 }
165 }
166
167 //--------------------------------------------------
168
analyze(const std::vector<TFxP> & fxs)169 bool TMacroFx::analyze(const std::vector<TFxP> &fxs) {
170 TFxP root = 0;
171 std::vector<TFxP> leafs;
172 std::vector<TFxP> roots;
173 return analyze(fxs, root, roots, leafs);
174 }
175
176 //--------------------------------------------------
177
isaLeaf(TFx * fx) const178 bool TMacroFx::isaLeaf(TFx *fx) const {
179 int count = fx->getInputPortCount();
180 if (count == 0) return true;
181
182 for (int i = 0; i < count; ++i) {
183 TFxPort *port = fx->getInputPort(i);
184 TFx *inputFx = port->getFx();
185 if (inputFx) {
186 if (std::find_if(m_fxs.begin(), m_fxs.end(), MatchesFx(inputFx)) ==
187 m_fxs.end()) {
188 // il nodo di input non appartiene al macroFx
189 return true;
190 }
191 } else {
192 // la porta di input non e' connessa
193 return true;
194 }
195 }
196
197 // tutte le porte di input sono connesse verso nodi appartenenti al macroFx
198 return false;
199 }
200
201 //--------------------------------------------------
202
TMacroFx()203 TMacroFx::TMacroFx() : m_isEditing(false) {}
204
205 //--------------------------------------------------
206
~TMacroFx()207 TMacroFx::~TMacroFx() {}
208
209 //--------------------------------------------------
210
clone(bool recursive) const211 TFx *TMacroFx::clone(bool recursive) const {
212 int n = m_fxs.size();
213 std::vector<TFxP> clones(n);
214 std::map<TFx *, int> table;
215 std::map<TFx *, int>::iterator it;
216 int i, rootIndex = -1;
217 // nodi
218 for (i = 0; i < n; ++i) {
219 TFx *fx = m_fxs[i].getPointer();
220 assert(fx);
221 clones[i] = fx->clone(false);
222 assert(table.count(fx) == 0);
223 table[fx] = i;
224 if (fx == m_root.getPointer()) rootIndex = i;
225 TFx *linkedFx = fx->getLinkedFx();
226 if (linkedFx && table.find(linkedFx) != table.end())
227 clones[i]->linkParams(clones[table[linkedFx]].getPointer());
228 }
229 assert(rootIndex >= 0);
230 // connessioni
231 for (i = 0; i < n; i++) {
232 TFx *fx = m_fxs[i].getPointer();
233 for (int j = 0; j < fx->getInputPortCount(); j++) {
234 TFxPort *port = fx->getInputPort(j);
235 TFx *inputFx = port->getFx();
236 if (!inputFx) continue;
237 it = table.find(inputFx);
238 if (it == table.end()) {
239 // il j-esimo input di fx e' esterno alla macro
240 if (recursive)
241 clones[i]->connect(fx->getInputPortName(j), inputFx->clone(true));
242 } else {
243 // il j-esimo input di fx e' interno alla macro
244 clones[i]->connect(fx->getInputPortName(j),
245 clones[it->second].getPointer());
246 }
247 }
248 }
249
250 // TFx *rootClone =
251 // const_cast<TMacroFx*>(this)->
252 // clone(m_root.getPointer(), recursive, visited, clones);
253
254 TMacroFx *clone = TMacroFx::create(clones);
255 clone->setName(getName());
256 clone->setFxId(getFxId());
257
258 // Copy the index of the passive cache manager.
259 clone->getAttributes()->passiveCacheDataIdx() =
260 getAttributes()->passiveCacheDataIdx();
261
262 assert(clone->getRoot() == clones[rootIndex].getPointer());
263
264 return clone;
265 }
266
267 //--------------------------------------------------
268
doGetBBox(double frame,TRectD & bBox,const TRenderSettings & info)269 bool TMacroFx::doGetBBox(double frame, TRectD &bBox,
270 const TRenderSettings &info) {
271 return m_root->doGetBBox(frame, bBox, info);
272 }
273
274 //--------------------------------------------------
275
doDryCompute(TRectD & rect,double frame,const TRenderSettings & info)276 void TMacroFx::doDryCompute(TRectD &rect, double frame,
277 const TRenderSettings &info) {
278 assert(m_root);
279 m_root->dryCompute(rect, frame, info);
280 }
281
282 //--------------------------------------------------
283
doCompute(TTile & tile,double frame,const TRenderSettings & ri)284 void TMacroFx::doCompute(TTile &tile, double frame, const TRenderSettings &ri) {
285 assert(m_root);
286 m_root->compute(tile, frame, ri);
287 }
288
289 //--------------------------------------------------
290
getTimeRegion() const291 TFxTimeRegion TMacroFx::getTimeRegion() const {
292 return m_root->getTimeRegion();
293 }
294
295 //--------------------------------------------------
296
getPluginId() const297 std::string TMacroFx::getPluginId() const { return "Base"; }
298
299 //--------------------------------------------------
300
setRoot(TFx * root)301 void TMacroFx::setRoot(TFx *root) {
302 m_root = root;
303 // TFx::m_imp->m_outputPort = root->m_imp->m_outputPort;
304 }
305
306 //--------------------------------------------------
307
getRoot() const308 TFx *TMacroFx::getRoot() const { return m_root.getPointer(); }
309
310 //--------------------------------------------------
311
getFxById(const std::wstring & id) const312 TFx *TMacroFx::getFxById(const std::wstring &id) const {
313 int i;
314 for (i = 0; i < (int)m_fxs.size(); i++) {
315 TFx *fx = m_fxs[i].getPointer();
316 if (fx->getFxId() == id) return fx;
317 }
318 return 0;
319 }
320
321 //--------------------------------------------------
322
getFxs() const323 const std::vector<TFxP> &TMacroFx::getFxs() const { return m_fxs; }
324
325 //--------------------------------------------------
326
getMacroFxType() const327 std::string TMacroFx::getMacroFxType() const {
328 std::string name = getFxType() + "(";
329 for (int i = 0; i < (int)m_fxs.size(); i++) {
330 if (i > 0) name += ",";
331 if (TMacroFx *childMacro = dynamic_cast<TMacroFx *>(m_fxs[i].getPointer()))
332 name += childMacro->getMacroFxType();
333 else
334 name += m_fxs[i]->getFxType();
335 }
336 return name + ")";
337 }
338
339 //--------------------------------------------------
340
create(const std::vector<TFxP> & fxs)341 TMacroFx *TMacroFx::create(const std::vector<TFxP> &fxs) {
342 std::vector<TFxP> leafs;
343 std::vector<TFxP> roots;
344 TFxP root = 0;
345
346 std::vector<TFxP> orederedFxs = sortFxs(fxs);
347
348 // verifica che gli effetti selezionati siano idonei ad essere raccolti
349 // in una macro. Ci deve essere un solo nodo terminale
350 // (roots.size()==1, roots[0] == root) e uno o piu' nodi di ingresso
351 // (assert leafs.size()>0)
352 if (!analyze(orederedFxs, root, roots, leafs)) return 0;
353
354 // -----------------------------
355
356 TMacroFx *macroFx = new TMacroFx;
357
358 // tutti i nodi vengono spostati (e non copiati) nella macro stessa
359 std::vector<TFxP>::const_iterator it = orederedFxs.begin();
360 for (; it != orederedFxs.end(); ++it) macroFx->m_fxs.push_back(*it);
361
362 // i nodi di ingresso vengono messi in collegamento con le
363 // porte di ingresso della macro
364 for (int i = 0; i < (int)leafs.size(); i++) {
365 TFxP fx = leafs[i];
366 int k = 0;
367 int count = fx->getInputPortCount();
368 for (; k < count; k++) {
369 TFxPort *port = fx->getInputPort(k);
370 std::string portName = fx->getInputPortName(k);
371 std::string fxId = ::to_string(fx->getFxId());
372 portName +=
373 "_" + std::to_string(macroFx->getInputPortCount()) + "_" + fxId;
374 TFx *portFx = port->getFx();
375 if (portFx) {
376 // se la porta k-esima del nodo di ingresso i-esimo e' collegata
377 // ad un effetto, la porta viene inserita solo se l'effetto non fa
378 // gia' parte della macro
379 if (std::find_if(orederedFxs.begin(), orederedFxs.end(),
380 MatchesFx(portFx)) == orederedFxs.end())
381 macroFx->addInputPort(portName, *port);
382 } else
383 macroFx->addInputPort(portName, *port);
384 }
385 }
386
387 // le porte di uscita di root diventano le porte di uscita della macro
388 int count = root->getOutputConnectionCount();
389 int k = count - 1;
390 for (; k >= 0; --k) {
391 TFxPort *port = root->getOutputConnection(k);
392 port->setFx(macroFx);
393 }
394
395 macroFx->setRoot(root.getPointer());
396
397 // tutti i parametri delle funzioni figlie diventano parametri della macro
398 collectParams(macroFx);
399 return macroFx;
400 }
401
402 //--------------------------------------------------
403
canHandle(const TRenderSettings & info,double frame)404 bool TMacroFx::canHandle(const TRenderSettings &info, double frame) {
405 return m_root->canHandle(info, frame);
406 }
407
408 //--------------------------------------------------
409
getAlias(double frame,const TRenderSettings & info) const410 std::string TMacroFx::getAlias(double frame,
411 const TRenderSettings &info) const {
412 std::string alias = getFxType();
413 alias += "[";
414
415 // alias degli effetti connessi alle porte di input separati da virgole
416 // una porta non connessa da luogo a un alias vuoto (stringa vuota)
417 int i;
418 for (i = 0; i < getInputPortCount(); i++) {
419 TFxPort *port = getInputPort(i);
420 if (port->isConnected()) {
421 TRasterFxP ifx = port->getFx();
422 assert(ifx);
423 alias += ifx->getAlias(frame, info);
424 }
425 alias += ",";
426 }
427
428 // alias dei valori dei parametri dell'effetto al frame dato
429 for (int j = 0; j < (int)m_fxs.size(); j++) {
430 alias += (j == 0) ? "(" : ",(";
431 for (i = 0; i < m_fxs[j]->getParams()->getParamCount(); i++) {
432 if (i > 0) alias += ",";
433 TParam *param = m_fxs[j]->getParams()->getParam(i);
434 alias += param->getName() + "=" + param->getValueAlias(frame, 2);
435 }
436 alias += ")";
437 }
438
439 alias += "]";
440 return alias;
441 }
442
443 //--------------------------------------------------
444
compatibilityTranslatePort(int major,int minor,std::string & portName)445 void TMacroFx::compatibilityTranslatePort(int major, int minor,
446 std::string &portName) {
447 // Reroute translation to the actual fx associated to the port
448 const std::string &fxId =
449 portName.substr(portName.find_last_of('_') + 1, std::string::npos);
450
451 if (TFx *fx = getFxById(::to_wstring(fxId))) {
452 size_t opnEnd = portName.find_first_of('_');
453
454 std::string originalPortName = portName.substr(0, opnEnd);
455 fx->compatibilityTranslatePort(major, minor, originalPortName);
456
457 portName.replace(0, opnEnd, originalPortName);
458 }
459
460 // Seems that at a certain point, the port name got extended...
461 if (VersionNumber(major, minor) == VersionNumber(1, 16)) {
462 for (int i = 0; i < getInputPortCount(); ++i) {
463 const std::string &name = getInputPortName(i);
464 if (name.find(portName) != std::string::npos) {
465 portName = name;
466 break;
467 }
468 }
469 }
470 }
471
472 //--------------------------------------------------
473
loadData(TIStream & is)474 void TMacroFx::loadData(TIStream &is) {
475 VersionNumber tnzVersion = is.getVersion();
476 std::string tagName;
477 while (is.openChild(tagName)) {
478 if (tagName == "root") {
479 // set the flag here in order to prevent the leaf macro fx in the tree
480 // to try to link this fx before finish loading
481 m_isLoading = true;
482 TPersist *p = 0;
483 is >> p;
484 m_root = dynamic_cast<TFx *>(p);
485 // release the flag
486 m_isLoading = false;
487 } else if (tagName == "nodes") {
488 while (!is.eos()) {
489 TPersist *p = 0;
490 is >> p;
491
492 // NOTE: In current implementation p is sharedly owned by is - it's
493 // automatically
494 // released upon stream destruction if the below assignment fails
495
496 if (TFx *fx = dynamic_cast<TFx *>(p)) {
497 m_fxs.push_back(fx);
498 }
499 }
500 // collecting params just after loading nodes since they may need on
501 // loading "super" tag in case it is linked with another macro fx
502 collectParams(this);
503 // link parameters if there is a waiting fx for linking with this
504 if (m_waitingLinkFx) {
505 m_waitingLinkFx->linkParams(this);
506 m_waitingLinkFx = nullptr;
507 }
508 } else if (tagName == "ports") {
509 int i = 0;
510 while (is.matchTag(tagName)) {
511 if (tagName == "port") {
512 std::string name = is.getTagAttribute("name");
513 if (tnzVersion < VersionNumber(1, 16) && name != "") {
514 TRasterFxPort *port = new TRasterFxPort();
515 addInputPort(name, *port);
516 } else {
517 name = is.getTagAttribute("name_inFx");
518 if (tnzVersion < VersionNumber(1, 17) &&
519 tnzVersion != VersionNumber(0, 0))
520 name.insert(name.find("_"), "_" + std::to_string(i));
521
522 compatibilityTranslatePort(tnzVersion.first, tnzVersion.second,
523 name);
524
525 std::string inPortName = name;
526 inPortName.erase(inPortName.find("_"), inPortName.size() - 1);
527
528 std::string inFxId = name;
529 inFxId.erase(0, inFxId.find_last_of("_") + 1);
530
531 for (int i = 0; i < (int)m_fxs.size(); i++) {
532 std::wstring fxId = m_fxs[i]->getFxId();
533 if (fxId == ::to_wstring(inFxId)) {
534 if (TFxPort *port = m_fxs[i]->getInputPort(inPortName))
535 addInputPort(name, *port);
536 }
537 }
538 }
539 i++;
540 } else
541 throw TException("unexpected tag " + tagName);
542 }
543 } else if (tagName == "super") {
544 TRasterFx::loadData(is);
545 } else
546 throw TException("unexpected tag " + tagName);
547 is.closeChild();
548 }
549 }
550
551 //--------------------------------------------------
552
saveData(TOStream & os)553 void TMacroFx::saveData(TOStream &os) {
554 int i;
555 os.openChild("root");
556 TPersist *p = m_root.getPointer();
557 os << p;
558 os.closeChild();
559 os.openChild("nodes");
560 for (i = 0; i < (int)m_fxs.size(); i++) {
561 TFxP fx = m_fxs[i];
562 TPersist *p = fx.getPointer();
563 os << p;
564 }
565 os.closeChild();
566 os.openChild("ports");
567 for (i = 0; i < getInputPortCount(); i++) {
568 std::string portName = getInputPortName(i);
569 std::map<std::string, std::string> attr;
570 attr["name_inFx"] = portName;
571 os.openCloseChild("port", attr);
572 }
573 os.closeChild();
574 os.openChild("super");
575 TRasterFx::saveData(os);
576 os.closeChild();
577 }
578
579 //--------------------------------------------------
580
linkParams(TFx * src)581 void TMacroFx::linkParams(TFx *src) {
582 // in case the src fx is not yet loaded
583 // (i.e. we are in loading the src fx tree),
584 // wait linking the parameters until loading src is completed
585 TMacroFx *srcMacroFx = dynamic_cast<TMacroFx *>(src);
586 if (srcMacroFx && srcMacroFx->isLoading()) {
587 srcMacroFx->setWaitingLinkFx(this);
588 return;
589 }
590
591 TFx::linkParams(src);
592 }
593
594 //--------------------------------------------------
595 FX_IDENTIFIER(TMacroFx, "macroFx")
596 // FX_IDENTIFIER_IS_HIDDEN(TMacroFx, "macroFx")
597