// TnzCore includes #include "trandom.h" #include "tutil.h" #include "tconvert.h" // TnzBase includes #include "ttokenizer.h" #include "tunit.h" #include "tparser.h" #include "tdoubleparam.h" #include "tdoublekeyframe.h" // STD includes #include #include #include // Qt includes #include #include "tgrammar.h" const double PI = 4 * atan(1.0); const double toDeg(double rad) { return rad * 180.0 / PI; } const double toRad(double deg) { return deg / 180.0 * PI; } namespace TSyntax { //=================================================================== // // RandomManager // // es. x = RandomManager::instance()->getValue(seed, frame); // //------------------------------------------------------------------- class RandomSequence { TRandom m_rnd; std::vector m_values; public: RandomSequence(UINT seed) : m_rnd(seed) {} double getValue(int i) { assert(i >= 0); if (i >= (int)m_values.size()) { m_values.reserve(i + 1); while (i >= (int)m_values.size()) m_values.push_back(m_rnd.getDouble()); } return m_values[i]; } }; //------------------------------------------------------------------- class RandomManager { // singleton typedef std::map Table; Table m_table; RandomManager() {} public: ~RandomManager() { for (Table::iterator i = m_table.begin(); i != m_table.end(); ++i) delete i->second; } static RandomManager *instance() { static RandomManager _instance; return &_instance; } RandomSequence *getSequence(UINT seed) { Table::iterator i = m_table.find(seed); if (i == m_table.end()) { RandomSequence *seq = new RandomSequence(seed); m_table[seed] = seq; return seq; } else return i->second; } double getValue(UINT seed, double t) { RandomSequence *seq = getSequence(seed); return seq->getValue(t > 0 ? tfloor(t) : 0); } }; //=================================================================== // Calculator //------------------------------------------------------------------- Calculator::Calculator() : m_rootNode(0), m_param(0), m_unit(0) { } //------------------------------------------------------------------- Calculator::~Calculator() { delete m_rootNode; } //------------------------------------------------------------------- void Calculator::setRootNode(CalculatorNode *node) { if (node != m_rootNode) { delete m_rootNode; m_rootNode = node; } } //=================================================================== // Nodes //------------------------------------------------------------------- template class Op0Node : public CalculatorNode { public: Op0Node(Calculator *calc) : CalculatorNode(calc) {} double compute(double vars[3]) const { Op op; return op(); } }; //------------------------------------------------------------------- template class Op1Node : public CalculatorNode { protected: std::auto_ptr m_a; public: Op1Node(Calculator *calc, CalculatorNode *a) : CalculatorNode(calc), m_a(a) {} double compute(double vars[3]) const { Op op; return op(m_a->compute(vars)); } void accept(CalculatorNodeVisitor &visitor) { m_a->accept(visitor); } }; //------------------------------------------------------------------- template class Op2Node : public CalculatorNode { protected: std::auto_ptr m_a, m_b; public: Op2Node(Calculator *calc, CalculatorNode *a, CalculatorNode *b) : CalculatorNode(calc), m_a(a), m_b(b) {} double compute(double vars[3]) const { Op op; return op(m_a->compute(vars), m_b->compute(vars)); } void accept(CalculatorNodeVisitor &visitor) { m_a->accept(visitor), m_b->accept(visitor); } }; //------------------------------------------------------------------- template class Op3Node : public CalculatorNode { protected: std::auto_ptr m_a, m_b, m_c; public: Op3Node(Calculator *calc, CalculatorNode *a, CalculatorNode *b, CalculatorNode *c) : CalculatorNode(calc), m_a(a), m_b(b), m_c(c) {} double compute(double vars[3]) const { Op op; return op(m_a->compute(vars), m_b->compute(vars), m_c->compute(vars)); } void accept(CalculatorNodeVisitor &visitor) { m_a->accept(visitor), m_b->accept(visitor), m_c->accept(visitor); } }; //------------------------------------------------------------------- class ChsNode : public CalculatorNode { std::auto_ptr m_a; public: ChsNode(Calculator *calc, CalculatorNode *a) : CalculatorNode(calc), m_a(a) {} double compute(double vars[3]) const { return -m_a->compute(vars); } void accept(CalculatorNodeVisitor &visitor) { m_a->accept(visitor); } }; //------------------------------------------------------------------- class QuestionNode : public CalculatorNode { std::auto_ptr m_a, m_b, m_c; public: QuestionNode(Calculator *calc, CalculatorNode *a, CalculatorNode *b, CalculatorNode *c) : CalculatorNode(calc), m_a(a), m_b(b), m_c(c) {} double compute(double vars[3]) const { return (m_a->compute(vars) != 0) ? m_b->compute(vars) : m_c->compute(vars); } void accept(CalculatorNodeVisitor &visitor) { m_a->accept(visitor), m_b->accept(visitor), m_c->accept(visitor); } }; //------------------------------------------------------------------- class NotNode : public CalculatorNode { std::auto_ptr m_a; public: NotNode(Calculator *calc, CalculatorNode *a) : CalculatorNode(calc), m_a(a) {} double compute(double vars[3]) const { return m_a->compute(vars) == 0; } void accept(CalculatorNodeVisitor &visitor) { m_a->accept(visitor); } }; //------------------------------------------------------------------- class CycleNode : public CalculatorNode { std::auto_ptr m_a; public: CycleNode(Calculator *calc, CalculatorNode *a) : CalculatorNode(calc), m_a(a) {} double compute(double vars[3]) const { struct locals { static inline double compute(const TDoubleParam ¶m, double f) { if (param.getKeyframeCount() >= 2 && f < param.keyframeIndexToFrame(0)) { TDoubleKeyframe kf = param.getKeyframe(0); if (kf.m_type == TDoubleKeyframe::Expression || kf.m_type == TDoubleKeyframe::SimilarShape) return param.getDefaultValue(); } double value = param.getValue(f); return value; } }; double delta = tmax(1.0, m_a->compute(vars)); const TDoubleParam *ownerParam = getCalculator()->getOwnerParameter(); if (!ownerParam) return 0; double value = locals::compute(*ownerParam, vars[FRAME] - 1 - delta); if (getCalculator()->getUnit()) value = getCalculator()->getUnit()->convertTo(value); return value; } void accept(CalculatorNodeVisitor &visitor) { m_a->accept(visitor); } }; //------------------------------------------------------------------- class RandomNode : public CalculatorNode { std::auto_ptr m_seed, m_min, m_max, m_arg; public: RandomNode(Calculator *calc) : CalculatorNode(calc), m_seed(0), m_min(0), m_max(0) { m_arg.reset(new VariableNode(calc, CalculatorNode::FRAME)); } void setSeed(CalculatorNode *arg) { assert(m_seed.get() == 0); m_seed.reset(arg); } void setMax(CalculatorNode *arg) { assert(m_max.get() == 0); m_max.reset(arg); } void setMin(CalculatorNode *arg) { assert(m_min.get() == 0); m_min.reset(arg); } double compute(double vars[3]) const { double s = (m_seed.get() != 0) ? m_seed->compute(vars) : 0; double r = RandomManager::instance()->getValue(s, fabs(m_arg->compute(vars))); if (m_min.get() == 0) if (m_max.get() == 0) return r; else return m_max->compute(vars) * r; else return (1 - r) * m_min->compute(vars) + r * m_max->compute(vars); } void accept(CalculatorNodeVisitor &visitor) { m_arg->accept(visitor); if (m_seed.get()) m_seed->accept(visitor); if (m_min.get()) m_min->accept(visitor); if (m_max.get()) m_max->accept(visitor); } }; //=================================================================== // Patterns //------------------------------------------------------------------- CalculatorNode *Pattern::popNode(std::vector &stack) const { CalculatorNode *node = stack.back(); stack.pop_back(); return node; } //=================================================================== class NumberPattern : public Pattern { public: bool matchToken(const std::vector &previousTokens, const Token &token) const { return previousTokens.empty() && token.getType() == Token::Number; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 1; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { return Number; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { assert(tokens.size() == 1); assert(tokens[0].getType() == Token::Number); stack.push_back(new NumberNode(calc, tokens[0].getDoubleValue())); } }; //------------------------------------------------------------------- class ConstantPattern : public Pattern { string m_constantName; double m_value; public: ConstantPattern(string constantName, double value, string description = "") : m_constantName(constantName), m_value(value) { setDescription(description); } string getFirstKeyword() const { return m_constantName; } bool matchToken(const std::vector &previousTokens, const Token &token) const { return previousTokens.empty() && token.getText() == m_constantName; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 1; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { return Constant; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { assert(tokens.size() == 1); stack.push_back(new NumberNode(calc, m_value)); } }; //------------------------------------------------------------------- class VariablePattern : public Pattern { string m_variableName; int m_varIdx; public: VariablePattern(string variableName, int varIdx, string description = "") : m_variableName(variableName), m_varIdx(varIdx) { setDescription(description); } string getFirstKeyword() const { return m_variableName; } bool matchToken(const std::vector &previousTokens, const Token &token) const { return previousTokens.empty() && token.getText() == m_variableName; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 1; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { return Variable; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { assert(tokens.size() == 1); assert(tokens[0].getText() == m_variableName); stack.push_back(new VariableNode(calc, m_varIdx)); } }; //------------------------------------------------------------------- template class Op2Pattern : public Pattern { string m_opName; int m_priority; public: Op2Pattern(string opName, int priority) : m_opName(opName), m_priority(priority) {} int getPriority() const { return m_priority; } string getFirstKeyword() const { return m_opName; } bool expressionExpected(const std::vector &previousTokens) const { return previousTokens.empty() || previousTokens.size() == 2; } bool matchToken(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 1 && token.getText() == m_opName; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 3; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 1 ? Operator : InternalError; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { assert(tokens.size() == 3); assert(tokens[1].getText() == m_opName); CalculatorNode *b = popNode(stack); CalculatorNode *a = popNode(stack); stack.push_back(new Op2Node(calc, a, b)); } }; //------------------------------------------------------------------- class UnaryMinusPattern : public Pattern { public: UnaryMinusPattern() {} int getPriority() const { return 50; } string getFirstKeyword() const { return "-"; } bool expressionExpected(const std::vector &previousTokens) const { return previousTokens.size() == 1; } bool matchToken(const std::vector &previousTokens, const Token &token) const { return previousTokens.empty() && token.getText() == "-"; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 2; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { return Operator; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { assert(tokens.size() == 2); assert(tokens[0].getText() == "-"); stack.push_back(new ChsNode(calc, popNode(stack))); } }; //------------------------------------------------------------------- class NotPattern : public Pattern { string m_prefix; public: NotPattern(string prefix, string description) : m_prefix(prefix) { setDescription(description); } int getPriority() const { return 5; } string getFirstKeyword() const { return m_prefix; } bool expressionExpected(const std::vector &previousTokens) const { return previousTokens.size() == 1; } bool matchToken(const std::vector &previousTokens, const Token &token) const { return previousTokens.empty() && token.getText() == m_prefix; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 2; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { return Operator; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { assert(tokens.size() == 2); assert(tokens[0].getText() == m_prefix); stack.push_back(new NotNode(calc, popNode(stack))); } }; //------------------------------------------------------------------- class QuestionTernaryPattern : public Pattern { public: QuestionTernaryPattern() {} int getPriority() const { return 5; } string getFirstKeyword() const { return "?"; } bool expressionExpected(const std::vector &previousTokens) const { int i = (int)previousTokens.size(); return i == 0 || i == 2 || i == 4; } bool matchToken(const std::vector &previousTokens, const Token &token) const { int i = (int)previousTokens.size(); return i == 1 && token.getText() == "?" || i == 3 && token.getText() == ":"; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 5; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { int i = (int)previousTokens.size(); return (i == 1 || i == 3) ? Operator : InternalError; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { CalculatorNode *node1 = popNode(stack); CalculatorNode *node2 = popNode(stack); CalculatorNode *node3 = popNode(stack); stack.push_back(new QuestionNode(calc, node3, node2, node1)); } }; //------------------------------------------------------------------- class BraketPattern : public Pattern { public: BraketPattern() {} int getPriority() const { return 5; } string getFirstKeyword() const { return "("; } bool expressionExpected(const std::vector &previousTokens) const { return previousTokens.size() == 1; } bool matchToken(const std::vector &previousTokens, const Token &token) const { return previousTokens.empty() && token.getText() == "(" || previousTokens.size() == 2 && token.getText() == ")"; } bool isFinished(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() == 3; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { return previousTokens.size() != 1 ? Parenthesis : InternalError; } void createNode( Calculator *calc, std::vector &stack, const std::vector &tokens) const { assert(tokens.size() == 3); assert(tokens[0].getText() == "("); assert(tokens[2].getText() == ")"); } }; //------------------------------------------------------------------- class FunctionPattern : public Pattern { protected: string m_functionName; bool m_implicitArgAllowed; // if m_implicitArgAllowed == true then the first argument is the frame number // e.g. f(5) means f(frame,5) // to use a different first argument (e.g. t*10) you have to write f(t*10;5) int m_minArgCount; std::vector m_optionalArgDefaults; public: FunctionPattern(string functionName, int minArgCount) : m_functionName(functionName), m_implicitArgAllowed(false), m_minArgCount(minArgCount) { } void allowImplicitArg(bool allowed) { m_implicitArgAllowed = allowed; } void addOptionalArg(double value) { m_optionalArgDefaults.push_back(value); } string getFirstKeyword() const { return m_functionName; } bool expressionExpected(const std::vector &previousTokens) const { int n = (int)previousTokens.size(); return 2 <= n && (n & 1) == 0; } bool matchToken(const std::vector &previousTokens, const Token &token) const { int i = (int)previousTokens.size(); string s = toLower(token.getText()); if (i == 0) return s == toLower(m_functionName); else if (i == 1) return s == "("; else if ((i & 1) == 0) return true; else if (s == ",") return true; else if (s == ";") return i == 3 && m_implicitArgAllowed; else if (s == ")") { int n = (i - 1) / 2; if (previousTokens.size() > 3 && previousTokens[3].getText() == ";") n--; if (n < m_minArgCount || n > m_minArgCount + (int)m_optionalArgDefaults.size()) return false; else return true; } else return false; } bool isFinished(const std::vector &previousTokens, const Token &token) const { if (previousTokens.empty()) return false; return m_minArgCount == 0 && previousTokens.size() == 1 && token.getText() != "(" || previousTokens.back().getText() == ")"; } TokenType getTokenType(const std::vector &previousTokens, const Token &token) const { int i = (int)previousTokens.size(); if (i == 0) return Function; else if (i == 1 || token.getText() == ")") return Function; else if (i == 3) return token.getText() == ";" ? Comma : Comma; else if (i & 1) return Comma; else return InternalError; } void getArgs( std::vector &nodes, Calculator *calc, std::vector &stack, const std::vector &tokens) const { bool implicitArgUsed = m_implicitArgAllowed && tokens.size() > 3 && tokens[3].getText() == ";"; // n = number of arguments to provide (mandatory + optional + implicit) int n = m_minArgCount + (int)m_optionalArgDefaults.size() + (m_implicitArgAllowed ? 1 : 0); // m = number of default arguments to assign (with their default value) int m = n - (tokens.size() - 2) / 2; if (m_implicitArgAllowed && !implicitArgUsed) m--; assert(m <= (int)m_optionalArgDefaults.size()); if (m > (int)m_optionalArgDefaults.size()) m = (int)m_optionalArgDefaults.size(); nodes.resize(n); // fetch arguments from the stack int k = n - m; if (implicitArgUsed) { while (k > 0) nodes[--k] = popNode(stack); } else { while (k > 1) nodes[--k] = popNode(stack); nodes[0] = new VariableNode(calc, CalculatorNode::FRAME); } // add default values for (int i = 0; i < m; i++) nodes[n - m + i] = new NumberNode(calc, m_optionalArgDefaults[i]); } }; //------------------------------------------------------------------- template class F0Pattern : public FunctionPattern { public: F0Pattern(string functionName) : FunctionPattern(functionName, 0) {} void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { stack.push_back(new Op0Node(calc, m_functionName)); } }; //------------------------------------------------------------------- template class F1Pattern : public FunctionPattern { public: F1Pattern(string functionName, string descr = "") : FunctionPattern(functionName, 1) { setDescription(descr); } void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { stack.push_back(new Op1Node(calc, popNode(stack))); } }; //------------------------------------------------------------------- template class F2Pattern : public FunctionPattern { public: F2Pattern(string functionName, string descr = "") : FunctionPattern(functionName, 2) { setDescription(descr); } void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { CalculatorNode *b = popNode(stack); CalculatorNode *a = popNode(stack); stack.push_back(new Op2Node(calc, a, b)); } }; //------------------------------------------------------------------- template class F3Pattern : public FunctionPattern { public: F3Pattern(string functionName, string descr = "") : FunctionPattern(functionName, 3) { setDescription(descr); } void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { CalculatorNode *c = popNode(stack); CalculatorNode *b = popNode(stack); CalculatorNode *a = popNode(stack); stack.push_back(new Op3Node(calc, a, b, c)); } }; //------------------------------------------------------------------- template class Fs2Pattern : public FunctionPattern { public: Fs2Pattern(string functionName, string description) : FunctionPattern(functionName, 1) { allowImplicitArg(true); setDescription(description); } void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { std::vector nodes; getArgs(nodes, calc, stack, tokens); stack.push_back(new Op2Node(calc, nodes[0], nodes[1])); } }; //------------------------------------------------------------------- template class Fs3Pattern : public FunctionPattern { public: Fs3Pattern(string functionName, double defVal, string descr) : FunctionPattern(functionName, 1) { allowImplicitArg(true); addOptionalArg(defVal); setDescription(descr); } void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { std::vector nodes; getArgs(nodes, calc, stack, tokens); stack.push_back(new Op3Node(calc, nodes[0], nodes[1], nodes[2])); } }; //------------------------------------------------------------------- class CyclePattern : public FunctionPattern { public: CyclePattern(string functionName) : FunctionPattern(functionName, 1) { setDescription("cycle(period)\nCycles the transitions of the period previous frames to the selected range"); } void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { CalculatorNode *a = popNode(stack); stack.push_back(new CycleNode(calc, a)); } }; //------------------------------------------------------------------- class RandomPattern : public FunctionPattern { bool m_seed; public: RandomPattern(string functionName, bool seed, string description) : FunctionPattern(functionName, seed ? 1 : 0), m_seed(seed) { allowImplicitArg(true); addOptionalArg(0); addOptionalArg(0); setDescription(description); } void createNode(Calculator *calc, std::vector &stack, const std::vector &tokens) const { int n = ((int)tokens.size() - 1) / 2; if (m_seed) n--; RandomNode *randomNode = new RandomNode(calc); if (n > 0) { randomNode->setMax(popNode(stack)); if (n > 1) randomNode->setMin(popNode(stack)); } if (m_seed) randomNode->setSeed(popNode(stack)); stack.push_back(randomNode); } }; //=================================================================== class PatternTable { std::map m_kTable; std::vector m_uTable; Grammar::Position m_position; public: PatternTable(Grammar::Position position) : m_position(position) {} ~PatternTable() { for (std::map::iterator it = m_kTable.begin(); it != m_kTable.end(); ++it) delete it->second; for (std::vector::iterator it = m_uTable.begin(); it != m_uTable.end(); ++it) delete *it; } void addPattern(Pattern *pattern) { string keyword = pattern->getFirstKeyword(); if (keyword != "") { // first keyword should be unique assert(m_kTable.count(keyword) == 0); m_kTable[keyword] = pattern; } else m_uTable.push_back(pattern); } const Pattern *getPattern(const Token &token) const { std::vector tokens; if (m_position == Grammar::ExpressionEnd) tokens.push_back(Token()); if (token.getType() == Token::Punct || token.getType() == Token::Ident) { string keyword = token.getText(); std::map::const_iterator it = m_kTable.find(keyword); if (it != m_kTable.end()) { Pattern *pattern = it->second; if (pattern->matchToken(tokens, token)) { return pattern; } } } for (int i = 0; i < (int)m_uTable.size(); i++) { Pattern *pattern = m_uTable[i]; if (pattern->matchToken(tokens, token)) { return pattern; } } return 0; } void getSuggestions(Grammar::Suggestions &suggestions) const { std::map::const_iterator it; for (it = m_kTable.begin(); it != m_kTable.end(); ++it) { suggestions.push_back(std::make_pair(it->first, it->second->getDescription())); } for (int i = 0; i < (int)m_uTable.size(); i++) { std::vector keywords; m_uTable[i]->getAcceptableKeywords(keywords); for (int j = 0; j < (int)keywords.size(); j++) suggestions.push_back(std::make_pair(keywords[j], m_uTable[i]->getDescription())); } } }; //=================================================================== // // funzioni trigonometriche, log, exp, ecc. // //------------------------------------------------------------------- class Pow { public: double operator()(double x, double y) const { return pow(x, y); } }; // class Mod {public: double operator()(double x, double y) const {return (int)x % (int)y;} }; class Sin { public: double operator()(double x) const { return sin(toRad(x)); } }; class Cos { public: double operator()(double x) const { return cos(toRad(x)); } }; class Tan { public: double operator()(double x) const { return tan(toRad(x)); } }; class Sinh { public: double operator()(double x) const { return sinh(toRad(x)); } }; class Cosh { public: double operator()(double x) const { return cosh(toRad(x)); } }; class Tanh { public: double operator()(double x) const { return tanh(toRad(x)); } }; class Atan { public: double operator()(double x) const { return toDeg(atan(x)); } }; class Atan2 { public: double operator()(double x, double y) const { return toDeg(atan2(x, y)); } }; class Log { public: double operator()(double x) const { return log(x); } }; class Exp { public: double operator()(double x) const { return exp(x); } }; class Floor { public: double operator()(double x) const { return tfloor(x); } }; class Ceil { public: double operator()(double x) const { return tceil(x); } }; class Round { public: double operator()(double x) const { return tround(x); } }; class Abs { public: double operator()(double x) const { return fabs(x); } }; class Sign { public: double operator()(double x) const { return x > 0 ? 1 : x < 0 ? -1 : 0; } }; class Sqrt { public: double operator()(double x) const { return x >= 0.0 ? sqrt(x) : 0; } }; class Sqr { public: double operator()(double x) const { return x * x; } }; class Crop { public: double operator()(double x, double a, double b) const { return tcrop(x, a, b); } }; class Step { public: double operator()(double x, double y) const { return x < y ? 0 : 1; } }; class Mod { public: double operator()(double x, double y) const { if (y == 0.0) return 0; return x - y * floor(x / y); } }; class Min { public: double operator()(double x, double y) const { return x < y ? x : y; } }; class Max { public: double operator()(double x, double y) const { return x > y ? x : y; } }; class Gt { public: double operator()(double x, double y) const { return x > y ? 1 : 0; } }; class Ge { public: double operator()(double x, double y) const { return x >= y ? 1 : 0; } }; class Lt { public: double operator()(double x, double y) const { return x < y ? 1 : 0; } }; class Le { public: double operator()(double x, double y) const { return x <= y ? 1 : 0; } }; class Ne { public: double operator()(double x, double y) const { return x != y ? 1 : 0; } }; class Eq { public: double operator()(double x, double y) const { return x == y ? 1 : 0; } }; class And { public: double operator()(double x, double y) const { return (x != 0) && (y != 0) ? 1 : 0; } }; class Or { public: double operator()(double x, double y) const { return (x != 0) || (y != 0) ? 1 : 0; } }; class Not { public: double operator()(double x) const { return x == 0; } }; class Smoothstep { public: double operator()(double v, double min, double max) const { if (v <= min) return 0; else if (v >= max) return 1; double t = (v - min) / (max - min); return -2 * t * t * t + 3 * t * t; } }; class Pulse { public: double operator()(double x, double x0, double length) const { // double length=5.0; double b = (.69315 * 4.0) / (length * length); x -= x0; return exp(-x * x * b); } }; class Saw { public: double operator()(double x, double length, double height) const { if (length <= 0.0) return 0.0; if (height <= 0.0) height = length; double q = x / length; return height * (q - floor(q)); } }; class Wave { public: double operator()(double x, double length) const { if (length <= 0.0) return 0.0; return sin(x * 2 * PI / length); } }; //=================================================================== class Grammar::Imp { public: PatternTable m_prePatterns, m_postPatterns; Imp() : m_prePatterns(Grammar::ExpressionStart), m_postPatterns(Grammar::ExpressionEnd) { } ~Imp() {} }; Grammar::Grammar() : m_imp(new Imp()) { addPattern(new NumberPattern()); addPattern(new ConstantPattern("pi", PI, "3.14159265...")); addPattern(new VariablePattern("t", CalculatorNode::T, "ranges from 0.0 to 1.0 along the transition")); const string f_desc = "the current frame number"; addPattern(new VariablePattern("f", CalculatorNode::FRAME, f_desc)); addPattern(new VariablePattern("frame", CalculatorNode::FRAME, f_desc)); const string r_desc = "the current frame number, relative to the transition"; addPattern(new VariablePattern("r", CalculatorNode::RFRAME, r_desc)); addPattern(new VariablePattern("rframe", CalculatorNode::RFRAME, r_desc)); addPattern(new Op2Pattern>("+", 10)); addPattern(new Op2Pattern>("*", 20)); addPattern(new Op2Pattern("^", 30)); addPattern(new Op2Pattern>("-", 10)); addPattern(new Op2Pattern>("/", 20)); addPattern(new Op2Pattern("%", 8)); addPattern(new Op2Pattern(">", 6)); addPattern(new Op2Pattern(">=", 6)); addPattern(new Op2Pattern("<", 6)); addPattern(new Op2Pattern("<=", 6)); addPattern(new Op2Pattern("==", 6)); addPattern(new Op2Pattern("!=", 6)); addPattern(new Op2Pattern("&&", 3)); addPattern(new Op2Pattern("||", 2)); addPattern(new Op2Pattern("and", 3)); addPattern(new Op2Pattern("or", 2)); addPattern(new NotPattern("!", "not")); addPattern(new NotPattern("not", "")); addPattern(new UnaryMinusPattern()); addPattern(new BraketPattern()); addPattern(new QuestionTernaryPattern()); addPattern(new F1Pattern("sin", "sin(degree)")); addPattern(new F1Pattern("cos", "cos(degree)")); addPattern(new F1Pattern("tan", "tan(degree)")); addPattern(new F1Pattern("sinh", "sinh(degree)\nHyperbolic sine")); addPattern(new F1Pattern("cosh", "cosh(degree)\nHyperbolic cosine")); addPattern(new F1Pattern("tanh", "tanh(degree)\nHyperbolic tangent")); addPattern(new F1Pattern("atan", "atan(x)\nArctangent : the inverse of tan()")); addPattern(new F2Pattern("atan2", "atan2(y,x)\nThe counter-clockwise angle in degree between the x-axis and the point(x,y)")); addPattern(new F1Pattern("log", "log(x)\nThe natural logarithm of x (base e)")); addPattern(new F1Pattern("exp", "exp(x)\nThe base-e exponential of x")); addPattern(new F1Pattern("floor", "floor(x)\nThe greatest integer <= x")); const string ceil_desc = "The smallest integer >= x"; addPattern(new F1Pattern("ceil", "ceil(x)\n" + ceil_desc)); addPattern(new F1Pattern("ceiling", "ceiling(x)\n" + ceil_desc)); addPattern(new F1Pattern("round", "round(x)\nThe integer nearest to x")); addPattern(new F1Pattern("abs", "abs(x)\nThe absolute value of x")); addPattern(new F1Pattern("sign", "sign(x)\n-1 if x<0, 1 if x>0 and 0 if x=0")); const string sqrt_desc = "Square root of x"; addPattern(new F1Pattern("sqrt", "sqrt(x)\n" + sqrt_desc)); addPattern(new F1Pattern("sqr", "sqr(x)\n" + sqrt_desc)); addPattern(new F3Pattern("crop", "crop(x,a,b)\na if xb, x if x in [a,b]")); addPattern(new F3Pattern("clamp", "clamp(x,a,b)\na if xb, x if x in [a,b]")); addPattern(new F2Pattern("min", "min(a,b)")); addPattern(new F2Pattern("max", "max(a,b)")); addPattern(new F2Pattern("step", "min(x,x0)\n0 if x=x0")); addPattern(new F3Pattern("smoothstep", "smoothstep(x,x0)\n0 if x=x0\nas step, but with smooth transition")); const string pulse_desc = "Generates a bump ranging from 0.0 to 1.0 set at position pos"; addPattern(new Fs3Pattern("pulse", 0.5, "pulse(pos)\npulse(pos,length)\npulse(arg; pos)\npulse(arg;pos,length)\n" + pulse_desc)); addPattern(new Fs3Pattern("bump", 0.5, "bump(pos)\nbump(pos,length)\nbump(arg; pos)\nbump(arg;pos,length)\n" + pulse_desc)); const string saw_desc = "Generates a periodic sawtooth shaped curve"; addPattern(new Fs3Pattern("sawtooth", 0.0, "sawtooth(length)\nsawtooth(length, height)\nsawtooth(arg; length)\nsawtooth(arg; length, height)\n" + saw_desc)); addPattern(new Fs3Pattern("saw", 0.0, "saw(length)\nsaw(length, height)\nsaw(arg; length)\nsaw(arg; length, height)\n" + saw_desc)); addPattern(new Fs2Pattern("wave", "wave(_length)\nwave(_arg;_length)\nsame as sin(f*180/length)")); const string rnd_desc = "Generates random number between min and max"; addPattern(new RandomPattern("random", false, "random = random(0,1)\nrandom(max) = random(0,max)\nrandom(min,max)\n" + rnd_desc)); addPattern(new RandomPattern("rnd", false, "rnd = rnd(0,1)\nrnd(max) = rnd(0,max)\nrnd(min,max)\n" + rnd_desc)); const string rnd_s_desc = rnd_desc + "; seed select different random sequences"; addPattern(new RandomPattern("random_s", true, "random_s(seed) = random_s(seed, 0,1)\nrandom_s(seed,max) = random_s(seed, 0,max)\nrandom_s(seed,min,max)\n" + rnd_s_desc)); addPattern(new RandomPattern("rnd_s", true, "rnd_s(seed) = rnd_s(seed, 0,1)\nrnd_s(seed,max) = rnd_s(seed, 0,max)\nrnd_s(seed,min,max)\n" + rnd_s_desc)); addPattern(new CyclePattern("cycle")); } Grammar::~Grammar() { delete m_imp; } void Grammar::addPattern(Pattern *pattern) { std::vector noTokens; if (pattern->expressionExpected(noTokens)) m_imp->m_postPatterns.addPattern(pattern); else m_imp->m_prePatterns.addPattern(pattern); } const Pattern *Grammar::getPattern(Position position, const Token &token) const { Pattern *pattern = 0; if (position == ExpressionStart) return m_imp->m_prePatterns.getPattern(token); else return m_imp->m_postPatterns.getPattern(token); } void Grammar::getSuggestions(Grammar::Suggestions &suggestions, Position position) const { if (position == ExpressionStart) return m_imp->m_prePatterns.getSuggestions(suggestions); else return m_imp->m_postPatterns.getSuggestions(suggestions); } //=================================================================== } // namespace TSyntax