mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
WIP checkpoint
This commit is contained in:
parent
af2b3bb9d5
commit
eacc2cae0c
7 changed files with 140 additions and 176 deletions
|
@ -66,7 +66,7 @@ function kneelDown() {
|
|||
function standUp() {
|
||||
kneeling = false;
|
||||
|
||||
MyAvatar.stopAnimation(KNEEL_ANIM_URL);
|
||||
MyAvatar.stopAnimation();
|
||||
|
||||
Overlays.editOverlay(standUpButton, { visible: false });
|
||||
Overlays.editOverlay(kneelDownButton, { visible: true });
|
||||
|
|
|
@ -4294,10 +4294,6 @@ void Application::stopAllScripts(bool restart) {
|
|||
it.value()->stop();
|
||||
qCDebug(interfaceapp) << "stopping script..." << it.key();
|
||||
}
|
||||
// HACK: ATM scripts cannot set/get their animation priorities, so we clear priorities
|
||||
// whenever a script stops in case it happened to have been setting joint rotations.
|
||||
// TODO: expose animation priorities and provide a layered animation control system.
|
||||
getMyAvatar()->clearJointAnimationPriorities();
|
||||
getMyAvatar()->clearScriptableSettings();
|
||||
}
|
||||
|
||||
|
@ -4313,10 +4309,6 @@ bool Application::stopScript(const QString& scriptHash, bool restart) {
|
|||
scriptEngine->stop();
|
||||
stoppedScript = true;
|
||||
qCDebug(interfaceapp) << "stopping script..." << scriptHash;
|
||||
// HACK: ATM scripts cannot set/get their animation priorities, so we clear priorities
|
||||
// whenever a script stops in case it happened to have been setting joint rotations.
|
||||
// TODO: expose animation priorities and provide a layered animation control system.
|
||||
getMyAvatar()->clearJointAnimationPriorities();
|
||||
}
|
||||
if (_scriptEnginesHash.empty()) {
|
||||
getMyAvatar()->clearScriptableSettings();
|
||||
|
|
|
@ -666,65 +666,47 @@ void MyAvatar::startAnimation(const QString& url, float fps, bool loop, float fi
|
|||
_rig->startAnimation(url, fps, loop, firstFrame, lastFrame);
|
||||
}
|
||||
|
||||
void MyAvatar::startAnimationByRole(const QString& role, const QString& url, float fps, float priority,
|
||||
bool loop, bool hold, float firstFrame, float lastFrame, const QStringList& maskedJoints) {
|
||||
void MyAvatar::stopAnimation() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "startAnimationByRole", Q_ARG(const QString&, role), Q_ARG(const QString&, url),
|
||||
Q_ARG(float, fps), Q_ARG(float, priority), Q_ARG(bool, loop), Q_ARG(bool, hold), Q_ARG(float, firstFrame),
|
||||
Q_ARG(float, lastFrame), Q_ARG(const QStringList&, maskedJoints));
|
||||
QMetaObject::invokeMethod(this, "stopAnimation");
|
||||
return;
|
||||
}
|
||||
_rig->startAnimationByRole(role, url, fps, priority, loop, hold, firstFrame, lastFrame, maskedJoints);
|
||||
_rig->stopAnimation();
|
||||
}
|
||||
|
||||
void MyAvatar::stopAnimationByRole(const QString& role) {
|
||||
QStringList MyAvatar::getAnimationRoles() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "stopAnimationByRole", Q_ARG(const QString&, role));
|
||||
return;
|
||||
}
|
||||
_rig->stopAnimationByRole(role);
|
||||
}
|
||||
|
||||
void MyAvatar::stopAnimation(const QString& url) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "stopAnimation", Q_ARG(const QString&, url));
|
||||
return;
|
||||
}
|
||||
_rig->stopAnimation(url);
|
||||
}
|
||||
|
||||
AnimationDetails MyAvatar::getAnimationDetailsByRole(const QString& role) {
|
||||
AnimationDetails result;
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "getAnimationDetailsByRole", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(AnimationDetails, result),
|
||||
Q_ARG(const QString&, role));
|
||||
QStringList result;
|
||||
QMetaObject::invokeMethod(this, "getAnimationRoles", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QStringList, result));
|
||||
return result;
|
||||
}
|
||||
foreach (const AnimationHandlePointer& handle, _rig->getRunningAnimations()) {
|
||||
if (handle->getRole() == role) {
|
||||
result = handle->getAnimationDetails();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return _rig->getAnimationRoles();
|
||||
}
|
||||
|
||||
AnimationDetails MyAvatar::getAnimationDetails(const QString& url) {
|
||||
AnimationDetails result;
|
||||
void MyAvatar::overrideAnimationRole(const QString& role, const QString& url, float fps, bool loop,
|
||||
float firstFrame, float lastFrame) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "getAnimationDetails", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(AnimationDetails, result),
|
||||
Q_ARG(const QString&, url));
|
||||
return result;
|
||||
QMetaObject::invokeMethod(this, "overrideAnimationRole", Q_ARG(const QString&, role), Q_ARG(const QString&, url),
|
||||
Q_ARG(float, fps), Q_ARG(bool, loop), Q_ARG(float, firstFrame), Q_ARG(float, lastFrame));
|
||||
return;
|
||||
}
|
||||
foreach (const AnimationHandlePointer& handle, _rig->getRunningAnimations()) {
|
||||
if (handle->getURL() == url) {
|
||||
result = handle->getAnimationDetails();
|
||||
break;
|
||||
}
|
||||
_rig->overrideAnimationRole(role, url, fps, loop, firstFrame, lastFrame);
|
||||
}
|
||||
|
||||
void MyAvatar::restoreAnimationRole(const QString& role) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "restoreAnimationRole", Q_ARG(const QString&, role));
|
||||
return;
|
||||
}
|
||||
return result;
|
||||
_rig->restoreAnimationRole(role);
|
||||
}
|
||||
|
||||
void MyAvatar::prefetchAnimation(const QString& url) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "prefetchAnimation", Q_ARG(const QString&, url));
|
||||
return;
|
||||
}
|
||||
_rig->prefetchAnimation(url);
|
||||
}
|
||||
|
||||
void MyAvatar::saveData() {
|
||||
|
@ -797,6 +779,7 @@ float loadSetting(QSettings& settings, const char* name, float defaultValue) {
|
|||
// If we demand the animation from the update thread while we're locked, we'll deadlock.
|
||||
// Until we untangle this, code puts the updates back on the main thread temporarilly and starts all the loading.
|
||||
void MyAvatar::safelyLoadAnimations() {
|
||||
/*
|
||||
_rig->addAnimationByRole("idle");
|
||||
_rig->addAnimationByRole("walk");
|
||||
_rig->addAnimationByRole("backup");
|
||||
|
@ -804,6 +787,7 @@ void MyAvatar::safelyLoadAnimations() {
|
|||
_rig->addAnimationByRole("rightTurn");
|
||||
_rig->addAnimationByRole("leftStrafe");
|
||||
_rig->addAnimationByRole("rightStrafe");
|
||||
*/
|
||||
}
|
||||
|
||||
void MyAvatar::setEnableRigAnimations(bool isEnabled) {
|
||||
|
@ -905,23 +889,6 @@ void MyAvatar::loadData() {
|
|||
settings.endArray();
|
||||
setAttachmentData(attachmentData);
|
||||
|
||||
int animationCount = settings.beginReadArray("animationHandles");
|
||||
_rig->deleteAnimations();
|
||||
for (int i = 0; i < animationCount; i++) {
|
||||
settings.setArrayIndex(i);
|
||||
_rig->addAnimationByRole(settings.value("role", "idle").toString(),
|
||||
settings.value("url").toString(),
|
||||
loadSetting(settings, "fps", 30.0f),
|
||||
loadSetting(settings, "priority", 1.0f),
|
||||
settings.value("loop", true).toBool(),
|
||||
settings.value("hold", false).toBool(),
|
||||
settings.value("firstFrame", 0.0f).toFloat(),
|
||||
settings.value("lastFrame", INT_MAX).toFloat(),
|
||||
settings.value("maskedJoints").toStringList(),
|
||||
settings.value("startAutomatically", true).toBool());
|
||||
}
|
||||
settings.endArray();
|
||||
|
||||
setDisplayName(settings.value("displayName").toString());
|
||||
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||
|
||||
|
@ -1177,14 +1144,7 @@ void MyAvatar::clearJointData(int index) {
|
|||
}
|
||||
|
||||
void MyAvatar::clearJointsData() {
|
||||
clearJointAnimationPriorities();
|
||||
}
|
||||
|
||||
void MyAvatar::clearJointAnimationPriorities() {
|
||||
int numStates = _skeletonModel.getJointStateCount();
|
||||
for (int i = 0; i < numStates; ++i) {
|
||||
_rig->clearJointAnimationPriority(i);
|
||||
}
|
||||
//clearJointAnimationPriorities();
|
||||
}
|
||||
|
||||
void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
|
@ -1382,7 +1342,6 @@ void MyAvatar::setScriptedMotorFrame(QString frame) {
|
|||
}
|
||||
|
||||
void MyAvatar::clearScriptableSettings() {
|
||||
clearJointAnimationPriorities();
|
||||
_scriptedMotorVelocity = glm::vec3(0.0f);
|
||||
_scriptedMotorTimescale = DEFAULT_SCRIPTED_MOTOR_TIMESCALE;
|
||||
}
|
||||
|
|
|
@ -117,22 +117,25 @@ public:
|
|||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _rig->getAnimationHandles(); }
|
||||
AnimationHandlePointer addAnimationHandle() { return _rig->createAnimationHandle(); }
|
||||
void removeAnimationHandle(const AnimationHandlePointer& handle) { _rig->removeAnimationHandle(handle); }
|
||||
/// Allows scripts to run animations.
|
||||
|
||||
// Interrupt the current animation with a custom animation.
|
||||
Q_INVOKABLE void startAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
|
||||
/// Stops an animation as identified by a URL.
|
||||
Q_INVOKABLE void stopAnimation(const QString& url);
|
||||
// Stops the animation that was started with startAnimation and go back to the standard animation.
|
||||
Q_INVOKABLE void stopAnimation();
|
||||
|
||||
// Returns a list of all clips that are available
|
||||
Q_INVOKABLE QStringList getAnimationRoles();
|
||||
|
||||
// Replace an existing standard role animation with a custom one.
|
||||
Q_INVOKABLE void overrideAnimationRole(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
|
||||
// remove an animation role override and return to the standard animation.
|
||||
Q_INVOKABLE void restoreAnimationRole(const QString& role);
|
||||
|
||||
// prefetch animation
|
||||
Q_INVOKABLE void prefetchAnimation(const QString& url);
|
||||
|
||||
/// Starts an animation by its role, using the provided URL and parameters if the avatar doesn't have a custom
|
||||
/// animation for the role.
|
||||
Q_INVOKABLE void startAnimationByRole(const QString& role, const QString& url = QString(), float fps = 30.0f,
|
||||
float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f,
|
||||
float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList());
|
||||
/// Stops an animation identified by its role.
|
||||
Q_INVOKABLE void stopAnimationByRole(const QString& role);
|
||||
Q_INVOKABLE AnimationDetails getAnimationDetailsByRole(const QString& role);
|
||||
Q_INVOKABLE AnimationDetails getAnimationDetails(const QString& url);
|
||||
void clearJointAnimationPriorities();
|
||||
// Adds handler(animStateDictionaryIn) => animStateDictionaryOut, which will be invoked just before each animGraph state update.
|
||||
// The handler will be called with an animStateDictionaryIn that has all those properties specified by the (possibly empty)
|
||||
// propertiesList argument. However for debugging, if the properties argument is null, all internal animGraph state is provided.
|
||||
|
|
|
@ -33,7 +33,7 @@ class QJsonObject;
|
|||
// * evaluate method, perform actual joint manipulations here and return result by reference.
|
||||
// Also, append any triggers that are detected during evaluation.
|
||||
|
||||
class AnimNode {
|
||||
class AnimNode : public std::enable_shared_from_this<AnimNode> {
|
||||
public:
|
||||
enum class Type {
|
||||
Clip = 0,
|
||||
|
@ -78,6 +78,30 @@ public:
|
|||
|
||||
void setCurrentFrame(float frame);
|
||||
|
||||
template <typename F>
|
||||
bool traverse(F func) {
|
||||
if (func(shared_from_this())) {
|
||||
for (auto&& child : _children) {
|
||||
if (!child->traverse(func)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Pointer findByName(const QString& id) {
|
||||
Pointer result;
|
||||
traverse([&](Pointer node) {
|
||||
if (id == node->getID()) {
|
||||
result = node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void setCurrentFrameInternal(float frame) {}
|
||||
|
|
|
@ -79,6 +79,8 @@ void Rig::startAnimation(const QString& url, float fps, bool loop, float firstFr
|
|||
bool hold = true;
|
||||
QStringList maskedJoints;
|
||||
|
||||
_currentUserAnimURL = url;
|
||||
|
||||
// This is different than startAnimationByRole, in which we use the existing values if the animation already exists.
|
||||
// Here we reuse the animation handle if possible, but in any case, we set the values to those given (or defaulted).
|
||||
AnimationHandlePointer handle = nullptr;
|
||||
|
@ -102,79 +104,12 @@ void Rig::startAnimation(const QString& url, float fps, bool loop, float firstFr
|
|||
handle->start();
|
||||
}
|
||||
}
|
||||
|
||||
AnimationHandlePointer Rig::addAnimationByRole(const QString& role, const QString& url, float fps, float priority,
|
||||
bool loop, bool hold, float firstFrame, float lastFrame, const QStringList& maskedJoints, bool startAutomatically) {
|
||||
|
||||
// check for a configured animation for the role
|
||||
//qCDebug(animation) << "addAnimationByRole" << role << url << fps << priority << loop << hold << firstFrame << lastFrame << maskedJoints << startAutomatically;
|
||||
foreach (const AnimationHandlePointer& candidate, _animationHandles) {
|
||||
if (candidate->getRole() == role) {
|
||||
if (startAutomatically) {
|
||||
candidate->start();
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
AnimationHandlePointer handle = createAnimationHandle();
|
||||
QString standard = "";
|
||||
if (url.isEmpty()) { // Default animations for fight club
|
||||
const QString& base = "https://hifi-public.s3.amazonaws.com/ozan/anim/standard_anims/";
|
||||
if (role == "walk") {
|
||||
standard = base + "walk_fwd.fbx";
|
||||
} else if (role == "backup") {
|
||||
standard = base + "walk_bwd.fbx";
|
||||
} else if (role == "leftTurn") {
|
||||
standard = base + "turn_left.fbx";
|
||||
} else if (role == "rightTurn") {
|
||||
standard = base + "turn_right.fbx";
|
||||
} else if (role == "leftStrafe") {
|
||||
standard = base + "strafe_left.fbx";
|
||||
} else if (role == "rightStrafe") {
|
||||
standard = base + "strafe_right.fbx";
|
||||
} else if (role == "idle") {
|
||||
standard = base + "idle.fbx";
|
||||
fps = 25.0f;
|
||||
}
|
||||
if (!standard.isEmpty()) {
|
||||
loop = true;
|
||||
}
|
||||
}
|
||||
handle->setRole(role);
|
||||
handle->setURL(url.isEmpty() ? standard : url);
|
||||
handle->setFPS(fps);
|
||||
handle->setPriority(priority);
|
||||
handle->setLoop(loop);
|
||||
handle->setHold(hold);
|
||||
handle->setFirstFrame(firstFrame);
|
||||
handle->setLastFrame(lastFrame);
|
||||
handle->setMaskedJoints(maskedJoints);
|
||||
if (startAutomatically) {
|
||||
handle->start();
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
const float FADE_FRAMES = 30.0f;
|
||||
const float FRAMES_PER_SECOND = 30.0f;
|
||||
const float FADE_FRAMES = 30.0f;
|
||||
|
||||
void Rig::startAnimationByRole(const QString& role, const QString& url, float fps, float priority,
|
||||
bool loop, bool hold, float firstFrame, float lastFrame, const QStringList& maskedJoints) {
|
||||
AnimationHandlePointer handle = addAnimationByRole(role, url, fps, priority, loop, hold, firstFrame, lastFrame, maskedJoints, true);
|
||||
handle->setFadePerSecond(FRAMES_PER_SECOND / FADE_FRAMES); // For now. Could be individualized later.
|
||||
}
|
||||
|
||||
void Rig::stopAnimationByRole(const QString& role) {
|
||||
foreach (const AnimationHandlePointer& handle, getRunningAnimations()) {
|
||||
if (handle->getRole() == role) {
|
||||
handle->setFadePerSecond(-(FRAMES_PER_SECOND / FADE_FRAMES)); // For now. Could be individualized later.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::stopAnimation(const QString& url) {
|
||||
void Rig::stopAnimation() {
|
||||
if (_enableAnimGraph) {
|
||||
if (url == _currentUserAnimURL) {
|
||||
if (_currentUserAnimURL != "") {
|
||||
_currentUserAnimURL = "";
|
||||
// notify the userAnimStateMachine the desired state.
|
||||
_animVars.set("userAnimNone", true);
|
||||
|
@ -183,7 +118,7 @@ void Rig::stopAnimation(const QString& url) {
|
|||
}
|
||||
} else {
|
||||
foreach (const AnimationHandlePointer& handle, getRunningAnimations()) {
|
||||
if (handle->getURL() == url) {
|
||||
if (handle->getURL() == _currentUserAnimURL) {
|
||||
handle->setFade(0.0f); // right away. Will be remove during updateAnimations, without locking
|
||||
handle->setFadePerSecond(-(FRAMES_PER_SECOND / FADE_FRAMES)); // so that the updateAnimation code notices
|
||||
}
|
||||
|
@ -191,6 +126,59 @@ void Rig::stopAnimation(const QString& url) {
|
|||
}
|
||||
}
|
||||
|
||||
QStringList Rig::getAnimationRoles() const {
|
||||
if (_enableAnimGraph && _animNode) {
|
||||
QStringList list;
|
||||
_animNode->traverse([&](AnimNode::Pointer node) {
|
||||
list.append(node->getID());
|
||||
return true;
|
||||
});
|
||||
return list;
|
||||
} else {
|
||||
return QStringList();
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::overrideAnimationRole(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame) {
|
||||
if (_enableAnimGraph && _animNode) {
|
||||
AnimNode::Pointer node = _animNode->findByName(role);
|
||||
if (node) {
|
||||
//_previousRoleAnimations[role] = node;
|
||||
// TODO: create clip node.
|
||||
// TODO: AnimNode needs the following methods.
|
||||
// Pointer getParent() const;
|
||||
// void swapChild(Pointer child, Pointer newChild);
|
||||
//
|
||||
// pseudo code
|
||||
//
|
||||
// auto clipNode = std::make_shared<AnimClip>(role, url, fps, firstFrame, lastFrame, loop);
|
||||
// node->getParent()->swapChild(node, clipNode);
|
||||
|
||||
} else {
|
||||
qCWarning(animation) << "Rig::overrideAnimationRole could not find role " << role;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::restoreAnimationRole(const QString& role) {
|
||||
if (_enableAnimGraph && _animNode) {
|
||||
AnimNode::Pointer node = _animNode->findByName(role);
|
||||
if (node) {
|
||||
// TODO: pseudo code
|
||||
// origNode = _previousRoleAnimations.find(role);
|
||||
// if (origNode) {
|
||||
// node->getParent()->swapChild(node, origNode);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rig::prefetchAnimation(const QString& url) {
|
||||
if (_enableAnimGraph) {
|
||||
// TODO:
|
||||
}
|
||||
}
|
||||
|
||||
bool Rig::removeRunningAnimation(AnimationHandlePointer animationHandle) {
|
||||
return _runningAnimations.removeOne(animationHandle);
|
||||
}
|
||||
|
@ -661,13 +649,13 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
|||
if (isOn) {
|
||||
if (!isRunningRole(role)) {
|
||||
qCDebug(animation) << "Rig STARTING" << role;
|
||||
startAnimationByRole(role);
|
||||
//startAnimationByRole(role);
|
||||
|
||||
}
|
||||
} else {
|
||||
if (isRunningRole(role)) {
|
||||
qCDebug(animation) << "Rig stopping" << role;
|
||||
stopAnimationByRole(role);
|
||||
//stopAnimationByRole(role);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -113,15 +113,13 @@ public:
|
|||
void deleteAnimations();
|
||||
void destroyAnimGraph();
|
||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||
|
||||
void startAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void stopAnimation(const QString& url);
|
||||
void startAnimationByRole(const QString& role, const QString& url = QString(), float fps = 30.0f,
|
||||
float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f,
|
||||
float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList());
|
||||
void stopAnimationByRole(const QString& role);
|
||||
AnimationHandlePointer addAnimationByRole(const QString& role, const QString& url = QString(), float fps = 30.0f,
|
||||
float priority = 1.0f, bool loop = false, bool hold = false, float firstFrame = 0.0f,
|
||||
float lastFrame = FLT_MAX, const QStringList& maskedJoints = QStringList(), bool startAutomatically = false);
|
||||
void stopAnimation();
|
||||
QStringList getAnimationRoles() const;
|
||||
void overrideAnimationRole(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void restoreAnimationRole(const QString& role);
|
||||
void prefetchAnimation(const QString& url);
|
||||
|
||||
void initJointStates(QVector<JointState> states, glm::mat4 rootTransform,
|
||||
int rootJointIndex,
|
||||
|
|
Loading…
Reference in a new issue