mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 08:21:24 +02:00
Animation bits.
This commit is contained in:
parent
62e7a31602
commit
49a0645677
8 changed files with 216 additions and 128 deletions
|
@ -423,6 +423,19 @@ void MyAvatar::setGravity(const glm::vec3& gravity) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimationHandlePointer MyAvatar::addAnimationHandle() {
|
||||||
|
AnimationHandlePointer handle = _skeletonModel.createAnimationHandle();
|
||||||
|
handle->setLoop(true);
|
||||||
|
handle->start();
|
||||||
|
_animationHandles.append(handle);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::removeAnimationHandle(const AnimationHandlePointer& handle) {
|
||||||
|
handle->stop();
|
||||||
|
_animationHandles.removeOne(handle);
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::saveData(QSettings* settings) {
|
void MyAvatar::saveData(QSettings* settings) {
|
||||||
settings->beginGroup("Avatar");
|
settings->beginGroup("Avatar");
|
||||||
|
|
||||||
|
@ -461,12 +474,12 @@ void MyAvatar::saveData(QSettings* settings) {
|
||||||
}
|
}
|
||||||
settings->endArray();
|
settings->endArray();
|
||||||
|
|
||||||
settings->beginWriteArray("animationData");
|
settings->beginWriteArray("animationHandles");
|
||||||
for (int i = 0; i < _animationData.size(); i++) {
|
for (int i = 0; i < _animationHandles.size(); i++) {
|
||||||
settings->setArrayIndex(i);
|
settings->setArrayIndex(i);
|
||||||
const AnimationData& animation = _animationData.at(i);
|
const AnimationHandlePointer& pointer = _animationHandles.at(i);
|
||||||
settings->setValue("url", animation.url);
|
settings->setValue("url", pointer->getURL());
|
||||||
settings->setValue("fps", animation.fps);
|
settings->setValue("fps", pointer->getFPS());
|
||||||
}
|
}
|
||||||
settings->endArray();
|
settings->endArray();
|
||||||
|
|
||||||
|
@ -520,17 +533,20 @@ void MyAvatar::loadData(QSettings* settings) {
|
||||||
settings->endArray();
|
settings->endArray();
|
||||||
setAttachmentData(attachmentData);
|
setAttachmentData(attachmentData);
|
||||||
|
|
||||||
QVector<AnimationData> animationData;
|
int animationCount = settings->beginReadArray("animationHandles");
|
||||||
int animationCount = settings->beginReadArray("animationData");
|
while (_animationHandles.size() > animationCount) {
|
||||||
|
_animationHandles.takeLast()->stop();
|
||||||
|
}
|
||||||
|
while (_animationHandles.size() < animationCount) {
|
||||||
|
addAnimationHandle();
|
||||||
|
}
|
||||||
for (int i = 0; i < animationCount; i++) {
|
for (int i = 0; i < animationCount; i++) {
|
||||||
settings->setArrayIndex(i);
|
settings->setArrayIndex(i);
|
||||||
AnimationData animation;
|
const AnimationHandlePointer& handle = _animationHandles.at(i);
|
||||||
animation.url = settings->value("url").toUrl();
|
handle->setURL(settings->value("url").toUrl());
|
||||||
animation.fps = loadSetting(settings, "fps", 30.0f);
|
handle->setFPS(loadSetting(settings, "fps", 30.0f));
|
||||||
animationData.append(animation);
|
|
||||||
}
|
}
|
||||||
settings->endArray();
|
settings->endArray();
|
||||||
setAnimationData(animationData);
|
|
||||||
|
|
||||||
setDisplayName(settings->value("displayName").toString());
|
setDisplayName(settings->value("displayName").toString());
|
||||||
|
|
||||||
|
@ -598,13 +614,6 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString&
|
||||||
return attachment;
|
return attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::setAnimationData(const QVector<AnimationData>& animationData) {
|
|
||||||
// exit early if no change
|
|
||||||
if (_animationData != animationData) {
|
|
||||||
_animationData = animationData;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {
|
int MyAvatar::parseDataAtOffset(const QByteArray& packet, int offset) {
|
||||||
qDebug() << "Error: ignoring update packet for MyAvatar"
|
qDebug() << "Error: ignoring update packet for MyAvatar"
|
||||||
<< " packetLength = " << packet.size()
|
<< " packetLength = " << packet.size()
|
||||||
|
@ -1570,10 +1579,3 @@ void MyAvatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& pe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimationData::AnimationData() :
|
|
||||||
fps(30.0f) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AnimationData::operator==(const AnimationData& other) const {
|
|
||||||
return url == other.url && fps == other.fps;
|
|
||||||
}
|
|
||||||
|
|
|
@ -14,12 +14,8 @@
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
|
||||||
#include <AnimationCache.h>
|
|
||||||
|
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
|
|
||||||
class AnimationData;
|
|
||||||
|
|
||||||
enum AvatarHandState
|
enum AvatarHandState
|
||||||
{
|
{
|
||||||
HAND_STATE_NULL = 0,
|
HAND_STATE_NULL = 0,
|
||||||
|
@ -66,6 +62,10 @@ public:
|
||||||
glm::vec3 getUprightHeadPosition() const;
|
glm::vec3 getUprightHeadPosition() const;
|
||||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||||
|
|
||||||
|
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||||
|
AnimationHandlePointer addAnimationHandle();
|
||||||
|
void removeAnimationHandle(const AnimationHandlePointer& handle);
|
||||||
|
|
||||||
// get/set avatar data
|
// get/set avatar data
|
||||||
void saveData(QSettings* settings);
|
void saveData(QSettings* settings);
|
||||||
void loadData(QSettings* settings);
|
void loadData(QSettings* settings);
|
||||||
|
@ -73,9 +73,6 @@ public:
|
||||||
void saveAttachmentData(const AttachmentData& attachment) const;
|
void saveAttachmentData(const AttachmentData& attachment) const;
|
||||||
AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const;
|
AttachmentData loadAttachmentData(const QUrl& modelURL, const QString& jointName = QString()) const;
|
||||||
|
|
||||||
void setAnimationData(const QVector<AnimationData>& animationData);
|
|
||||||
const QVector<AnimationData>& getAnimationData() const { return _animationData; }
|
|
||||||
|
|
||||||
// Set what driving keys are being pressed to control thrust levels
|
// Set what driving keys are being pressed to control thrust levels
|
||||||
void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
|
void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
|
||||||
bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; };
|
bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; };
|
||||||
|
@ -158,16 +155,7 @@ private:
|
||||||
bool _billboardValid;
|
bool _billboardValid;
|
||||||
float _oculusYawOffset;
|
float _oculusYawOffset;
|
||||||
|
|
||||||
QVector<AnimationData> _animationData;
|
QList<AnimationHandlePointer> _animationHandles;
|
||||||
|
|
||||||
class AnimationState {
|
|
||||||
public:
|
|
||||||
AnimationPointer animation;
|
|
||||||
QVector<int> jointMappings;
|
|
||||||
float frameIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
QVector<AnimationState> _animationStates;
|
|
||||||
|
|
||||||
// private methods
|
// private methods
|
||||||
void updateOrientation(float deltaTime);
|
void updateOrientation(float deltaTime);
|
||||||
|
@ -185,15 +173,4 @@ private:
|
||||||
void setGravity(const glm::vec3& gravity);
|
void setGravity(const glm::vec3& gravity);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Describes an animation being run on the avatar.
|
|
||||||
class AnimationData {
|
|
||||||
public:
|
|
||||||
QUrl url;
|
|
||||||
float fps;
|
|
||||||
|
|
||||||
AnimationData();
|
|
||||||
|
|
||||||
bool operator==(const AnimationData& other) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_MyAvatar_h
|
#endif // hifi_MyAvatar_h
|
||||||
|
|
|
@ -404,6 +404,22 @@ QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance
|
||||||
return lod;
|
return lod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint qHash(const QWeakPointer<Animation>& animation, uint seed = 0) {
|
||||||
|
return qHash(animation.data(), seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<int> NetworkGeometry::getJointMappings(const AnimationPointer& animation) {
|
||||||
|
QVector<int> mappings = _jointMappings.value(animation);
|
||||||
|
if (mappings.isEmpty() && isLoaded() && animation && animation->isLoaded()) {
|
||||||
|
const FBXGeometry& animationGeometry = animation->getGeometry();
|
||||||
|
for (int i = 0; i < animationGeometry.joints.size(); i++) {
|
||||||
|
mappings.append(_geometry.jointIndices.value(animationGeometry.joints.at(i).name) - 1);
|
||||||
|
}
|
||||||
|
_jointMappings.insert(animation, mappings);
|
||||||
|
}
|
||||||
|
return mappings;
|
||||||
|
}
|
||||||
|
|
||||||
void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {
|
void NetworkGeometry::setLoadPriority(const QPointer<QObject>& owner, float priority) {
|
||||||
Resource::setLoadPriority(owner, priority);
|
Resource::setLoadPriority(owner, priority);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#include <FBXReader.h>
|
#include <FBXReader.h>
|
||||||
|
|
||||||
|
#include <AnimationCache.h>
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
class NetworkGeometry;
|
class NetworkGeometry;
|
||||||
class NetworkMesh;
|
class NetworkMesh;
|
||||||
|
@ -90,6 +92,8 @@ public:
|
||||||
const FBXGeometry& getFBXGeometry() const { return _geometry; }
|
const FBXGeometry& getFBXGeometry() const { return _geometry; }
|
||||||
const QVector<NetworkMesh>& getMeshes() const { return _meshes; }
|
const QVector<NetworkMesh>& getMeshes() const { return _meshes; }
|
||||||
|
|
||||||
|
QVector<int> getJointMappings(const AnimationPointer& animation);
|
||||||
|
|
||||||
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
||||||
virtual void setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities);
|
virtual void setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities);
|
||||||
virtual void clearLoadPriority(const QPointer<QObject>& owner);
|
virtual void clearLoadPriority(const QPointer<QObject>& owner);
|
||||||
|
@ -117,6 +121,8 @@ private:
|
||||||
QVector<NetworkMesh> _meshes;
|
QVector<NetworkMesh> _meshes;
|
||||||
|
|
||||||
QWeakPointer<NetworkGeometry> _lodParent;
|
QWeakPointer<NetworkGeometry> _lodParent;
|
||||||
|
|
||||||
|
QHash<QWeakPointer<Animation>, QVector<int> > _jointMappings;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The state associated with a single mesh part.
|
/// The state associated with a single mesh part.
|
||||||
|
|
|
@ -594,13 +594,15 @@ QStringList Model::getJointNames() const {
|
||||||
return isActive() ? _geometry->getFBXGeometry().getJointNames() : QStringList();
|
return isActive() ? _geometry->getFBXGeometry().getJointNames() : QStringList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::startAnimation(const QUrl& url, float fps, bool loop, float offset) {
|
uint qHash(const WeakAnimationHandlePointer& handle, uint seed) {
|
||||||
AnimationState state = { Application::getInstance()->getAnimationCache()->getAnimation(url), fps, loop, offset };
|
return qHash(handle.data(), seed);
|
||||||
_animationStates.append(state);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::stopAnimation() {
|
AnimationHandlePointer Model::createAnimationHandle() {
|
||||||
_animationStates.clear();
|
AnimationHandlePointer handle(new AnimationHandle(this));
|
||||||
|
handle->_self = handle;
|
||||||
|
_animationHandles.insert(handle);
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::clearShapes() {
|
void Model::clearShapes() {
|
||||||
|
@ -1015,19 +1017,8 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|
||||||
|
|
||||||
void Model::simulateInternal(float deltaTime) {
|
void Model::simulateInternal(float deltaTime) {
|
||||||
// update animations
|
// update animations
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
|
||||||
for (int i = 0; i < _animationStates.size(); i++) {
|
handle->simulate(deltaTime);
|
||||||
AnimationState& state = _animationStates[i];
|
|
||||||
if (!(state.animation && state.animation->isLoaded())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const FBXGeometry& animationGeometry = state.animation->getGeometry();
|
|
||||||
if (state.jointMappings.isEmpty()) {
|
|
||||||
for (int j = 0; j < geometry.joints.size(); j++) {
|
|
||||||
state.jointMappings.append(animationGeometry.jointIndices.value(geometry.joints.at(j).name) - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: this is a recursive call that walks all attachments, and their attachments
|
// NOTE: this is a recursive call that walks all attachments, and their attachments
|
||||||
|
@ -1038,6 +1029,7 @@ void Model::simulateInternal(float deltaTime) {
|
||||||
_shapesAreDirty = true;
|
_shapesAreDirty = true;
|
||||||
|
|
||||||
// update the attachment transforms and simulate them
|
// update the attachment transforms and simulate them
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
for (int i = 0; i < _attachments.size(); i++) {
|
for (int i = 0; i < _attachments.size(); i++) {
|
||||||
const FBXAttachment& attachment = geometry.attachments.at(i);
|
const FBXAttachment& attachment = geometry.attachments.at(i);
|
||||||
Model* model = _attachments.at(i);
|
Model* model = _attachments.at(i);
|
||||||
|
@ -1448,8 +1440,14 @@ void Model::deleteGeometry() {
|
||||||
_meshStates.clear();
|
_meshStates.clear();
|
||||||
clearShapes();
|
clearShapes();
|
||||||
|
|
||||||
for (int i = 0; i < _animationStates.size(); i++) {
|
for (QSet<WeakAnimationHandlePointer>::iterator it = _animationHandles.begin(); it != _animationHandles.end(); ) {
|
||||||
_animationStates[i].jointMappings.clear();
|
AnimationHandlePointer handle = it->toStrongRef();
|
||||||
|
if (handle) {
|
||||||
|
handle->_jointMappings.clear();
|
||||||
|
it++;
|
||||||
|
} else {
|
||||||
|
it = _animationHandles.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_geometry) {
|
if (_geometry) {
|
||||||
|
@ -1647,3 +1645,71 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) {
|
||||||
activeProgram->release();
|
activeProgram->release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimationHandle::setURL(const QUrl& url) {
|
||||||
|
_animation = Application::getInstance()->getAnimationCache()->getAnimation(_url = url);
|
||||||
|
_jointMappings.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationHandle::start() {
|
||||||
|
if (!_model->_runningAnimations.contains(_self)) {
|
||||||
|
_model->_runningAnimations.append(_self);
|
||||||
|
}
|
||||||
|
_frameIndex = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationHandle::stop() {
|
||||||
|
_model->_runningAnimations.removeOne(_self);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationHandle::AnimationHandle(Model* model) :
|
||||||
|
QObject(model),
|
||||||
|
_model(model),
|
||||||
|
_fps(30.0f),
|
||||||
|
_loop(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationHandle::simulate(float deltaTime) {
|
||||||
|
_frameIndex += deltaTime * _fps;
|
||||||
|
|
||||||
|
// update the joint mappings if necessary/possible
|
||||||
|
if (_jointMappings.isEmpty()) {
|
||||||
|
if (_model->isActive()) {
|
||||||
|
_jointMappings = _model->getGeometry()->getJointMappings(_animation);
|
||||||
|
}
|
||||||
|
if (_jointMappings.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FBXGeometry& animationGeometry = _animation->getGeometry();
|
||||||
|
if (animationGeometry.animationFrames.isEmpty()) {
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int ceilFrameIndex = (int)glm::ceil(_frameIndex);
|
||||||
|
if (!_loop && ceilFrameIndex >= animationGeometry.animationFrames.size()) {
|
||||||
|
const FBXAnimationFrame& frame = animationGeometry.animationFrames.last();
|
||||||
|
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||||
|
int mapping = _jointMappings.at(i);
|
||||||
|
if (mapping != -1) {
|
||||||
|
_model->_jointStates[mapping].rotation = frame.rotations.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const FBXAnimationFrame& ceilFrame = animationGeometry.animationFrames.at(
|
||||||
|
ceilFrameIndex % animationGeometry.animationFrames.size());
|
||||||
|
const FBXAnimationFrame& floorFrame = animationGeometry.animationFrames.at(
|
||||||
|
(int)glm::floor(_frameIndex) % animationGeometry.animationFrames.size());
|
||||||
|
float frameFraction = glm::fract(_frameIndex);
|
||||||
|
for (int i = 0; i < _jointMappings.size(); i++) {
|
||||||
|
int mapping = _jointMappings.at(i);
|
||||||
|
if (mapping != -1) {
|
||||||
|
_model->_jointStates[mapping].rotation = safeMix(floorFrame.rotations.at(i),
|
||||||
|
ceilFrame.rotations.at(i), frameFraction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,12 @@
|
||||||
#include "ProgramObject.h"
|
#include "ProgramObject.h"
|
||||||
#include "TextureCache.h"
|
#include "TextureCache.h"
|
||||||
|
|
||||||
|
class AnimationHandle;
|
||||||
class Shape;
|
class Shape;
|
||||||
|
|
||||||
|
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
||||||
|
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
||||||
|
|
||||||
/// A generic 3D model displaying geometry loaded from a URL.
|
/// A generic 3D model displaying geometry loaded from a URL.
|
||||||
class Model : public QObject {
|
class Model : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -187,22 +191,7 @@ public:
|
||||||
|
|
||||||
QStringList getJointNames() const;
|
QStringList getJointNames() const;
|
||||||
|
|
||||||
class AnimationState {
|
AnimationHandlePointer createAnimationHandle();
|
||||||
public:
|
|
||||||
AnimationPointer animation;
|
|
||||||
float fps;
|
|
||||||
bool loop;
|
|
||||||
float offset;
|
|
||||||
QVector<int> jointMappings;
|
|
||||||
};
|
|
||||||
|
|
||||||
const QVector<AnimationState>& getAnimationStates() const { return _animationStates; }
|
|
||||||
|
|
||||||
/// Starts playing the animation at the specified URL.
|
|
||||||
void startAnimation(const QUrl& url, float fps = 30.0f, bool loop = true, float offset = 0.0f);
|
|
||||||
|
|
||||||
/// Stops playing all animations.
|
|
||||||
void stopAnimation();
|
|
||||||
|
|
||||||
void clearShapes();
|
void clearShapes();
|
||||||
void rebuildShapes();
|
void rebuildShapes();
|
||||||
|
@ -279,8 +268,6 @@ protected:
|
||||||
|
|
||||||
QVector<MeshState> _meshStates;
|
QVector<MeshState> _meshStates;
|
||||||
|
|
||||||
QVector<AnimationState> _animationStates;
|
|
||||||
|
|
||||||
// returns 'true' if needs fullUpdate after geometry change
|
// returns 'true' if needs fullUpdate after geometry change
|
||||||
bool updateGeometry();
|
bool updateGeometry();
|
||||||
|
|
||||||
|
@ -320,6 +307,8 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
friend class AnimationHandle;
|
||||||
|
|
||||||
void applyNextGeometry();
|
void applyNextGeometry();
|
||||||
void deleteGeometry();
|
void deleteGeometry();
|
||||||
void renderMeshes(float alpha, RenderMode mode, bool translucent);
|
void renderMeshes(float alpha, RenderMode mode, bool translucent);
|
||||||
|
@ -343,6 +332,10 @@ private:
|
||||||
|
|
||||||
QVector<Model*> _attachments;
|
QVector<Model*> _attachments;
|
||||||
|
|
||||||
|
QSet<WeakAnimationHandlePointer> _animationHandles;
|
||||||
|
|
||||||
|
QList<AnimationHandlePointer> _runningAnimations;
|
||||||
|
|
||||||
static ProgramObject _program;
|
static ProgramObject _program;
|
||||||
static ProgramObject _normalMapProgram;
|
static ProgramObject _normalMapProgram;
|
||||||
static ProgramObject _specularMapProgram;
|
static ProgramObject _specularMapProgram;
|
||||||
|
@ -378,4 +371,40 @@ Q_DECLARE_METATYPE(QPointer<Model>)
|
||||||
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
|
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
|
||||||
Q_DECLARE_METATYPE(QVector<glm::vec3>)
|
Q_DECLARE_METATYPE(QVector<glm::vec3>)
|
||||||
|
|
||||||
|
/// Represents a handle to a model animation.
|
||||||
|
class AnimationHandle : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void setURL(const QUrl& url);
|
||||||
|
const QUrl& getURL() const { return _url; }
|
||||||
|
|
||||||
|
void setFPS(float fps) { _fps = fps; }
|
||||||
|
float getFPS() const { return _fps; }
|
||||||
|
|
||||||
|
void setLoop(bool loop) { _loop = loop; }
|
||||||
|
bool getLoop() const { return _loop; }
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
friend class Model;
|
||||||
|
|
||||||
|
AnimationHandle(Model* model);
|
||||||
|
|
||||||
|
void simulate(float deltaTime);
|
||||||
|
|
||||||
|
Model* _model;
|
||||||
|
WeakAnimationHandlePointer _self;
|
||||||
|
AnimationPointer _animation;
|
||||||
|
QUrl _url;
|
||||||
|
float _fps;
|
||||||
|
bool _loop;
|
||||||
|
QVector<int> _jointMappings;
|
||||||
|
float _frameIndex;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_Model_h
|
#endif // hifi_Model_h
|
||||||
|
|
|
@ -39,8 +39,8 @@ AnimationsDialog::AnimationsDialog() :
|
||||||
area->setWidget(container);
|
area->setWidget(container);
|
||||||
_animations->addStretch(1);
|
_animations->addStretch(1);
|
||||||
|
|
||||||
foreach (const AnimationData& data, Application::getInstance()->getAvatar()->getAnimationData()) {
|
foreach (const AnimationHandlePointer& handle, Application::getInstance()->getAvatar()->getAnimationHandles()) {
|
||||||
addAnimation(data);
|
_animations->insertWidget(_animations->count() - 1, new AnimationPanel(this, handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton* newAnimation = new QPushButton("New Animation");
|
QPushButton* newAnimation = new QPushButton("New Animation");
|
||||||
|
@ -64,20 +64,14 @@ void AnimationsDialog::setVisible(bool visible) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationsDialog::updateAnimationData() {
|
void AnimationsDialog::addAnimation() {
|
||||||
QVector<AnimationData> data;
|
_animations->insertWidget(_animations->count() - 1, new AnimationPanel(
|
||||||
for (int i = 0; i < _animations->count() - 1; i++) {
|
this, Application::getInstance()->getAvatar()->addAnimationHandle()));
|
||||||
data.append(static_cast<AnimationPanel*>(_animations->itemAt(i)->widget())->getAnimationData());
|
|
||||||
}
|
|
||||||
Application::getInstance()->getAvatar()->setAnimationData(data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationsDialog::addAnimation(const AnimationData& data) {
|
AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePointer& handle) :
|
||||||
_animations->insertWidget(_animations->count() - 1, new AnimationPanel(this, data));
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationData& data) :
|
|
||||||
_dialog(dialog),
|
_dialog(dialog),
|
||||||
|
_handle(handle),
|
||||||
_applying(false) {
|
_applying(false) {
|
||||||
setFrameStyle(QFrame::StyledPanel);
|
setFrameStyle(QFrame::StyledPanel);
|
||||||
|
|
||||||
|
@ -87,8 +81,8 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationData& da
|
||||||
|
|
||||||
QHBoxLayout* urlBox = new QHBoxLayout();
|
QHBoxLayout* urlBox = new QHBoxLayout();
|
||||||
layout->addRow("URL:", urlBox);
|
layout->addRow("URL:", urlBox);
|
||||||
urlBox->addWidget(_url = new QLineEdit(data.url.toString()), 1);
|
urlBox->addWidget(_url = new QLineEdit(handle->getURL().toString()), 1);
|
||||||
dialog->connect(_url, SIGNAL(returnPressed()), SLOT(updateAnimationData()));
|
connect(_url, SIGNAL(returnPressed()), SLOT(updateHandle()));
|
||||||
QPushButton* chooseURL = new QPushButton("Choose");
|
QPushButton* chooseURL = new QPushButton("Choose");
|
||||||
urlBox->addWidget(chooseURL);
|
urlBox->addWidget(chooseURL);
|
||||||
connect(chooseURL, SIGNAL(clicked(bool)), SLOT(chooseURL()));
|
connect(chooseURL, SIGNAL(clicked(bool)), SLOT(chooseURL()));
|
||||||
|
@ -96,20 +90,12 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationData& da
|
||||||
layout->addRow("FPS:", _fps = new QDoubleSpinBox());
|
layout->addRow("FPS:", _fps = new QDoubleSpinBox());
|
||||||
_fps->setSingleStep(0.01);
|
_fps->setSingleStep(0.01);
|
||||||
_fps->setMaximum(FLT_MAX);
|
_fps->setMaximum(FLT_MAX);
|
||||||
_fps->setValue(data.fps);
|
_fps->setValue(handle->getFPS());
|
||||||
dialog->connect(_fps, SIGNAL(valueChanged(double)), SLOT(updateAnimationData()));
|
connect(_fps, SIGNAL(valueChanged(double)), SLOT(updateHandle()));
|
||||||
|
|
||||||
QPushButton* remove = new QPushButton("Delete");
|
QPushButton* remove = new QPushButton("Delete");
|
||||||
layout->addRow(remove);
|
layout->addRow(remove);
|
||||||
connect(remove, SIGNAL(clicked(bool)), SLOT(deleteLater()));
|
connect(remove, SIGNAL(clicked(bool)), SLOT(removeHandle()));
|
||||||
dialog->connect(remove, SIGNAL(clicked(bool)), SLOT(updateAnimationData()), Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimationData AnimationPanel::getAnimationData() const {
|
|
||||||
AnimationData data;
|
|
||||||
data.url = _url->text();
|
|
||||||
data.fps = _fps->value();
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationPanel::chooseURL() {
|
void AnimationPanel::chooseURL() {
|
||||||
|
@ -125,3 +111,12 @@ void AnimationPanel::chooseURL() {
|
||||||
emit _url->returnPressed();
|
emit _url->returnPressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimationPanel::updateHandle() {
|
||||||
|
_handle->setURL(_url->text());
|
||||||
|
_handle->setFPS(_fps->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationPanel::removeHandle() {
|
||||||
|
Application::getInstance()->getAvatar()->removeAnimationHandle(_handle);
|
||||||
|
deleteLater();
|
||||||
|
}
|
||||||
|
|
|
@ -32,14 +32,10 @@ public:
|
||||||
|
|
||||||
virtual void setVisible(bool visible);
|
virtual void setVisible(bool visible);
|
||||||
|
|
||||||
public slots:
|
|
||||||
|
|
||||||
void updateAnimationData();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void addAnimation(const AnimationData& animation = AnimationData());
|
void addAnimation();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
QVBoxLayout* _animations;
|
QVBoxLayout* _animations;
|
||||||
|
@ -52,17 +48,18 @@ class AnimationPanel : public QFrame {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AnimationPanel(AnimationsDialog* dialog, const AnimationData& data = AnimationData());
|
AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePointer& handle);
|
||||||
|
|
||||||
AnimationData getAnimationData() const;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void chooseURL();
|
void chooseURL();
|
||||||
|
void updateHandle();
|
||||||
|
void removeHandle();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
AnimationsDialog* _dialog;
|
AnimationsDialog* _dialog;
|
||||||
|
AnimationHandlePointer _handle;
|
||||||
QLineEdit* _url;
|
QLineEdit* _url;
|
||||||
QDoubleSpinBox* _fps;
|
QDoubleSpinBox* _fps;
|
||||||
bool _applying;
|
bool _applying;
|
||||||
|
|
Loading…
Reference in a new issue