| |
| |
| #include "tmacrofx.h" |
| |
| |
| #include "tparamcontainer.h" |
| #include "tfxattributes.h" |
| |
| |
| #include "tstream.h" |
| |
| |
| |
| namespace { |
| |
| class MatchesFx { |
| public: |
| MatchesFx(const TFxP &fx) : m_fx(fx) {} |
| |
| bool operator()(const TFxP &fx) { |
| return m_fx.getPointer() == fx.getPointer(); |
| } |
| |
| TFxP m_fx; |
| }; |
| |
| |
| |
| void pushParents(const TFxP &root, std::vector<TFxP> &fxs, |
| const std::vector<TFxP> &selectedFxs) { |
| int i, count = root->getInputPortCount(); |
| if (count == 0) { |
| std::vector<TFxP>::const_iterator found = |
| std::find_if(fxs.begin(), fxs.end(), MatchesFx(root)); |
| if (found == fxs.end()) fxs.push_back(root); |
| return; |
| } |
| for (i = 0; i < count; i++) { |
| TFxP inutFx = root->getInputPort(i)->getFx(); |
| std::vector<TFxP>::const_iterator found = |
| std::find_if(selectedFxs.begin(), selectedFxs.end(), MatchesFx(inutFx)); |
| if (found != selectedFxs.end()) pushParents(inutFx, fxs, selectedFxs); |
| } |
| std::vector<TFxP>::const_iterator found = |
| std::find_if(fxs.begin(), fxs.end(), MatchesFx(root)); |
| if (found == fxs.end()) fxs.push_back(root); |
| } |
| |
| |
| |
| std::vector<TFxP> sortFxs(const std::vector<TFxP> &fxs) { |
| std::vector<TFxP> app; |
| std::vector<TFxP> roots; |
| |
| int i; |
| for (i = 0; i < (int)fxs.size(); i++) { |
| TFxP fx = fxs[i]; |
| int j, count = (int)fx->getOutputConnectionCount(); |
| if (count == 0) { |
| roots.push_back(fx); |
| continue; |
| } |
| for (j = 0; j < count; j++) { |
| TFxP connectedFx = fx->getOutputConnection(j)->getOwnerFx(); |
| std::vector<TFxP>::const_iterator found = |
| std::find_if(fxs.begin(), fxs.end(), MatchesFx(connectedFx)); |
| if (found == fxs.end()) { |
| roots.push_back(fx); |
| break; |
| } |
| } |
| } |
| for (i = 0; i < (int)roots.size(); i++) pushParents(roots[i], app, fxs); |
| assert(fxs.size() == app.size()); |
| return app; |
| } |
| |
| |
| |
| |
| void collectParams(TMacroFx *macroFx) { |
| int k; |
| for (k = 0; k < (int)macroFx->m_fxs.size(); k++) { |
| TFxP fx = macroFx->m_fxs[k]; |
| int j; |
| for (j = 0; j < fx->getParams()->getParamCount(); j++) |
| macroFx->getParams()->add(fx->getParams()->getParamVar(j)->clone()); |
| } |
| } |
| |
| } |
| |
| |
| |
| bool TMacroFx::analyze(const std::vector<TFxP> &fxs, TFxP &root, |
| std::vector<TFxP> &roots, std::vector<TFxP> &leafs) { |
| if (fxs.size() == 1) |
| return false; |
| else { |
| leafs.clear(); |
| roots.clear(); |
| std::vector<TFxP>::const_iterator it = fxs.begin(); |
| for (; it != fxs.end(); ++it) { |
| TFxP fx = *it; |
| int inputInternalConnection = 0; |
| int inputExternalConnection = 0; |
| int outputInternalConnection = 0; |
| int outputExternalConnection = 0; |
| |
| int i; |
| |
| |
| |
| int inputPortCount = fx->getInputPortCount(); |
| for (i = 0; i < inputPortCount; ++i) { |
| TFxPort *inputPort = fx->getInputPort(i); |
| TFx *inputPortFx = inputPort->getFx(); |
| if (inputPortFx) { |
| if (std::find_if(fxs.begin(), fxs.end(), MatchesFx(inputPortFx)) != |
| fxs.end()) |
| ++inputInternalConnection; |
| else |
| ++inputExternalConnection; |
| } |
| } |
| |
| |
| |
| int outputPortCount = fx->getOutputConnectionCount(); |
| for (i = 0; i < outputPortCount; ++i) { |
| TFxPort *outputPort = fx->getOutputConnection(i); |
| TFx *outputFx = outputPort->getOwnerFx(); |
| if (outputFx) { |
| if (std::find_if(fxs.begin(), fxs.end(), MatchesFx(outputFx)) != |
| fxs.end()) |
| ++outputInternalConnection; |
| else |
| ++outputExternalConnection; |
| } |
| } |
| |
| |
| if ((outputExternalConnection > 0) || |
| (outputExternalConnection == 0 && outputInternalConnection == 0)) { |
| root = fx; |
| roots.push_back(fx); |
| } |
| |
| |
| if (inputExternalConnection > 0 || fx->getInputPortCount() == 0 || |
| (inputExternalConnection == 0 && |
| inputInternalConnection < fx->getInputPortCount())) { |
| leafs.push_back(fx); |
| } |
| } |
| |
| if (roots.size() != 1) |
| return false; |
| else { |
| if (leafs.size() == 0) return false; |
| } |
| |
| return true; |
| } |
| } |
| |
| |
| |
| bool TMacroFx::analyze(const std::vector<TFxP> &fxs) { |
| TFxP root = 0; |
| std::vector<TFxP> leafs; |
| std::vector<TFxP> roots; |
| return analyze(fxs, root, roots, leafs); |
| } |
| |
| |
| |
| bool TMacroFx::isaLeaf(TFx *fx) const { |
| int count = fx->getInputPortCount(); |
| if (count == 0) return true; |
| |
| for (int i = 0; i < count; ++i) { |
| TFxPort *port = fx->getInputPort(i); |
| TFx *inputFx = port->getFx(); |
| if (inputFx) { |
| if (std::find_if(m_fxs.begin(), m_fxs.end(), MatchesFx(inputFx)) == |
| m_fxs.end()) { |
| |
| return true; |
| } |
| } else { |
| |
| return true; |
| } |
| } |
| |
| |
| return false; |
| } |
| |
| |
| |
| TMacroFx::TMacroFx() : m_isEditing(false) {} |
| |
| |
| |
| TMacroFx::~TMacroFx() {} |
| |
| |
| |
| TFx *TMacroFx::clone(bool recursive) const { |
| int n = m_fxs.size(); |
| std::vector<TFxP> clones(n); |
| std::map<TFx *, int> table; |
| std::map<TFx *, int>::iterator it; |
| int i, rootIndex = -1; |
| |
| for (i = 0; i < n; ++i) { |
| TFx *fx = m_fxs[i].getPointer(); |
| assert(fx); |
| clones[i] = fx->clone(false); |
| assert(table.count(fx) == 0); |
| table[fx] = i; |
| if (fx == m_root.getPointer()) rootIndex = i; |
| TFx *linkedFx = fx->getLinkedFx(); |
| if (linkedFx && table.find(linkedFx) != table.end()) |
| clones[i]->linkParams(clones[table[linkedFx]].getPointer()); |
| } |
| assert(rootIndex >= 0); |
| |
| for (i = 0; i < n; i++) { |
| TFx *fx = m_fxs[i].getPointer(); |
| for (int j = 0; j < fx->getInputPortCount(); j++) { |
| TFxPort *port = fx->getInputPort(j); |
| TFx *inputFx = port->getFx(); |
| if (!inputFx) continue; |
| it = table.find(inputFx); |
| if (it == table.end()) { |
| |
| if (recursive) |
| clones[i]->connect(fx->getInputPortName(j), inputFx->clone(true)); |
| } else { |
| |
| clones[i]->connect(fx->getInputPortName(j), |
| clones[it->second].getPointer()); |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| TMacroFx *clone = TMacroFx::create(clones); |
| clone->setName(getName()); |
| clone->setFxId(getFxId()); |
| |
| |
| clone->getAttributes()->passiveCacheDataIdx() = |
| getAttributes()->passiveCacheDataIdx(); |
| |
| assert(clone->getRoot() == clones[rootIndex].getPointer()); |
| |
| return clone; |
| } |
| |
| |
| |
| bool TMacroFx::doGetBBox(double frame, TRectD &bBox, |
| const TRenderSettings &info) { |
| return m_root->doGetBBox(frame, bBox, info); |
| } |
| |
| |
| |
| void TMacroFx::doDryCompute(TRectD &rect, double frame, |
| const TRenderSettings &info) { |
| assert(m_root); |
| m_root->dryCompute(rect, frame, info); |
| } |
| |
| |
| |
| void TMacroFx::doCompute(TTile &tile, double frame, const TRenderSettings &ri) { |
| assert(m_root); |
| m_root->compute(tile, frame, ri); |
| } |
| |
| |
| |
| TFxTimeRegion TMacroFx::getTimeRegion() const { |
| return m_root->getTimeRegion(); |
| } |
| |
| |
| |
| std::string TMacroFx::getPluginId() const { return "Base"; } |
| |
| |
| |
| void TMacroFx::setRoot(TFx *root) { |
| m_root = root; |
| |
| } |
| |
| |
| |
| TFx *TMacroFx::getRoot() const { return m_root.getPointer(); } |
| |
| |
| |
| TFx *TMacroFx::getFxById(const std::wstring &id) const { |
| int i; |
| for (i = 0; i < (int)m_fxs.size(); i++) { |
| TFx *fx = m_fxs[i].getPointer(); |
| if (fx->getFxId() == id) return fx; |
| } |
| return 0; |
| } |
| |
| |
| |
| const std::vector<TFxP> &TMacroFx::getFxs() const { return m_fxs; } |
| |
| |
| |
| std::string TMacroFx::getMacroFxType() const { |
| std::string name = getFxType() + "("; |
| for (int i = 0; i < (int)m_fxs.size(); i++) { |
| if (i > 0) name += ","; |
| if (TMacroFx *childMacro = dynamic_cast<TMacroFx *>(m_fxs[i].getPointer())) |
| name += childMacro->getMacroFxType(); |
| else |
| name += m_fxs[i]->getFxType(); |
| } |
| return name + ")"; |
| } |
| |
| |
| |
| TMacroFx *TMacroFx::create(const std::vector<TFxP> &fxs) { |
| std::vector<TFxP> leafs; |
| std::vector<TFxP> roots; |
| TFxP root = 0; |
| |
| std::vector<TFxP> orederedFxs = sortFxs(fxs); |
| |
| |
| |
| |
| |
| if (!analyze(orederedFxs, root, roots, leafs)) return 0; |
| |
| |
| |
| TMacroFx *macroFx = new TMacroFx; |
| |
| |
| std::vector<TFxP>::const_iterator it = orederedFxs.begin(); |
| for (; it != orederedFxs.end(); ++it) macroFx->m_fxs.push_back(*it); |
| |
| |
| |
| for (int i = 0; i < (int)leafs.size(); i++) { |
| TFxP fx = leafs[i]; |
| int k = 0; |
| int count = fx->getInputPortCount(); |
| for (; k < count; k++) { |
| TFxPort *port = fx->getInputPort(k); |
| std::string portName = fx->getInputPortName(k); |
| std::string fxId = ::to_string(fx->getFxId()); |
| portName += |
| "_" + std::to_string(macroFx->getInputPortCount()) + "_" + fxId; |
| TFx *portFx = port->getFx(); |
| if (portFx) { |
| |
| |
| |
| if (std::find_if(orederedFxs.begin(), orederedFxs.end(), |
| MatchesFx(portFx)) == orederedFxs.end()) |
| macroFx->addInputPort(portName, *port); |
| } else |
| macroFx->addInputPort(portName, *port); |
| } |
| } |
| |
| |
| int count = root->getOutputConnectionCount(); |
| int k = count - 1; |
| for (; k >= 0; --k) { |
| TFxPort *port = root->getOutputConnection(k); |
| port->setFx(macroFx); |
| } |
| |
| macroFx->setRoot(root.getPointer()); |
| |
| |
| collectParams(macroFx); |
| return macroFx; |
| } |
| |
| |
| |
| bool TMacroFx::canHandle(const TRenderSettings &info, double frame) { |
| return m_root->canHandle(info, frame); |
| } |
| |
| |
| |
| std::string TMacroFx::getAlias(double frame, |
| const TRenderSettings &info) const { |
| std::string alias = getFxType(); |
| alias += "["; |
| |
| |
| |
| int i; |
| for (i = 0; i < getInputPortCount(); i++) { |
| TFxPort *port = getInputPort(i); |
| if (port->isConnected()) { |
| TRasterFxP ifx = port->getFx(); |
| assert(ifx); |
| alias += ifx->getAlias(frame, info); |
| } |
| alias += ","; |
| } |
| |
| |
| for (int j = 0; j < (int)m_fxs.size(); j++) { |
| alias += (j == 0) ? "(" : ",("; |
| for (i = 0; i < m_fxs[j]->getParams()->getParamCount(); i++) { |
| if (i > 0) alias += ","; |
| TParam *param = m_fxs[j]->getParams()->getParam(i); |
| alias += param->getName() + "=" + param->getValueAlias(frame, 2); |
| } |
| alias += ")"; |
| } |
| |
| alias += "]"; |
| return alias; |
| } |
| |
| |
| |
| void TMacroFx::compatibilityTranslatePort(int major, int minor, |
| std::string &portName) { |
| |
| const std::string &fxId = |
| portName.substr(portName.find_last_of('_') + 1, std::string::npos); |
| |
| if (TFx *fx = getFxById(::to_wstring(fxId))) { |
| size_t opnEnd = portName.find_first_of('_'); |
| |
| std::string originalPortName = portName.substr(0, opnEnd); |
| fx->compatibilityTranslatePort(major, minor, originalPortName); |
| |
| portName.replace(0, opnEnd, originalPortName); |
| } |
| |
| |
| if (VersionNumber(major, minor) == VersionNumber(1, 16)) { |
| for (int i = 0; i < getInputPortCount(); ++i) { |
| const std::string &name = getInputPortName(i); |
| if (name.find(portName) != std::string::npos) { |
| portName = name; |
| break; |
| } |
| } |
| } |
| } |
| |
| |
| |
| void TMacroFx::loadData(TIStream &is) { |
| VersionNumber tnzVersion = is.getVersion(); |
| std::string tagName; |
| while (is.openChild(tagName)) { |
| if (tagName == "root") { |
| TPersist *p = 0; |
| is >> p; |
| m_root = dynamic_cast<TFx *>(p); |
| } else if (tagName == "nodes") { |
| while (!is.eos()) { |
| TPersist *p = 0; |
| is >> p; |
| |
| |
| |
| |
| |
| if (TFx *fx = dynamic_cast<TFx *>(p)) { |
| m_fxs.push_back(fx); |
| } |
| } |
| } else if (tagName == "ports") { |
| int i = 0; |
| while (is.matchTag(tagName)) { |
| if (tagName == "port") { |
| std::string name = is.getTagAttribute("name"); |
| if (tnzVersion < VersionNumber(1, 16) && name != "") { |
| TRasterFxPort *port = new TRasterFxPort(); |
| addInputPort(name, *port); |
| } else { |
| name = is.getTagAttribute("name_inFx"); |
| if (tnzVersion < VersionNumber(1, 17) && |
| tnzVersion != VersionNumber(0, 0)) |
| name.insert(name.find("_"), "_" + std::to_string(i)); |
| |
| compatibilityTranslatePort(tnzVersion.first, tnzVersion.second, |
| name); |
| |
| std::string inPortName = name; |
| inPortName.erase(inPortName.find("_"), inPortName.size() - 1); |
| |
| std::string inFxId = name; |
| inFxId.erase(0, inFxId.find_last_of("_") + 1); |
| |
| for (int i = 0; i < (int)m_fxs.size(); i++) { |
| std::wstring fxId = m_fxs[i]->getFxId(); |
| if (fxId == ::to_wstring(inFxId)) { |
| if (TFxPort *port = m_fxs[i]->getInputPort(inPortName)) |
| addInputPort(name, *port); |
| } |
| } |
| } |
| i++; |
| } else |
| throw TException("unexpected tag " + tagName); |
| } |
| } else if (tagName == "super") { |
| TRasterFx::loadData(is); |
| } else |
| throw TException("unexpected tag " + tagName); |
| is.closeChild(); |
| } |
| collectParams(this); |
| } |
| |
| |
| |
| void TMacroFx::saveData(TOStream &os) { |
| int i; |
| os.openChild("root"); |
| TPersist *p = m_root.getPointer(); |
| os << p; |
| os.closeChild(); |
| os.openChild("nodes"); |
| for (i = 0; i < (int)m_fxs.size(); i++) { |
| TFxP fx = m_fxs[i]; |
| TPersist *p = fx.getPointer(); |
| os << p; |
| } |
| os.closeChild(); |
| os.openChild("ports"); |
| for (i = 0; i < getInputPortCount(); i++) { |
| std::string portName = getInputPortName(i); |
| std::map<std::string, std::string> attr; |
| attr["name_inFx"] = portName; |
| os.openCloseChild("port", attr); |
| } |
| os.closeChild(); |
| os.openChild("super"); |
| TRasterFx::saveData(os); |
| os.closeChild(); |
| } |
| |
| |
| FX_IDENTIFIER(TMacroFx, "macroFx") |
| |
| |