mirror of
https://github.com/overte-org/overte.git
synced 2025-07-24 00:43:49 +02:00
First step toward evaluation
* added OpCodes * added first parser rules * removed mat4 support from AnimVariantMap
This commit is contained in:
parent
61d1dd00d1
commit
04d8a598da
6 changed files with 265 additions and 86 deletions
|
@ -16,23 +16,20 @@
|
||||||
|
|
||||||
AnimExpression::AnimExpression(const QString& str) :
|
AnimExpression::AnimExpression(const QString& str) :
|
||||||
_expression(str) {
|
_expression(str) {
|
||||||
parseExpression(_expression);
|
auto iter = str.begin();
|
||||||
|
parseExpression(_expression, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnimExpression::parseExpression(const QString& str) {
|
void AnimExpression::unconsumeToken(const Token& token) {
|
||||||
Token token(Token::End);
|
_tokenStack.push(token);
|
||||||
auto iter = str.begin();
|
|
||||||
do {
|
|
||||||
token = consumeToken(str, iter);
|
|
||||||
switch(token.type) {
|
|
||||||
case Token::Error:
|
|
||||||
case Token::End:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} while(iter != str.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimExpression::Token AnimExpression::consumeToken(const QString& str, QString::const_iterator& iter) const {
|
AnimExpression::Token AnimExpression::consumeToken(const QString& str, QString::const_iterator& iter) const {
|
||||||
|
if (!_tokenStack.empty()) {
|
||||||
|
Token top = _tokenStack.top();
|
||||||
|
_tokenStack.pop();
|
||||||
|
return top;
|
||||||
|
} else {
|
||||||
while (iter != str.end()) {
|
while (iter != str.end()) {
|
||||||
if (iter->isSpace()) {
|
if (iter->isSpace()) {
|
||||||
++iter;
|
++iter;
|
||||||
|
@ -62,12 +59,13 @@ AnimExpression::Token AnimExpression::consumeToken(const QString& str, QString::
|
||||||
}
|
}
|
||||||
return Token(Token::End);
|
return Token(Token::End);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AnimExpression::Token AnimExpression::consumeIdentifier(const QString& str, QString::const_iterator& iter) const {
|
AnimExpression::Token AnimExpression::consumeIdentifier(const QString& str, QString::const_iterator& iter) const {
|
||||||
assert(iter != str.end());
|
assert(iter != str.end());
|
||||||
assert(iter->isLetter());
|
assert(iter->isLetter());
|
||||||
auto begin = iter;
|
auto begin = iter;
|
||||||
while (iter->isLetter() && iter != str.end()) {
|
while ((iter->isLetter() || iter->isDigit()) && iter != str.end()) {
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
int pos = (int)(begin - str.begin());
|
int pos = (int)(begin - str.begin());
|
||||||
|
@ -185,3 +183,93 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co
|
||||||
return Token(Token::Not);
|
return Token(Token::Not);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AnimExpression::parseExpression(const QString& str, QString::const_iterator& iter) {
|
||||||
|
auto token = consumeToken(str, iter);
|
||||||
|
if (token.type == Token::Identifier) {
|
||||||
|
if (token.strVal == "true") {
|
||||||
|
_opCodes.push_back(OpCode {true});
|
||||||
|
} else if (token.strVal == "false") {
|
||||||
|
_opCodes.push_back(OpCode {false});
|
||||||
|
} else {
|
||||||
|
_opCodes.push_back(OpCode {token.strVal});
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (token.type == Token::Int) {
|
||||||
|
_opCodes.push_back(OpCode {token.intVal});
|
||||||
|
return true;
|
||||||
|
} else if (token.type == Token::Float) {
|
||||||
|
_opCodes.push_back(OpCode {token.floatVal});
|
||||||
|
return true;
|
||||||
|
} else if (token.type == Token::LeftParen) {
|
||||||
|
if (parseUnaryExpression(str, iter)) {
|
||||||
|
token = consumeToken(str, iter);
|
||||||
|
if (token.type != Token::RightParen) {
|
||||||
|
qCCritical(animation) << "Error parsing expression, expected ')'";
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
qCCritical(animation) << "Error parsing expression, unexpected symbol";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AnimExpression::parseUnaryExpression(const QString& str, QString::const_iterator& iter) {
|
||||||
|
auto token = consumeToken(str, iter);
|
||||||
|
if (token.type == Token::Plus) {
|
||||||
|
if (parseExpression(str, iter)) {
|
||||||
|
_opCodes.push_back(OpCode {OpCode::UnaryPlus});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (token.type == Token::Minus) {
|
||||||
|
if (parseExpression(str, iter)) {
|
||||||
|
_opCodes.push_back(OpCode {OpCode::UnaryMinus});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (token.type == Token::Not) {
|
||||||
|
if (parseExpression(str, iter)) {
|
||||||
|
_opCodes.push_back(OpCode {OpCode::Not});
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unconsumeToken(token);
|
||||||
|
return parseExpression(str, iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimExpression::OpCode AnimExpression::evaluate(const AnimVariantMap& map) const {
|
||||||
|
std::stack<OpCode> stack;
|
||||||
|
for (auto& opCode : _opCodes) {
|
||||||
|
switch (opCode.type) {
|
||||||
|
case OpCode::Identifier:
|
||||||
|
case OpCode::Int:
|
||||||
|
case OpCode::Float:
|
||||||
|
stack.push(opCode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
switch (opCode.type) {
|
||||||
|
case OpCode::Not:
|
||||||
|
evalNot(map, stack);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack.top();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimExpression::evalNot(const AnimVariantMap& map, std::stack<OpCode>& stack) const {
|
||||||
|
bool lhs = stack.top().coerceBool(map);
|
||||||
|
stack.pop();
|
||||||
|
stack.push(OpCode {!lhs});
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
#include <stack>
|
||||||
|
#include <vector>
|
||||||
|
#include "AnimVariant.h"
|
||||||
|
|
||||||
class AnimExpression {
|
class AnimExpression {
|
||||||
public:
|
public:
|
||||||
|
@ -44,15 +47,64 @@ protected:
|
||||||
Comma,
|
Comma,
|
||||||
Error
|
Error
|
||||||
};
|
};
|
||||||
Token(Type type) : type(type) {}
|
Token(Type type) : type {type} {}
|
||||||
Token(const QStringRef& strRef) : type(Type::Identifier), strVal(strRef.toString()) {}
|
Token(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {}
|
||||||
Token(int val) : type(Type::Int), intVal(val) {}
|
Token(int val) : type {Type::Int}, intVal {val} {}
|
||||||
Token(float val) : type(Type::Float), floatVal(val) {}
|
Token(float val) : type {Type::Float}, floatVal {val} {}
|
||||||
Type type = End;
|
Type type {End};
|
||||||
QString strVal;
|
QString strVal;
|
||||||
int intVal;
|
int intVal {0};
|
||||||
float floatVal;
|
float floatVal {0.0f};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct OpCode {
|
||||||
|
enum Type {
|
||||||
|
Identifier,
|
||||||
|
Bool,
|
||||||
|
Int,
|
||||||
|
Float,
|
||||||
|
And,
|
||||||
|
Or,
|
||||||
|
GreaterThan,
|
||||||
|
GreaterThanEqual,
|
||||||
|
LessThan,
|
||||||
|
LessThanEqual,
|
||||||
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
LeftParen,
|
||||||
|
RightParen,
|
||||||
|
Not,
|
||||||
|
Minus,
|
||||||
|
Plus,
|
||||||
|
Multiply,
|
||||||
|
Modulus,
|
||||||
|
UnaryPlus,
|
||||||
|
UnaryMinus
|
||||||
|
};
|
||||||
|
OpCode(Type type) : type {type} {}
|
||||||
|
OpCode(const QStringRef& strRef) : type {Type::Identifier}, strVal {strRef.toString()} {}
|
||||||
|
OpCode(const QString& str) : type {Type::Identifier}, strVal {str} {}
|
||||||
|
OpCode(int val) : type {Type::Int}, intVal {val} {}
|
||||||
|
OpCode(bool val) : type {Type::Bool}, intVal {(int)val} {}
|
||||||
|
OpCode(float val) : type {Type::Float}, floatVal {val} {}
|
||||||
|
|
||||||
|
bool coerceBool(const AnimVariantMap& map) const {
|
||||||
|
if (type == Int || type == Bool) {
|
||||||
|
return intVal != 0;
|
||||||
|
} else if (type == Identifier) {
|
||||||
|
return map.lookup(strVal, false);
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type {Int};
|
||||||
|
QString strVal;
|
||||||
|
int intVal {0};
|
||||||
|
float floatVal {0.0f};
|
||||||
|
};
|
||||||
|
|
||||||
|
void unconsumeToken(const Token& token);
|
||||||
Token consumeToken(const QString& str, QString::const_iterator& iter) const;
|
Token consumeToken(const QString& str, QString::const_iterator& iter) const;
|
||||||
Token consumeIdentifier(const QString& str, QString::const_iterator& iter) const;
|
Token consumeIdentifier(const QString& str, QString::const_iterator& iter) const;
|
||||||
Token consumeNumber(const QString& str, QString::const_iterator& iter) const;
|
Token consumeNumber(const QString& str, QString::const_iterator& iter) const;
|
||||||
|
@ -62,9 +114,16 @@ protected:
|
||||||
Token consumeLessThan(const QString& str, QString::const_iterator& iter) const;
|
Token consumeLessThan(const QString& str, QString::const_iterator& iter) const;
|
||||||
Token consumeNot(const QString& str, QString::const_iterator& iter) const;
|
Token consumeNot(const QString& str, QString::const_iterator& iter) const;
|
||||||
|
|
||||||
bool parseExpression(const QString& str);
|
bool parseExpression(const QString& str, QString::const_iterator& iter);
|
||||||
|
bool parseUnaryExpression(const QString& str, QString::const_iterator& iter);
|
||||||
|
|
||||||
|
OpCode evaluate(const AnimVariantMap& map) const;
|
||||||
|
void evalNot(const AnimVariantMap& map, std::stack<OpCode>& stack) const;
|
||||||
|
|
||||||
QString _expression;
|
QString _expression;
|
||||||
|
mutable std::stack<Token> _tokenStack;
|
||||||
|
std::vector<OpCode> _opCodes;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <QScriptValue>
|
#include <QScriptValue>
|
||||||
|
#include <StreamUtils.h>
|
||||||
|
#include <GLMHelpers.h>
|
||||||
#include "AnimationLogging.h"
|
#include "AnimationLogging.h"
|
||||||
#include "StreamUtils.h"
|
|
||||||
|
|
||||||
class AnimVariant {
|
class AnimVariant {
|
||||||
public:
|
public:
|
||||||
|
@ -29,7 +30,6 @@ public:
|
||||||
Float,
|
Float,
|
||||||
Vec3,
|
Vec3,
|
||||||
Quat,
|
Quat,
|
||||||
Mat4,
|
|
||||||
String,
|
String,
|
||||||
NumTypes
|
NumTypes
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,6 @@ public:
|
||||||
AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; }
|
AnimVariant(float value) : _type(Type::Float) { _val.floats[0] = value; }
|
||||||
AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast<glm::vec3*>(&_val) = value; }
|
AnimVariant(const glm::vec3& value) : _type(Type::Vec3) { *reinterpret_cast<glm::vec3*>(&_val) = value; }
|
||||||
AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast<glm::quat*>(&_val) = value; }
|
AnimVariant(const glm::quat& value) : _type(Type::Quat) { *reinterpret_cast<glm::quat*>(&_val) = value; }
|
||||||
AnimVariant(const glm::mat4& value) : _type(Type::Mat4) { *reinterpret_cast<glm::mat4*>(&_val) = value; }
|
|
||||||
AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; }
|
AnimVariant(const QString& value) : _type(Type::String) { _stringVal = value; }
|
||||||
|
|
||||||
bool isBool() const { return _type == Type::Bool; }
|
bool isBool() const { return _type == Type::Bool; }
|
||||||
|
@ -48,7 +47,6 @@ public:
|
||||||
bool isFloat() const { return _type == Type::Float; }
|
bool isFloat() const { return _type == Type::Float; }
|
||||||
bool isVec3() const { return _type == Type::Vec3; }
|
bool isVec3() const { return _type == Type::Vec3; }
|
||||||
bool isQuat() const { return _type == Type::Quat; }
|
bool isQuat() const { return _type == Type::Quat; }
|
||||||
bool isMat4() const { return _type == Type::Mat4; }
|
|
||||||
bool isString() const { return _type == Type::String; }
|
bool isString() const { return _type == Type::String; }
|
||||||
Type getType() const { return _type; }
|
Type getType() const { return _type; }
|
||||||
|
|
||||||
|
@ -57,17 +55,52 @@ public:
|
||||||
void setFloat(float value) { assert(_type == Type::Float); _val.floats[0] = value; }
|
void setFloat(float value) { assert(_type == Type::Float); _val.floats[0] = value; }
|
||||||
void setVec3(const glm::vec3& value) { assert(_type == Type::Vec3); *reinterpret_cast<glm::vec3*>(&_val) = value; }
|
void setVec3(const glm::vec3& value) { assert(_type == Type::Vec3); *reinterpret_cast<glm::vec3*>(&_val) = value; }
|
||||||
void setQuat(const glm::quat& value) { assert(_type == Type::Quat); *reinterpret_cast<glm::quat*>(&_val) = value; }
|
void setQuat(const glm::quat& value) { assert(_type == Type::Quat); *reinterpret_cast<glm::quat*>(&_val) = value; }
|
||||||
void setMat4(const glm::mat4& value) { assert(_type == Type::Mat4); *reinterpret_cast<glm::mat4*>(&_val) = value; }
|
|
||||||
void setString(const QString& value) { assert(_type == Type::String); _stringVal = value; }
|
void setString(const QString& value) { assert(_type == Type::String); _stringVal = value; }
|
||||||
|
|
||||||
bool getBool() const { assert(_type == Type::Bool); return _val.boolVal; }
|
bool getBool() const {
|
||||||
int getInt() const { assert(_type == Type::Int || _type == Type::Float); return _type == Type::Float ? (int)_val.floats[0] : _val.intVal; }
|
if (_type == Type::Bool) {
|
||||||
float getFloat() const { assert(_type == Type::Float || _type == Type::Int); return _type == Type::Int ? (float)_val.intVal : _val.floats[0]; }
|
return _val.boolVal;
|
||||||
|
} else if (_type == Type::Int) {
|
||||||
const glm::vec3& getVec3() const { assert(_type == Type::Vec3); return *reinterpret_cast<const glm::vec3*>(&_val); }
|
return _val.intVal != 0;
|
||||||
const glm::quat& getQuat() const { assert(_type == Type::Quat); return *reinterpret_cast<const glm::quat*>(&_val); }
|
} else {
|
||||||
const glm::mat4& getMat4() const { assert(_type == Type::Mat4); return *reinterpret_cast<const glm::mat4*>(&_val); }
|
return false;
|
||||||
const QString& getString() const { assert(_type == Type::String); return _stringVal; }
|
}
|
||||||
|
}
|
||||||
|
int getInt() const {
|
||||||
|
if (_type == Type::Int) {
|
||||||
|
return _val.intVal;
|
||||||
|
} else if (_type == Type::Float) {
|
||||||
|
return (int)_val.floats[0];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float getFloat() const {
|
||||||
|
if (_type == Type::Float) {
|
||||||
|
return _val.floats[0];
|
||||||
|
} else if (_type == Type::Int) {
|
||||||
|
return (float)_val.intVal;
|
||||||
|
} else {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const glm::vec3& getVec3() const {
|
||||||
|
if (_type == Type::Vec3) {
|
||||||
|
return *reinterpret_cast<const glm::vec3*>(&_val);
|
||||||
|
} else {
|
||||||
|
return Vectors::ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const glm::quat& getQuat() const {
|
||||||
|
if (_type == Type::Quat) {
|
||||||
|
return *reinterpret_cast<const glm::quat*>(&_val);
|
||||||
|
} else {
|
||||||
|
return Quaternions::IDENTITY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const QString& getString() const {
|
||||||
|
return _stringVal;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Type _type;
|
Type _type;
|
||||||
|
@ -75,7 +108,7 @@ protected:
|
||||||
union {
|
union {
|
||||||
bool boolVal;
|
bool boolVal;
|
||||||
int intVal;
|
int intVal;
|
||||||
float floats[16];
|
float floats[4];
|
||||||
} _val;
|
} _val;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,15 +163,6 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const glm::mat4& lookup(const QString& key, const glm::mat4& defaultValue) const {
|
|
||||||
if (key.isEmpty()) {
|
|
||||||
return defaultValue;
|
|
||||||
} else {
|
|
||||||
auto iter = _map.find(key);
|
|
||||||
return iter != _map.end() ? iter->second.getMat4() : defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString& lookup(const QString& key, const QString& defaultValue) const {
|
const QString& lookup(const QString& key, const QString& defaultValue) const {
|
||||||
if (key.isEmpty()) {
|
if (key.isEmpty()) {
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
|
@ -153,7 +177,6 @@ public:
|
||||||
void set(const QString& key, float value) { _map[key] = AnimVariant(value); }
|
void set(const QString& key, float value) { _map[key] = AnimVariant(value); }
|
||||||
void set(const QString& key, const glm::vec3& value) { _map[key] = AnimVariant(value); }
|
void set(const QString& key, const glm::vec3& value) { _map[key] = AnimVariant(value); }
|
||||||
void set(const QString& key, const glm::quat& value) { _map[key] = AnimVariant(value); }
|
void set(const QString& key, const glm::quat& value) { _map[key] = AnimVariant(value); }
|
||||||
void set(const QString& key, const glm::mat4& value) { _map[key] = AnimVariant(value); }
|
|
||||||
void set(const QString& key, const QString& value) { _map[key] = AnimVariant(value); }
|
void set(const QString& key, const QString& value) { _map[key] = AnimVariant(value); }
|
||||||
void unset(const QString& key) { _map.erase(key); }
|
void unset(const QString& key) { _map.erase(key); }
|
||||||
|
|
||||||
|
@ -189,9 +212,6 @@ public:
|
||||||
case AnimVariant::Type::Quat:
|
case AnimVariant::Type::Quat:
|
||||||
qCDebug(animation) << " " << pair.first << "=" << pair.second.getQuat();
|
qCDebug(animation) << " " << pair.first << "=" << pair.second.getQuat();
|
||||||
break;
|
break;
|
||||||
case AnimVariant::Type::Mat4:
|
|
||||||
qCDebug(animation) << " " << pair.first << "=" << pair.second.getMat4();
|
|
||||||
break;
|
|
||||||
case AnimVariant::Type::String:
|
case AnimVariant::Type::String:
|
||||||
qCDebug(animation) << " " << pair.first << "=" << pair.second.getString();
|
qCDebug(animation) << " " << pair.first << "=" << pair.second.getString();
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -80,6 +80,7 @@ public:
|
||||||
static const vec3& RIGHT;
|
static const vec3& RIGHT;
|
||||||
static const vec3& UP;
|
static const vec3& UP;
|
||||||
static const vec3& FRONT;
|
static const vec3& FRONT;
|
||||||
|
static const vec3 ZERO4;
|
||||||
};
|
};
|
||||||
|
|
||||||
// These pack/unpack functions are designed to start specific known types in as efficient a manner
|
// These pack/unpack functions are designed to start specific known types in as efficient a manner
|
||||||
|
|
|
@ -195,10 +195,7 @@ void AnimTests::testVariant() {
|
||||||
auto floatVarNegative = AnimVariant(-1.0f);
|
auto floatVarNegative = AnimVariant(-1.0f);
|
||||||
auto vec3Var = AnimVariant(glm::vec3(1.0f, -2.0f, 3.0f));
|
auto vec3Var = AnimVariant(glm::vec3(1.0f, -2.0f, 3.0f));
|
||||||
auto quatVar = AnimVariant(glm::quat(1.0f, 2.0f, -3.0f, 4.0f));
|
auto quatVar = AnimVariant(glm::quat(1.0f, 2.0f, -3.0f, 4.0f));
|
||||||
auto mat4Var = AnimVariant(glm::mat4(glm::vec4(1.0f, 2.0f, 3.0f, 4.0f),
|
|
||||||
glm::vec4(5.0f, 6.0f, -7.0f, 8.0f),
|
|
||||||
glm::vec4(9.0f, 10.0f, 11.0f, 12.0f),
|
|
||||||
glm::vec4(13.0f, 14.0f, 15.0f, 16.0f)));
|
|
||||||
QVERIFY(defaultVar.isBool());
|
QVERIFY(defaultVar.isBool());
|
||||||
QVERIFY(defaultVar.getBool() == false);
|
QVERIFY(defaultVar.getBool() == false);
|
||||||
|
|
||||||
|
@ -233,12 +230,6 @@ void AnimTests::testVariant() {
|
||||||
QVERIFY(q.x == 2.0f);
|
QVERIFY(q.x == 2.0f);
|
||||||
QVERIFY(q.y == -3.0f);
|
QVERIFY(q.y == -3.0f);
|
||||||
QVERIFY(q.z == 4.0f);
|
QVERIFY(q.z == 4.0f);
|
||||||
|
|
||||||
QVERIFY(mat4Var.isMat4());
|
|
||||||
auto m = mat4Var.getMat4();
|
|
||||||
QVERIFY(m[0].x == 1.0f);
|
|
||||||
QVERIFY(m[1].z == -7.0f);
|
|
||||||
QVERIFY(m[3].w == 16.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimTests::testAccumulateTime() {
|
void AnimTests::testAccumulateTime() {
|
||||||
|
@ -323,10 +314,11 @@ void AnimTests::testAccumulateTimeWithParameters(float startFrame, float endFram
|
||||||
QVERIFY(resultFrame == startFrame + 0.5f);
|
QVERIFY(resultFrame == startFrame + 0.5f);
|
||||||
QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop");
|
QVERIFY(!triggers.empty() && triggers[0] == "testNodeOnLoop");
|
||||||
triggers.clear();
|
triggers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void AnimTests::testTokenizer() {
|
void AnimTests::testExpressionTokenizer() {
|
||||||
QString str = "(10 + x) >= 20.1 && (y != !z)";
|
QString str = "(10 + x) >= 20.1 && (y != !z)";
|
||||||
AnimExpression e("");
|
AnimExpression e("x");
|
||||||
auto iter = str.cbegin();
|
auto iter = str.cbegin();
|
||||||
AnimExpression::Token token = e.consumeToken(str, iter);
|
AnimExpression::Token token = e.consumeToken(str, iter);
|
||||||
QVERIFY(token.type == AnimExpression::Token::LeftParen);
|
QVERIFY(token.type == AnimExpression::Token::LeftParen);
|
||||||
|
@ -364,3 +356,21 @@ void AnimTests::testTokenizer() {
|
||||||
token = e.consumeToken(str, iter);
|
token = e.consumeToken(str, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimTests::testExpressionParser() {
|
||||||
|
QString str = "(!x)";
|
||||||
|
AnimExpression e(str);
|
||||||
|
QVERIFY(e._opCodes.size() == 2);
|
||||||
|
if (e._opCodes.size() == 2) {
|
||||||
|
QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Identifier);
|
||||||
|
QVERIFY(e._opCodes[0].strVal == "x");
|
||||||
|
QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Not);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vars = AnimVariantMap();
|
||||||
|
vars.set("x", false);
|
||||||
|
|
||||||
|
auto opCode = e.evaluate(vars);
|
||||||
|
QVERIFY(opCode.type == AnimExpression::OpCode::Bool);
|
||||||
|
QVERIFY(opCode.coerceBool(vars) == true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ private slots:
|
||||||
void testLoader();
|
void testLoader();
|
||||||
void testVariant();
|
void testVariant();
|
||||||
void testAccumulateTime();
|
void testAccumulateTime();
|
||||||
void testTokenizer();
|
void testExpressionTokenizer();
|
||||||
|
void testExpressionParser();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AnimTests_h
|
#endif // hifi_AnimTests_h
|
||||||
|
|
Loading…
Reference in a new issue