diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index f2ec0426be..14b3e9da87 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -151,6 +151,21 @@ AnimExpression::Token AnimExpression::consumeIdentifier(const QString& str, QStr return Token(QStringRef(const_cast(&str), pos, len)); } +// TODO: not very efficient or accruate, but it's close enough for now. +static float computeFractionalPart(int fractionalPart) +{ + float frac = (float)fractionalPart; + while (fractionalPart) { + fractionalPart /= 10; + frac /= 10.0f; + } + return frac; +} + +static float computeFloat(int whole, int fraction) { + return (float)whole + computeFractionalPart(fraction); +} + AnimExpression::Token AnimExpression::consumeNumber(const QString& str, QString::const_iterator& iter) const { assert(iter != str.end()); assert(iter->isDigit()); @@ -158,10 +173,31 @@ AnimExpression::Token AnimExpression::consumeNumber(const QString& str, QString: while (iter->isDigit() && iter != str.end()) { ++iter; } + + // parse whole integer part int pos = (int)(begin - str.begin()); int len = (int)(iter - begin); QString sub = QStringRef(const_cast(&str), pos, len).toString(); - return Token(sub.toInt()); + int whole = sub.toInt(); + + // parse optional fractional part + if (iter->unicode() == '.') { + iter++; + auto begin = iter; + while (iter->isDigit() && iter != str.end()) { + ++iter; + } + + int pos = (int)(begin - str.begin()); + int len = (int)(iter - begin); + QString sub = QStringRef(const_cast(&str), pos, len).toString(); + int fraction = sub.toInt(); + + return Token(computeFloat(whole, fraction)); + + } else { + return Token(whole); + } } AnimExpression::Token AnimExpression::consumeAnd(const QString& str, QString::const_iterator& iter) const { diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index a69b13c286..25e1803721 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -50,6 +50,7 @@ protected: Token(Type type) : type(type) {} Token(const QStringRef& strRef) : type(Type::Identifier), strVal(strRef.toString()) {} Token(int val) : type(Type::LiteralInt), intVal(val) {} + Token(float val) : type(Type::LiteralFloat), floatVal(val) {} Type type = End; QString strVal; int intVal; diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 08f13b7ec7..5b6806ec09 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -325,7 +325,7 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram triggers.clear(); void AnimTests::testTokenizer() { - QString str = "(10 + x) >= 20 && (y != !z)"; + QString str = "(10 + x) >= 20.1 && (y != !z)"; AnimExpression e(""); auto iter = str.cbegin(); AnimExpression::Token token = e.consumeToken(str, iter); @@ -343,8 +343,8 @@ void AnimTests::testTokenizer() { token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::GreaterThanEqual); token = e.consumeToken(str, iter); - QVERIFY(token.type == AnimExpression::Token::LiteralInt); - QVERIFY(token.intVal == 20); + QVERIFY(token.type == AnimExpression::Token::LiteralFloat); + QVERIFY(fabsf(token.floatVal - 20.1f) < 0.0001f); token = e.consumeToken(str, iter); QVERIFY(token.type == AnimExpression::Token::And); token = e.consumeToken(str, iter);