2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
|
|
|
|
// TnzCore includes
|
|
|
|
#include "tconvert.h"
|
|
|
|
|
|
|
|
// TnzBase includes
|
|
|
|
#include "tdoubleparam.h"
|
|
|
|
#include "tparamcontainer.h"
|
|
|
|
#include "tparamset.h"
|
|
|
|
#include "texpression.h"
|
|
|
|
#include "tparser.h"
|
|
|
|
#include "tfx.h"
|
2020-04-17 19:02:53 +12:00
|
|
|
#include "tzeraryfx.h"
|
|
|
|
#include "tcolumnset.h"
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
#include "tw/stringtable.h"
|
|
|
|
#include "tunit.h"
|
|
|
|
|
|
|
|
// TnzLib includes
|
|
|
|
#include "toonz/txsheet.h"
|
|
|
|
#include "toonz/txshcell.h"
|
|
|
|
#include "toonz/tstageobjectid.h"
|
|
|
|
#include "toonz/tstageobject.h"
|
|
|
|
#include "toonz/fxdag.h"
|
2020-04-17 19:02:53 +12:00
|
|
|
#include "toonz/tstageobjecttree.h"
|
|
|
|
#include "toonz/tcolumnfxset.h"
|
|
|
|
#include "toonz/tcolumnfx.h"
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
// Boost includes
|
|
|
|
#include "boost/noncopyable.hpp"
|
|
|
|
|
|
|
|
// Qt includes
|
|
|
|
#include <QString>
|
|
|
|
|
|
|
|
#include "toonz/txsheetexpr.h"
|
|
|
|
|
2016-04-17 17:56:16 +12:00
|
|
|
#include <memory>
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
using namespace TSyntax;
|
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
// Local namespace stuff
|
|
|
|
//******************************************************************************
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
namespace {
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//===================================================================
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
class ParamDependencyFinder final : public TSyntax::CalculatorNodeVisitor {
|
2016-06-15 18:43:10 +12:00
|
|
|
TDoubleParam *m_possiblyDependentParam;
|
|
|
|
bool m_found;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
ParamDependencyFinder(TDoubleParam *possiblyDependentParam)
|
|
|
|
: m_possiblyDependentParam(possiblyDependentParam), m_found(false) {}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
void check(TDoubleParam *param) {
|
|
|
|
if (param == m_possiblyDependentParam) m_found = true;
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool found() const { return m_found; }
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
2020-04-17 19:02:53 +12:00
|
|
|
//===================================================================
|
|
|
|
/*
|
|
|
|
class ColumnReferenceFinder final : public TSyntax::CalculatorNodeVisitor {
|
|
|
|
QSet<int> m_indices;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ColumnReferenceFinder() {}
|
|
|
|
|
|
|
|
void registerColumnIndex(int columnIndex) { m_indices.insert(columnIndex); }
|
|
|
|
|
|
|
|
QSet<int> indices() const { return m_indices; }
|
|
|
|
};
|
|
|
|
*/
|
|
|
|
//===================================================================
|
|
|
|
|
|
|
|
class ParamReferenceFinder final : public TSyntax::CalculatorNodeVisitor {
|
|
|
|
QSet<TDoubleParam *> m_refParams;
|
|
|
|
QSet<int> m_columnIndices;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ParamReferenceFinder() {}
|
|
|
|
|
|
|
|
void registerRefParam(TDoubleParam *param) { m_refParams.insert(param); }
|
|
|
|
void registerColumnIndex(int columnIndex) {
|
|
|
|
m_columnIndices.insert(columnIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
QSet<int> columnIndices() const { return m_columnIndices; }
|
|
|
|
QSet<TDoubleParam *> refParams() const { return m_refParams; }
|
|
|
|
};
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
//===================================================================
|
|
|
|
//
|
|
|
|
// Calculator Nodes
|
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
2020-04-17 19:02:53 +12:00
|
|
|
class ParamCalculatorNode : public CalculatorNode,
|
|
|
|
public TParamObserver,
|
|
|
|
public boost::noncopyable {
|
2016-07-21 00:49:32 +12:00
|
|
|
std::unique_ptr<CalculatorNode> m_frame;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2020-04-17 19:02:53 +12:00
|
|
|
protected:
|
|
|
|
TDoubleParamP m_param;
|
|
|
|
|
2016-03-19 06:57:51 +13:00
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
ParamCalculatorNode(Calculator *calculator, const TDoubleParamP ¶m,
|
2016-07-21 00:49:32 +12:00
|
|
|
std::unique_ptr<CalculatorNode> frame)
|
|
|
|
: CalculatorNode(calculator), m_param(param), m_frame(std::move(frame)) {
|
2016-06-15 18:43:10 +12:00
|
|
|
param->addObserver(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
~ParamCalculatorNode() { m_param->removeObserver(this); }
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
double compute(double vars[3]) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
double value = m_param->getValue(m_frame->compute(vars) - 1);
|
|
|
|
TMeasure *measure = m_param->getMeasure();
|
|
|
|
if (measure) {
|
|
|
|
const TUnit *unit = measure->getCurrentUnit();
|
2020-06-12 20:33:50 +12:00
|
|
|
if (unit) value = unit->convertTo(value);
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
void accept(TSyntax::CalculatorNodeVisitor &visitor) override {
|
2020-04-17 19:02:53 +12:00
|
|
|
ParamReferenceFinder *prf = dynamic_cast<ParamReferenceFinder *>(&visitor);
|
|
|
|
if (prf) {
|
|
|
|
prf->registerRefParam(m_param.getPointer());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
ParamDependencyFinder *pdf =
|
|
|
|
dynamic_cast<ParamDependencyFinder *>(&visitor);
|
2020-04-17 19:02:53 +12:00
|
|
|
if (pdf) {
|
|
|
|
pdf->check(m_param.getPointer());
|
|
|
|
if (!pdf->found()) m_param->accept(visitor);
|
|
|
|
}
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
void onChange(const TParamChange ¶mChange) override {
|
2016-06-15 18:43:10 +12:00
|
|
|
// The referenced parameter changed. This means the parameter owning the
|
|
|
|
// expression this node is part of, changes too.
|
|
|
|
|
|
|
|
// A param change is thus propagated for this parameter, with the 'keyframe'
|
|
|
|
// parameter turned off - since no keyframe value is actually altered.
|
|
|
|
|
|
|
|
if (TDoubleParam *ownerParam = getCalculator()->getOwnerParameter()) {
|
|
|
|
const std::set<TParamObserver *> &observers = ownerParam->observers();
|
|
|
|
|
|
|
|
TParamChange propagatedChange(ownerParam, 0, 0, false,
|
|
|
|
paramChange.m_dragging,
|
|
|
|
paramChange.m_undoing);
|
|
|
|
|
|
|
|
std::set<TParamObserver *>::const_iterator ot, oEnd = observers.end();
|
|
|
|
for (ot = observers.begin(); ot != oEnd; ++ot)
|
|
|
|
(*ot)->onChange(propagatedChange);
|
|
|
|
}
|
|
|
|
}
|
2020-04-17 19:02:53 +12:00
|
|
|
|
|
|
|
bool hasReference() const override { return true; }
|
|
|
|
};
|
|
|
|
|
|
|
|
// ParamCalculatorNode subclass to monitor referenced columns
|
|
|
|
class ColumnParamCalculatorNode final : public ParamCalculatorNode {
|
|
|
|
int m_columnIndex;
|
|
|
|
|
|
|
|
public:
|
|
|
|
ColumnParamCalculatorNode(Calculator *calculator, const TDoubleParamP ¶m,
|
|
|
|
std::unique_ptr<CalculatorNode> frame,
|
|
|
|
int columnIndex)
|
|
|
|
: ParamCalculatorNode(calculator, param, std::move(frame))
|
|
|
|
, m_columnIndex(columnIndex) {}
|
|
|
|
|
|
|
|
void accept(TSyntax::CalculatorNodeVisitor &visitor) override {
|
|
|
|
ParamReferenceFinder *prf = dynamic_cast<ParamReferenceFinder *>(&visitor);
|
|
|
|
if (prf) {
|
|
|
|
prf->registerRefParam(m_param.getPointer());
|
|
|
|
prf->registerColumnIndex(m_columnIndex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ParamDependencyFinder *pdf =
|
|
|
|
dynamic_cast<ParamDependencyFinder *>(&visitor);
|
|
|
|
if (pdf) {
|
|
|
|
pdf->check(m_param.getPointer());
|
|
|
|
if (!pdf->found()) m_param->accept(visitor);
|
|
|
|
}
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
class XsheetDrawingCalculatorNode final : public CalculatorNode,
|
|
|
|
public boost::noncopyable {
|
2016-06-15 18:43:10 +12:00
|
|
|
TXsheet *m_xsh;
|
|
|
|
int m_columnIndex;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-07-21 00:49:32 +12:00
|
|
|
std::unique_ptr<CalculatorNode> m_frame;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
XsheetDrawingCalculatorNode(Calculator *calc, TXsheet *xsh, int columnIndex,
|
2016-07-21 00:49:32 +12:00
|
|
|
std::unique_ptr<CalculatorNode> frame)
|
2016-06-15 18:43:10 +12:00
|
|
|
: CalculatorNode(calc)
|
|
|
|
, m_xsh(xsh)
|
|
|
|
, m_columnIndex(columnIndex)
|
2016-07-21 00:49:32 +12:00
|
|
|
, m_frame(std::move(frame)) {}
|
2016-06-15 18:43:10 +12:00
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
double compute(double vars[3]) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
double f = m_frame->compute(vars);
|
|
|
|
int i = tfloor(f);
|
|
|
|
f = f - (double)i;
|
|
|
|
TXshCell cell;
|
|
|
|
cell = m_xsh->getCell(i, m_columnIndex);
|
|
|
|
int d0 = cell.isEmpty() ? 0 : cell.m_frameId.getNumber();
|
|
|
|
cell = m_xsh->getCell(i + 1, m_columnIndex);
|
|
|
|
int d1 = cell.isEmpty() ? 0 : cell.m_frameId.getNumber();
|
|
|
|
double d = (1 - f) * d0 + f * d1;
|
|
|
|
return d;
|
|
|
|
}
|
|
|
|
|
2020-04-17 19:02:53 +12:00
|
|
|
void accept(TSyntax::CalculatorNodeVisitor &visitor) override {
|
|
|
|
ParamReferenceFinder *prf = dynamic_cast<ParamReferenceFinder *>(&visitor);
|
|
|
|
if (prf) prf->registerColumnIndex(m_columnIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool hasReference() const override { return true; }
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//===================================================================
|
|
|
|
//
|
|
|
|
// Patterns
|
|
|
|
//
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
class XsheetReferencePattern final : public Pattern {
|
2016-06-15 18:43:10 +12:00
|
|
|
TXsheet *m_xsh;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
XsheetReferencePattern(TXsheet *xsh) : m_xsh(xsh) {
|
|
|
|
setDescription(std::string("object.action\nTransformation reference\n") +
|
|
|
|
"object can be: tab, table, cam<n>, camera<n>, col<n>, "
|
|
|
|
"peg<n>, pegbar<n>\n" +
|
|
|
|
"action can be: "
|
|
|
|
"ns,ew,rot,ang,angle,z,zdepth,sx,sy,sc,scale,scalex,scaley,"
|
|
|
|
"path,pos,shx,shy");
|
|
|
|
}
|
|
|
|
|
|
|
|
TStageObjectId matchObjectName(const Token &token) const {
|
|
|
|
std::string s = toLower(token.getText());
|
|
|
|
int len = (int)s.length(), i, j;
|
|
|
|
for (i = 0; i < len && isascii(s[i]) && isalpha(s[i]); i++) {
|
|
|
|
}
|
|
|
|
if (i == 0) return TStageObjectId::NoneId;
|
|
|
|
std::string a = s.substr(0, i);
|
|
|
|
int index = 0;
|
|
|
|
for (j = i; j < len && isascii(s[j]) && isdigit(s[j]); j++)
|
|
|
|
index = index * 10 + (s[j] - '0');
|
|
|
|
if (j < len) return TStageObjectId::NoneId;
|
|
|
|
if (i == j) index = -1;
|
|
|
|
if ((a == "table" || a == "tab") && index < 0)
|
|
|
|
return TStageObjectId::TableId;
|
|
|
|
else if (a == "col" && index >= 1)
|
|
|
|
return TStageObjectId::ColumnId(index - 1);
|
|
|
|
else if ((a == "cam" || a == "camera") && index >= 1)
|
|
|
|
return TStageObjectId::CameraId(index - 1);
|
|
|
|
else if ((a == "peg" || a == "pegbar") && index >= 1)
|
|
|
|
return TStageObjectId::PegbarId(index - 1);
|
|
|
|
else
|
|
|
|
return TStageObjectId::NoneId;
|
|
|
|
}
|
|
|
|
|
2020-04-17 19:02:53 +12:00
|
|
|
TStageObjectId matchExistingObjectName(const Token &token) const {
|
|
|
|
TStageObjectId objId = matchObjectName(token);
|
|
|
|
if (objId != TStageObjectId::NoneId &&
|
|
|
|
m_xsh->getStageObjectTree()->getStageObject(objId, false))
|
|
|
|
return objId;
|
|
|
|
else
|
|
|
|
return TStageObjectId::NoneId;
|
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TStageObject::Channel matchChannelName(const Token &token) const {
|
|
|
|
std::string s = toLower(token.getText());
|
2020-06-12 20:33:50 +12:00
|
|
|
if (s == "ns" || s == "y")
|
2016-06-15 18:43:10 +12:00
|
|
|
return TStageObject::T_Y;
|
2020-06-12 20:33:50 +12:00
|
|
|
else if (s == "ew" || s == "x")
|
2016-06-15 18:43:10 +12:00
|
|
|
return TStageObject::T_X;
|
|
|
|
else if (s == "rot" || s == "ang" || s == "angle")
|
|
|
|
return TStageObject::T_Angle;
|
|
|
|
else if (s == "z" || s == "zdepth")
|
|
|
|
return TStageObject::T_Z;
|
|
|
|
else if (s == "sx" || s == "scalex" || s == "xscale" || s == "xs" ||
|
|
|
|
s == "sh" || s == "scaleh" || s == "hscale" || s == "hs")
|
|
|
|
return TStageObject::T_ScaleX;
|
|
|
|
else if (s == "sy" || s == "scaley" || s == "yscale" || s == "ys" ||
|
|
|
|
s == "sv" || s == "scalev" || s == "vscale" || s == "vs")
|
|
|
|
return TStageObject::T_ScaleY;
|
|
|
|
else if (s == "sc" || s == "scale")
|
|
|
|
return TStageObject::T_Scale;
|
|
|
|
else if (s == "path" || s == "pos")
|
|
|
|
return TStageObject::T_Path;
|
|
|
|
else if (s == "shearx" || s == "shx" || s == "shearh" || s == "shh")
|
|
|
|
return TStageObject::T_ShearX;
|
|
|
|
else if (s == "sheary" || s == "shy" || s == "shearv" || s == "shv")
|
|
|
|
return TStageObject::T_ShearY;
|
|
|
|
else
|
|
|
|
return TStageObject::T_ChannelCount;
|
|
|
|
}
|
|
|
|
|
2016-06-20 14:23:05 +12:00
|
|
|
bool expressionExpected(
|
|
|
|
const std::vector<Token> &previousTokens) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return previousTokens.size() == 4;
|
|
|
|
}
|
|
|
|
bool matchToken(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
int i = (int)previousTokens.size();
|
|
|
|
if (i == 0)
|
2020-04-17 19:02:53 +12:00
|
|
|
return matchExistingObjectName(token) != TStageObjectId::NoneId;
|
2020-04-12 17:19:20 +12:00
|
|
|
else if ((i == 1 && token.getText() == ".") ||
|
|
|
|
(i == 3 && token.getText() == "(") ||
|
|
|
|
(i == 5 && token.getText() == ")"))
|
2016-06-15 18:43:10 +12:00
|
|
|
return true;
|
|
|
|
else if (i == 2) {
|
|
|
|
if (matchChannelName(token) < TStageObject::T_ChannelCount)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return token.getText() == "cell" &&
|
2020-04-17 19:02:53 +12:00
|
|
|
matchExistingObjectName(previousTokens[0]).isColumn();
|
2016-06-15 18:43:10 +12:00
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool isFinished(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return previousTokens.size() >= 6;
|
|
|
|
}
|
|
|
|
bool isComplete(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return previousTokens.size() >= 6 || previousTokens.size() == 3;
|
|
|
|
}
|
|
|
|
TSyntax::TokenType getTokenType(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return TSyntax::Operator;
|
|
|
|
}
|
|
|
|
|
2016-06-20 14:23:05 +12:00
|
|
|
void getAcceptableKeywords(
|
|
|
|
std::vector<std::string> &keywords) const override {
|
2018-09-06 05:07:46 +12:00
|
|
|
keywords.insert(keywords.end(),
|
|
|
|
{"table", "tab", "col", "cam", "camera", "peg", "pegbar"});
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
void createNode(Calculator *calc, std::vector<CalculatorNode *> &stack,
|
2016-06-19 20:06:29 +12:00
|
|
|
const std::vector<Token> &tokens) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(tokens.size() >= 3);
|
|
|
|
|
2016-07-21 00:49:32 +12:00
|
|
|
std::unique_ptr<CalculatorNode> frameNode(
|
2016-06-15 18:43:10 +12:00
|
|
|
(tokens.size() == 6) ? popNode(stack)
|
|
|
|
: new VariableNode(calc, CalculatorNode::FRAME));
|
|
|
|
|
|
|
|
TStageObjectId objectId = matchObjectName(tokens[0]);
|
|
|
|
|
|
|
|
std::string field = toLower(tokens[2].getText());
|
|
|
|
if (field == "cell" || field == "cel" || field == "cels") {
|
|
|
|
int columnIndex = objectId.getIndex();
|
2016-07-21 00:49:32 +12:00
|
|
|
stack.push_back(new XsheetDrawingCalculatorNode(calc, m_xsh, columnIndex,
|
|
|
|
std::move(frameNode)));
|
2016-06-15 18:43:10 +12:00
|
|
|
} else {
|
2020-04-17 19:02:53 +12:00
|
|
|
// do not create object if it does not exist
|
|
|
|
TStageObject *object =
|
|
|
|
m_xsh->getStageObjectTree()->getStageObject(objectId, false);
|
|
|
|
if (!object) return;
|
2016-06-15 18:43:10 +12:00
|
|
|
TStageObject::Channel channelName = matchChannelName(tokens[2]);
|
|
|
|
TDoubleParam *channel = object->getParam(channelName);
|
2020-04-17 19:02:53 +12:00
|
|
|
if (channel) {
|
|
|
|
if (objectId.isColumn())
|
|
|
|
stack.push_back(new ColumnParamCalculatorNode(
|
|
|
|
calc, channel, std::move(frameNode), objectId.getIndex()));
|
|
|
|
else
|
|
|
|
stack.push_back(
|
|
|
|
new ParamCalculatorNode(calc, channel, std::move(frameNode)));
|
|
|
|
}
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
class FxReferencePattern final : public Pattern {
|
2016-06-15 18:43:10 +12:00
|
|
|
TXsheet *m_xsh;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
FxReferencePattern(TXsheet *xsh) : m_xsh(xsh) {}
|
|
|
|
|
|
|
|
TFx *getFx(const Token &token) const {
|
2020-04-17 19:02:53 +12:00
|
|
|
TFx *fx =
|
|
|
|
m_xsh->getFxDag()->getFxById(::to_wstring(toLower(token.getText())));
|
|
|
|
// removed fx cannot be referenced
|
|
|
|
if (!fx)
|
|
|
|
return nullptr;
|
|
|
|
else if (fx->isZerary()) {
|
|
|
|
TZeraryFx *zFx = dynamic_cast<TZeraryFx *>(fx);
|
|
|
|
// For now we cannot use zFx->getColumnFx()->getColumnIndex() < 0 to check
|
|
|
|
// existence of the column. See a comment in tcolumnset.h for details.
|
|
|
|
if (!zFx || !zFx->getColumnFx()->getXshColumn()->inColumnsSet())
|
|
|
|
return nullptr;
|
|
|
|
} else if (!m_xsh->getFxDag()->getInternalFxs()->containsFx(fx))
|
|
|
|
return nullptr;
|
|
|
|
return fx;
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
|
|
|
TParam *getParam(const TFx *fx, const Token &token) const {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < fx->getParams()->getParamCount(); i++) {
|
|
|
|
TParam *param = fx->getParams()->getParam(i);
|
|
|
|
std::string paramName = ::to_string(
|
|
|
|
TStringTable::translate(fx->getFxType() + "." + param->getName()));
|
2017-11-28 16:36:26 +13:00
|
|
|
int i = paramName.find_first_of(" -");
|
2016-06-15 18:43:10 +12:00
|
|
|
while (i != std::string::npos) {
|
|
|
|
paramName.erase(i, 1);
|
2017-11-28 16:36:26 +13:00
|
|
|
i = paramName.find_first_of(" -");
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
|
|
|
std::string paramNameToCheck = token.getText();
|
|
|
|
if (paramName == paramNameToCheck ||
|
|
|
|
toLower(paramName) == toLower(paramNameToCheck))
|
|
|
|
return param;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
TParam *getLeafParam(const TFx *fx, const TParamSet *paramSet,
|
|
|
|
const Token &token) const {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < paramSet->getParamCount(); i++) {
|
|
|
|
TParam *param = paramSet->getParam(i).getPointer();
|
|
|
|
std::string paramName = param->getName();
|
|
|
|
int i = paramName.find(" ");
|
|
|
|
while (i != std::string::npos) {
|
|
|
|
paramName.erase(i, 1);
|
|
|
|
i = paramName.find(" ");
|
|
|
|
}
|
|
|
|
std::string paramNameToCheck = token.getText();
|
|
|
|
if (paramName == paramNameToCheck ||
|
|
|
|
toLower(paramName) == toLower(paramNameToCheck))
|
|
|
|
return param;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2016-06-19 20:06:29 +12:00
|
|
|
std::string getFirstKeyword() const override { return "fx"; }
|
2016-06-20 14:23:05 +12:00
|
|
|
bool expressionExpected(
|
|
|
|
const std::vector<Token> &previousTokens) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return !previousTokens.empty() && previousTokens.back().getText() == "(";
|
|
|
|
}
|
|
|
|
bool matchToken(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
int i = (int)previousTokens.size();
|
|
|
|
std::string s = toLower(token.getText());
|
|
|
|
if (i == 0 && s == "fx")
|
|
|
|
return true;
|
|
|
|
else if (i == 1)
|
|
|
|
return s == ".";
|
|
|
|
else if (i & 1) {
|
|
|
|
if (previousTokens[i - 2].getText() == "(")
|
|
|
|
return s == ")";
|
|
|
|
else
|
|
|
|
return s == "." || s == "(";
|
|
|
|
} else if (i == 2) {
|
|
|
|
// nome fx
|
|
|
|
return getFx(token) != 0;
|
|
|
|
} else if (i == 4) {
|
|
|
|
TFx *fx = getFx(previousTokens[2]);
|
|
|
|
if (!fx) return false;
|
|
|
|
TParam *param = getParam(fx, token);
|
|
|
|
return !!param;
|
|
|
|
} else if (i == 6) {
|
|
|
|
TFx *fx = getFx(previousTokens[2]);
|
|
|
|
if (!fx) return false;
|
|
|
|
TParam *param = getParam(fx, previousTokens[4]);
|
|
|
|
TParamSet *paramSet = dynamic_cast<TParamSet *>(param);
|
|
|
|
if (!paramSet) return false;
|
|
|
|
TParam *leafParam = getLeafParam(fx, paramSet, token);
|
|
|
|
return !!param;
|
|
|
|
} else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
bool isFinished(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return !previousTokens.empty() && previousTokens.back().getText() == ")";
|
|
|
|
}
|
|
|
|
bool isComplete(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
int n = (int)previousTokens.size();
|
|
|
|
return n >= 2 && (n & 1) == 1 && previousTokens[n - 2].getText() != "(";
|
|
|
|
}
|
|
|
|
TSyntax::TokenType getTokenType(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return TSyntax::Operator;
|
|
|
|
}
|
|
|
|
|
|
|
|
void createNode(Calculator *calc, std::vector<CalculatorNode *> &stack,
|
2016-06-19 20:06:29 +12:00
|
|
|
const std::vector<Token> &tokens) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
int tokenSize = tokens.size();
|
|
|
|
|
2016-07-21 00:49:32 +12:00
|
|
|
std::unique_ptr<CalculatorNode> frameNode(
|
2016-06-15 18:43:10 +12:00
|
|
|
(tokenSize > 0 && tokens.back().getText() == ")")
|
|
|
|
? popNode(stack)
|
|
|
|
: new VariableNode(calc, CalculatorNode::FRAME));
|
|
|
|
|
|
|
|
TFx *fx = getFx(tokens[2]);
|
|
|
|
if (!fx || tokenSize < 4) return;
|
|
|
|
|
|
|
|
TParamP param = getParam(fx, tokens[4]);
|
|
|
|
if (!param.getPointer()) return;
|
|
|
|
|
|
|
|
TDoubleParamP channel;
|
|
|
|
TParamSet *paramSet = dynamic_cast<TParamSet *>(param.getPointer());
|
|
|
|
|
|
|
|
if (paramSet && tokenSize > 6)
|
|
|
|
channel =
|
|
|
|
dynamic_cast<TDoubleParam *>(getLeafParam(fx, paramSet, tokens[6]));
|
|
|
|
else
|
|
|
|
channel = param;
|
|
|
|
|
|
|
|
if (channel.getPointer())
|
2016-07-21 00:49:32 +12:00
|
|
|
stack.push_back(
|
|
|
|
new ParamCalculatorNode(calc, channel, std::move(frameNode)));
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
|
2016-06-29 18:17:12 +12:00
|
|
|
class PlasticVertexPattern final : public Pattern {
|
2016-06-15 18:43:10 +12:00
|
|
|
TXsheet *m_xsh;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Full pattern layout:
|
|
|
|
|
|
|
|
vertex ( columnNumber , " vertexName " ) . component ( expr )
|
|
|
|
0 1 2 3 4 5 6 7 8 9 10 11 12
|
|
|
|
*/
|
|
|
|
|
|
|
|
enum Positions {
|
|
|
|
OBJECT,
|
|
|
|
L1,
|
|
|
|
COLUMN_NUMBER,
|
|
|
|
COMMA,
|
|
|
|
QUOTE1,
|
|
|
|
VERTEX_NAME,
|
|
|
|
QUOTE2,
|
|
|
|
R1,
|
|
|
|
SELECTOR,
|
|
|
|
COMPONENT,
|
|
|
|
L2,
|
|
|
|
EXPR,
|
|
|
|
R2,
|
|
|
|
POSITIONS_COUNT
|
|
|
|
};
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
public:
|
2016-06-15 18:43:10 +12:00
|
|
|
PlasticVertexPattern(TXsheet *xsh) : m_xsh(xsh) {
|
|
|
|
setDescription(
|
|
|
|
"vertex(columnNumber, \"vertexName\").action\nVertex data\n"
|
|
|
|
"columnNumber must be the number of the column containing the desired "
|
|
|
|
"skeleton\n"
|
|
|
|
"vertexName must be the name of a Plastic Skeleton vertex\n"
|
|
|
|
"action must be one of the parameter names available for a Plastic "
|
|
|
|
"Skeleton vertex");
|
|
|
|
}
|
|
|
|
|
2016-06-19 20:06:29 +12:00
|
|
|
std::string getFirstKeyword() const override { return "vertex"; }
|
2016-06-15 18:43:10 +12:00
|
|
|
|
2016-06-20 14:23:05 +12:00
|
|
|
bool expressionExpected(
|
|
|
|
const std::vector<Token> &previousTokens) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return (previousTokens.size() == EXPR);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool matchToken(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
struct {
|
|
|
|
const PlasticVertexPattern *m_this;
|
|
|
|
const SkD *skdp(const Token &columnToken) {
|
|
|
|
int colIdx = columnToken.getIntValue() -
|
|
|
|
1; // The first column (1) actually starts at index 0
|
|
|
|
|
|
|
|
if (!m_this->m_xsh->isColumnEmpty(colIdx)) {
|
|
|
|
TStageObject *obj =
|
|
|
|
m_this->m_xsh->getStageObject(TStageObjectId::ColumnId(colIdx));
|
|
|
|
assert(obj);
|
|
|
|
|
|
|
|
if (const SkDP &skdp = obj->getPlasticSkeletonDeformation())
|
|
|
|
return skdp.getPointer();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} locals = {this};
|
|
|
|
|
|
|
|
const std::string &text = token.getText();
|
|
|
|
int pos = previousTokens.size();
|
|
|
|
|
|
|
|
if (!m_fixedTokens[pos].empty()) return (text == m_fixedTokens[pos]);
|
|
|
|
|
|
|
|
switch (pos) {
|
|
|
|
case COLUMN_NUMBER:
|
|
|
|
return (token.getType() == Token::Number && locals.skdp(token));
|
|
|
|
|
|
|
|
case VERTEX_NAME:
|
|
|
|
if (const SkD *skdp = locals.skdp(previousTokens[COLUMN_NUMBER])) {
|
|
|
|
const QString &vertexName = QString::fromStdString(text);
|
|
|
|
return (skdp->vertexDeformation(vertexName) != 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMPONENT:
|
|
|
|
return std::count(m_components,
|
|
|
|
m_components + sizeof(m_components) / sizeof(Component),
|
|
|
|
text) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isFinished(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return (previousTokens.size() >= POSITIONS_COUNT);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool isComplete(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return (previousTokens.size() >= POSITIONS_COUNT ||
|
|
|
|
previousTokens.size() == L2);
|
|
|
|
}
|
|
|
|
|
|
|
|
TSyntax::TokenType getTokenType(const std::vector<Token> &previousTokens,
|
2016-06-19 20:06:29 +12:00
|
|
|
const Token &token) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
return TSyntax::Operator;
|
|
|
|
}
|
|
|
|
|
|
|
|
void createNode(Calculator *calc, std::vector<CalculatorNode *> &stack,
|
2016-06-19 20:06:29 +12:00
|
|
|
const std::vector<Token> &tokens) const override {
|
2016-06-15 18:43:10 +12:00
|
|
|
assert(tokens.size() > COMPONENT);
|
|
|
|
|
2016-07-21 00:49:32 +12:00
|
|
|
std::unique_ptr<CalculatorNode> frameNode(
|
2016-06-15 18:43:10 +12:00
|
|
|
(tokens.size() == POSITIONS_COUNT)
|
|
|
|
? popNode(stack)
|
|
|
|
: new VariableNode(calc, CalculatorNode::FRAME));
|
|
|
|
|
|
|
|
int colIdx = tokens[COLUMN_NUMBER].getIntValue() - 1;
|
|
|
|
if (!m_xsh->isColumnEmpty(colIdx)) {
|
|
|
|
TStageObject *obj =
|
|
|
|
m_xsh->getStageObject(TStageObjectId::ColumnId(colIdx));
|
|
|
|
assert(obj);
|
|
|
|
|
|
|
|
if (const SkDP &skdp = obj->getPlasticSkeletonDeformation()) {
|
|
|
|
const QString &vertexName =
|
|
|
|
QString::fromStdString(tokens[VERTEX_NAME].getText());
|
|
|
|
if (SkVD *skvd = skdp->vertexDeformation(vertexName)) {
|
2020-06-12 20:33:50 +12:00
|
|
|
const Component *componentsEnd =
|
|
|
|
m_components +
|
|
|
|
sizeof(m_components) / sizeof(Component),
|
2016-06-15 18:43:10 +12:00
|
|
|
*component = std::find(m_components, componentsEnd,
|
|
|
|
tokens[COMPONENT].getText());
|
|
|
|
|
|
|
|
if (component != componentsEnd) {
|
|
|
|
const TDoubleParamP ¶m =
|
|
|
|
skvd->m_params[component->m_paramId].getPointer();
|
2016-07-21 00:49:32 +12:00
|
|
|
stack.push_back(
|
|
|
|
new ParamCalculatorNode(calc, param, std::move(frameNode)));
|
2016-06-15 18:43:10 +12:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
struct Component {
|
|
|
|
std::string m_name;
|
|
|
|
SkVD::Params m_paramId;
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool operator==(const std::string &name) const { return (m_name == name); }
|
|
|
|
};
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
private:
|
2016-06-15 18:43:10 +12:00
|
|
|
static const std::string m_fixedTokens[POSITIONS_COUNT];
|
|
|
|
static const Component m_components[5];
|
2016-03-19 06:57:51 +13:00
|
|
|
};
|
|
|
|
|
|
|
|
const std::string PlasticVertexPattern::m_fixedTokens[POSITIONS_COUNT] = {
|
2016-06-15 18:43:10 +12:00
|
|
|
"vertex", "(", "", ",", "\"", "", "\"", ")", ".", "", "(", "", ")"};
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
const PlasticVertexPattern::Component PlasticVertexPattern::m_components[] = {
|
2016-06-15 18:43:10 +12:00
|
|
|
{"ang", SkVD::ANGLE},
|
|
|
|
{"angle", SkVD::ANGLE},
|
|
|
|
{"dist", SkVD::DISTANCE},
|
|
|
|
{"distance", SkVD::DISTANCE},
|
|
|
|
{"so", SkVD::SO}};
|
2016-03-19 06:57:51 +13:00
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
} // namespace
|
2016-03-19 06:57:51 +13:00
|
|
|
|
|
|
|
//******************************************************************************
|
|
|
|
// API functions
|
|
|
|
//******************************************************************************
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
TSyntax::Grammar *createXsheetGrammar(TXsheet *xsh) {
|
|
|
|
Grammar *grammar = new Grammar();
|
|
|
|
grammar->addPattern(new XsheetReferencePattern(xsh));
|
|
|
|
grammar->addPattern(new FxReferencePattern(xsh));
|
|
|
|
grammar->addPattern(new PlasticVertexPattern(xsh));
|
|
|
|
return grammar;
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool dependsOn(TExpression &expr, TDoubleParam *possiblyDependentParam) {
|
|
|
|
ParamDependencyFinder pdf(possiblyDependentParam);
|
|
|
|
expr.accept(pdf);
|
|
|
|
return pdf.found();
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
|
|
|
|
2016-06-15 18:43:10 +12:00
|
|
|
bool dependsOn(TDoubleParam *param, TDoubleParam *possiblyDependentParam) {
|
|
|
|
ParamDependencyFinder pdf(possiblyDependentParam);
|
|
|
|
param->accept(pdf);
|
|
|
|
return pdf.found();
|
2016-03-19 06:57:51 +13:00
|
|
|
}
|
2020-04-17 19:02:53 +12:00
|
|
|
|
|
|
|
void referenceParams(TExpression &expr, QSet<int> &columnIndices,
|
|
|
|
QSet<TDoubleParam *> ¶ms) {
|
|
|
|
ParamReferenceFinder prf;
|
|
|
|
expr.accept(prf);
|
|
|
|
columnIndices = prf.columnIndices();
|
|
|
|
params = prf.refParams();
|
|
|
|
}
|