3bfa549e8b
- using std::string; - using std::wstring; - using std::ostream; - using std::istream; - using std::iostream; - using std::ostrstream; - using std::istrstream; - using std::fstream;
390 lines
10 KiB
C++
390 lines
10 KiB
C++
|
|
|
|
#include "toonz/fxdag.h"
|
|
|
|
// TnzLib includes
|
|
#include "toonz/tcolumnfxset.h"
|
|
#include "toonz/tcolumnfx.h"
|
|
#include "tw/stringtable.h"
|
|
|
|
// TnzBase includes
|
|
#include "tmacrofx.h"
|
|
#include "tfxattributes.h"
|
|
|
|
// TnzCore includes
|
|
#include "tstream.h"
|
|
|
|
// tcg includes
|
|
#include "tcg/function_types.h"
|
|
|
|
// STD includes
|
|
//#include <cwctypes>
|
|
|
|
//===================================================================
|
|
|
|
FxDag::FxDag()
|
|
: m_internalFxs(new TFxSet()), m_terminalFxs(new TFxSet()), m_groupIdCount(0), m_dagGridDimension(eSmall)
|
|
{
|
|
TXsheetFx *xsheetFx = new TXsheetFx;
|
|
xsheetFx->setFxDag(this);
|
|
m_xsheetFx = xsheetFx;
|
|
m_xsheetFx->addRef();
|
|
m_xsheetFx->setNewIdentifier();
|
|
addOutputFx();
|
|
m_outputFxs[0]->getInputPort(0)->setFx(m_xsheetFx);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
FxDag::~FxDag()
|
|
{
|
|
delete m_internalFxs;
|
|
delete m_terminalFxs;
|
|
m_xsheetFx->release();
|
|
int i;
|
|
for (i = 0; i < (int)m_outputFxs.size(); i++)
|
|
m_outputFxs[i]->release();
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
TOutputFx *FxDag::addOutputFx(TOutputFx *outputFx)
|
|
{
|
|
if (!outputFx)
|
|
outputFx = new TOutputFx();
|
|
outputFx->addRef();
|
|
m_xsheetFx->setNewIdentifier();
|
|
assert(outputFx->getInputPortCount() == 1);
|
|
m_outputFxs.push_back(outputFx);
|
|
return outputFx;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::removeOutputFx(TOutputFx *fx)
|
|
{
|
|
assert(fx);
|
|
if (m_outputFxs.size() == 1)
|
|
return;
|
|
if (std::find(m_outputFxs.begin(), m_outputFxs.end(), fx) == m_outputFxs.end())
|
|
return;
|
|
m_outputFxs.erase(
|
|
std::remove(m_outputFxs.begin(), m_outputFxs.end(), fx),
|
|
m_outputFxs.end());
|
|
fx->release();
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
TFxSet *FxDag::getInternalFxs() const
|
|
{
|
|
return m_internalFxs;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::setCurrentOutputFx(TOutputFx *fx)
|
|
{
|
|
std::vector<TOutputFx *>::iterator it;
|
|
it = std::find(m_outputFxs.begin(), m_outputFxs.end(), fx);
|
|
if (it == m_outputFxs.end())
|
|
return;
|
|
if (it == m_outputFxs.begin())
|
|
return;
|
|
std::swap(*it, *m_outputFxs.begin());
|
|
}
|
|
|
|
TOutputFx *FxDag::getCurrentOutputFx() const
|
|
{
|
|
assert(!m_outputFxs.empty());
|
|
return m_outputFxs[0];
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
bool FxDag::checkLoop(TFx *inputFx, TFx *fx)
|
|
{
|
|
if (inputFx == fx)
|
|
return true;
|
|
if (dynamic_cast<TXsheetFx *>(inputFx)) {
|
|
TFxSet *terminals = getTerminalFxs();
|
|
for (int i = 0; i < terminals->getFxCount(); i++) {
|
|
TFx *tfx = terminals->getFx(i);
|
|
if (tfx && checkLoop(tfx, fx))
|
|
return true;
|
|
}
|
|
} else {
|
|
if (TZeraryColumnFx *zerary = dynamic_cast<TZeraryColumnFx *>(inputFx))
|
|
inputFx = zerary->getZeraryFx();
|
|
for (int i = 0; i < inputFx->getInputPortCount(); i++) {
|
|
TFx *ifx = inputFx->getInputPort(i)->getFx();
|
|
if (ifx && checkLoop(ifx, fx))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
TFxSet *FxDag::getTerminalFxs() const
|
|
{
|
|
return m_terminalFxs;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::addToXsheet(TFx *fx)
|
|
{
|
|
m_terminalFxs->addFx(fx);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::removeFromXsheet(TFx *fx)
|
|
{
|
|
m_terminalFxs->removeFx(fx);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
struct NotAlnum {
|
|
bool operator()(wint_t val) const { return !iswalnum(val); }
|
|
};
|
|
} // namespace
|
|
|
|
void FxDag::assignUniqueId(TFx *fx)
|
|
{
|
|
struct locals {
|
|
static void eraseNonAlnums(std::wstring &str)
|
|
{
|
|
str.erase(std::remove_if(str.begin(), str.end(), NotAlnum()), str.end());
|
|
}
|
|
}; // locals
|
|
|
|
std::string type = fx->getFxType();
|
|
int count = ++m_typeTable[type];
|
|
|
|
fx->getAttributes()->setId(count);
|
|
|
|
std::wstring name = TStringTable::translate(type);
|
|
locals::eraseNonAlnums(name); // fx ids are used as XML tag names - thus, we'll restrict
|
|
// the char set to alnums. Specifically, '/' must be ruled out.
|
|
// E.g.: "Erode/Dilate 1" must become "ErodeDilate1"
|
|
name = name + QString::number(count).rightJustified(2, '0').toStdWString();
|
|
|
|
if (fx->getName() == L"")
|
|
fx->setName(name);
|
|
fx->setFxId(name);
|
|
m_idTable[toLower(name)] = fx;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
TFx *FxDag::getFxById(std::wstring id) const
|
|
{
|
|
std::map<std::wstring, TFx *>::const_iterator it = m_idTable.find(id);
|
|
if (it == m_idTable.end())
|
|
return 0;
|
|
else
|
|
return it->second;
|
|
}
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::updateFxTypeTable(TFx *fx, int value)
|
|
{
|
|
std::string type = fx->getFxType();
|
|
m_typeTable[type] = value;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::updateFxIdTable(TFx *fx)
|
|
{
|
|
m_idTable[toLower(fx->getFxId())] = fx;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
int FxDag::getFxTypeCount(TFx *fx)
|
|
{
|
|
std::string type = fx->getFxType();
|
|
std::map<std::string, int>::iterator it = m_typeTable.find(type);
|
|
if (it == m_typeTable.end())
|
|
return 0;
|
|
return it->second;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::getFxs(std::vector<TFx *> &fxs) const
|
|
{
|
|
std::set<TFx *> fxSet;
|
|
getInternalFxs()->getFxs(fxSet);
|
|
fxs.insert(fxs.end(), fxSet.begin(), fxSet.end());
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
bool FxDag::isRendered(TFx *fx) const
|
|
{
|
|
if (m_terminalFxs->containsFx(fx))
|
|
return true;
|
|
if (dynamic_cast<TOutputFx *>(fx))
|
|
return true;
|
|
int i;
|
|
for (i = 0; i < fx->getOutputConnectionCount(); i++) {
|
|
TFx *outFx = fx->getOutputConnection(i)->getOwnerFx();
|
|
if (outFx && isRendered(outFx))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
bool FxDag::isControl(TFx *fx) const
|
|
{
|
|
if (m_terminalFxs->containsFx(fx))
|
|
return false;
|
|
if (dynamic_cast<TOutputFx *>(fx))
|
|
return false;
|
|
int i;
|
|
for (i = 0; i < fx->getOutputConnectionCount(); i++) {
|
|
TFxPort *port = fx->getOutputConnection(i);
|
|
TFx *outFx = port->getOwnerFx();
|
|
if (outFx) {
|
|
if (outFx->getInputPort(0) != port)
|
|
return true;
|
|
if (isControl(outFx))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
namespace
|
|
{
|
|
TFx *search(const std::map<TFx *, TFx *> &table, TFx *fx)
|
|
{
|
|
std::map<TFx *, TFx *>::const_iterator it = table.find(fx);
|
|
return it == table.end() ? 0 : it->second;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::saveData(TOStream &os, int occupiedColumnCount)
|
|
{
|
|
if (getInternalFxs()->getFxCount() > 0) {
|
|
os.openChild("internal");
|
|
getInternalFxs()->saveData(os, occupiedColumnCount);
|
|
os.closeChild();
|
|
}
|
|
if (getTerminalFxs()->getFxCount() > 0) {
|
|
os.openChild("terminal");
|
|
getTerminalFxs()->saveData(os, occupiedColumnCount);
|
|
os.closeChild();
|
|
}
|
|
os.child("xsheet") << m_xsheetFx;
|
|
int k;
|
|
for (k = 0; k < (int)m_outputFxs.size(); k++)
|
|
os.child("output") << m_outputFxs[k];
|
|
os.child("grid_dimension") << (int)m_dagGridDimension;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
void FxDag::loadData(TIStream &is)
|
|
{
|
|
VersionNumber tnzVersion = is.getVersion();
|
|
int k;
|
|
for (k = 0; k < (int)m_outputFxs.size(); k++)
|
|
m_outputFxs[k]->release();
|
|
m_outputFxs.clear();
|
|
std::string tagName;
|
|
while (is.openChild(tagName)) {
|
|
if (tagName == "terminal") {
|
|
TFxSet *fxSet = getTerminalFxs();
|
|
fxSet->loadData(is);
|
|
int i;
|
|
for (i = 0; i < fxSet->getFxCount(); i++) {
|
|
TFx *fx = fxSet->getFx(i);
|
|
if (fx->getAttributes()->isGrouped() && m_groupIdCount < fx->getAttributes()->getGroupId())
|
|
m_groupIdCount = fx->getAttributes()->getGroupId();
|
|
if (TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx))
|
|
fx = zfx->getZeraryFx();
|
|
if (tnzVersion < VersionNumber(1, 16)) {
|
|
std::wstring app = fx->getName();
|
|
assignUniqueId(fx);
|
|
fx->setName(app);
|
|
continue;
|
|
}
|
|
int fxTypeCount = getFxTypeCount(fx);
|
|
int maxFxTypeId = tmax(fxTypeCount, fx->getAttributes()->getId());
|
|
updateFxTypeTable(fx, maxFxTypeId);
|
|
TMacroFx *macroFx = dynamic_cast<TMacroFx *>(fx);
|
|
if (macroFx) {
|
|
std::vector<TFxP> fxs = macroFx->getFxs();
|
|
int j;
|
|
for (j = 0; j < (int)fxs.size(); j++) {
|
|
TFxP inMacroFx = fxs[j];
|
|
fxTypeCount = getFxTypeCount(inMacroFx.getPointer());
|
|
maxFxTypeId = tmax(fxTypeCount, inMacroFx->getAttributes()->getId());
|
|
updateFxTypeTable(inMacroFx.getPointer(), maxFxTypeId);
|
|
m_idTable[toLower(inMacroFx->getFxId())] = inMacroFx.getPointer();
|
|
}
|
|
}
|
|
}
|
|
} else if (tagName == "internal") {
|
|
TFxSet *fxSet = getInternalFxs();
|
|
fxSet->loadData(is);
|
|
int i;
|
|
for (i = 0; i < fxSet->getFxCount(); i++) {
|
|
TFx *fx = fxSet->getFx(i);
|
|
if (fx->getAttributes()->isGrouped() && m_groupIdCount < fx->getAttributes()->getGroupId())
|
|
m_groupIdCount = fx->getAttributes()->getGroupId();
|
|
if (TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx))
|
|
fx = zfx->getZeraryFx();
|
|
if (tnzVersion < VersionNumber(1, 16)) {
|
|
std::wstring app = fx->getName();
|
|
assignUniqueId(fx);
|
|
fx->setName(app);
|
|
continue;
|
|
}
|
|
int fxTypeCount = getFxTypeCount(fx);
|
|
int maxFxTypeId = tmax(fxTypeCount, fx->getAttributes()->getId());
|
|
updateFxTypeTable(fx, maxFxTypeId);
|
|
m_idTable[toLower(fx->getFxId())] = fx;
|
|
}
|
|
} else if (tagName == "xsheet" || tagName == "output") {
|
|
TPersist *p = 0;
|
|
is >> p;
|
|
TFx *fx = dynamic_cast<TFx *>(p);
|
|
if (!fx)
|
|
throw TException("FxDag. unexpeced Fx");
|
|
fx->addRef();
|
|
fx->setNewIdentifier();
|
|
if (tagName == "xsheet") {
|
|
m_xsheetFx->release();
|
|
m_xsheetFx = fx;
|
|
|
|
TXsheetFx *xsheetFx = dynamic_cast<TXsheetFx *>(fx);
|
|
if (xsheetFx)
|
|
xsheetFx->setFxDag(this);
|
|
} else {
|
|
TOutputFx *outputFx = dynamic_cast<TOutputFx *>(fx);
|
|
if (outputFx)
|
|
m_outputFxs.push_back(outputFx);
|
|
}
|
|
} else if (tagName == "grid_dimension") {
|
|
is >> m_dagGridDimension;
|
|
} else
|
|
throw TException("FxDag. unexpeced tag: " + tagName);
|
|
is.closeChild();
|
|
}
|
|
}
|