mirror of
https://github.com/lubosz/overte.git
synced 2025-05-29 16:40:16 +02:00
174 lines
7.2 KiB
C++
174 lines
7.2 KiB
C++
//
|
|
// AnimVariant.cpp
|
|
// library/animation
|
|
//
|
|
// Created by Howard Stearns on 10/15/15.
|
|
// Copyright (c) 2015 High Fidelity, Inc. All rights reserved.
|
|
// Copyright 2023 Overte e.V.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
#include "AnimVariant.h" // which has AnimVariant/AnimVariantMap
|
|
|
|
#include <ScriptEngine.h>
|
|
#include <QThread>
|
|
#include <ScriptValueIterator.h>
|
|
#include <ScriptValueUtils.h>
|
|
|
|
const AnimVariant AnimVariant::False = AnimVariant();
|
|
|
|
ScriptValue AnimVariantMap::animVariantMapToScriptValue(ScriptEngine* engine, const QStringList& names, bool useNames) const {
|
|
if (QThread::currentThread() != engine->thread()) {
|
|
qCWarning(animation) << "Cannot create Javacript object from non-script thread" << QThread::currentThread();
|
|
Q_ASSERT(false);
|
|
return ScriptValue();
|
|
}
|
|
ScriptValue target = engine->newObject();
|
|
auto setOne = [&] (const QString& name, const AnimVariant& value) {
|
|
switch (value.getType()) {
|
|
case AnimVariant::Type::Bool:
|
|
target.setProperty(name, value.getBool());
|
|
break;
|
|
case AnimVariant::Type::Int:
|
|
target.setProperty(name, value.getInt());
|
|
break;
|
|
case AnimVariant::Type::Float:
|
|
target.setProperty(name, value.getFloat());
|
|
break;
|
|
case AnimVariant::Type::String:
|
|
target.setProperty(name, value.getString());
|
|
break;
|
|
case AnimVariant::Type::Vec3:
|
|
target.setProperty(name, vec3ToScriptValue(engine, value.getVec3()));
|
|
break;
|
|
case AnimVariant::Type::Quat:
|
|
target.setProperty(name, quatToScriptValue(engine, value.getQuat()));
|
|
break;
|
|
default:
|
|
// Unknown type
|
|
assert(QString("AnimVariant::Type") == QString("valid"));
|
|
}
|
|
};
|
|
if (useNames) { // copy only the requested names
|
|
for (const QString& name : names) {
|
|
auto search = _map.find(name);
|
|
if (search != _map.end()) {
|
|
setOne(name, search->second);
|
|
} else if (_triggers.count(name) == 1) {
|
|
target.setProperty(name, true);
|
|
} // scripts are allowed to request names that do not exist
|
|
}
|
|
|
|
} else { // copy all of them
|
|
for (auto& pair : _map) {
|
|
setOne(pair.first, pair.second);
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
|
|
void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) {
|
|
for (auto& pair : other._map) {
|
|
_map[pair.first] = pair.second;
|
|
}
|
|
}
|
|
|
|
void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValue& source) {
|
|
if (QThread::currentThread() != source.engine()->thread()) {
|
|
qCWarning(animation) << "Cannot examine Javacript object from non-script thread" << QThread::currentThread();
|
|
Q_ASSERT(false);
|
|
return;
|
|
}
|
|
// This was here before, but marking as V8TODO
|
|
// POTENTIAL OPTIMIZATION: cache the types we've seen. I.e, keep a dictionary mapping property names to an enumeration of types.
|
|
// Whenever we identify a new outbound type in animVariantMapToScriptValue above, or a new inbound type in the code that follows here,
|
|
// we would enter it into the dictionary. Then switch on that type here, with the code that follow being executed only if
|
|
// the type is not known. One problem with that is that there is no checking that two different script use the same name differently.
|
|
ScriptValueIteratorPointer property(source.newIterator());
|
|
// Note: ScriptValueIterator iterates only over source's own properties. It does not follow the prototype chain.
|
|
while (property->hasNext()) {
|
|
property->next();
|
|
ScriptValue value = property->value();
|
|
if (value.isBool()) {
|
|
set(property->name(), value.toBool());
|
|
} else if (value.isString()) {
|
|
set(property->name(), value.toString());
|
|
} else if (value.isNumber()) {
|
|
int asInteger = value.toInt32();
|
|
float asFloat = value.toNumber();
|
|
if (asInteger == asFloat) {
|
|
set(property->name(), asInteger);
|
|
} else {
|
|
set(property->name(), asFloat);
|
|
}
|
|
} else { // Try to get x,y,z and possibly w
|
|
if (value.isObject()) {
|
|
ScriptValue x = value.property("x");
|
|
if (x.isNumber()) {
|
|
ScriptValue y = value.property("y");
|
|
if (y.isNumber()) {
|
|
ScriptValue z = value.property("z");
|
|
if (z.isNumber()) {
|
|
ScriptValue w = value.property("w");
|
|
if (w.isNumber()) {
|
|
set(property->name(), glm::quat(w.toNumber(), x.toNumber(), y.toNumber(), z.toNumber()));
|
|
} else {
|
|
set(property->name(), glm::vec3(x.toNumber(), y.toNumber(), z.toNumber()));
|
|
}
|
|
continue; // we got either a vector or quaternion object, so don't fall through to warning
|
|
}
|
|
}
|
|
}
|
|
}
|
|
qCWarning(animation) << "Ignoring unrecognized data " << value.toString() << " for animation property " << property->name();
|
|
//Q_ASSERT(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
std::map<QString, QString> AnimVariantMap::toDebugMap() const {
|
|
std::map<QString, QString> result;
|
|
for (auto& pair : _map) {
|
|
switch (pair.second.getType()) {
|
|
case AnimVariant::Type::Bool:
|
|
result[pair.first] = QString("%1").arg(pair.second.getBool());
|
|
break;
|
|
case AnimVariant::Type::Int:
|
|
result[pair.first] = QString("%1").arg(pair.second.getInt());
|
|
break;
|
|
case AnimVariant::Type::Float:
|
|
result[pair.first] = QString::number(pair.second.getFloat(), 'f', 3);
|
|
break;
|
|
case AnimVariant::Type::Vec3: {
|
|
// To prevent filling up debug stats, don't show vec3 values
|
|
glm::vec3 value = pair.second.getVec3();
|
|
result[pair.first] = QString("(%1, %2, %3)").
|
|
arg(QString::number(value.x, 'f', 3)).
|
|
arg(QString::number(value.y, 'f', 3)).
|
|
arg(QString::number(value.z, 'f', 3));
|
|
break;
|
|
}
|
|
case AnimVariant::Type::Quat: {
|
|
// To prevent filling up the anim stats, don't show quat values
|
|
glm::quat value = pair.second.getQuat();
|
|
result[pair.first] = QString("(%1, %2, %3, %4)").
|
|
arg(QString::number(value.x, 'f', 3)).
|
|
arg(QString::number(value.y, 'f', 3)).
|
|
arg(QString::number(value.z, 'f', 3)).
|
|
arg(QString::number(value.w, 'f', 3));
|
|
break;
|
|
}
|
|
case AnimVariant::Type::String:
|
|
// To prevent filling up anim stats, don't show string values
|
|
result[pair.first] = pair.second.getString();
|
|
break;
|
|
default:
|
|
// invalid AnimVariant::Type
|
|
assert(false);
|
|
}
|
|
}
|
|
return result;
|
|
}
|