mirror of
https://github.com/overte-org/overte.git
synced 2025-08-05 04:10:11 +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) {
|
||||
settings->beginGroup("Avatar");
|
||||
|
||||
|
@ -461,12 +474,12 @@ void MyAvatar::saveData(QSettings* settings) {
|
|||
}
|
||||
settings->endArray();
|
||||
|
||||
settings->beginWriteArray("animationData");
|
||||
for (int i = 0; i < _animationData.size(); i++) {
|
||||
settings->beginWriteArray("animationHandles");
|
||||
for (int i = 0; i < _animationHandles.size(); i++) {
|
||||
settings->setArrayIndex(i);
|
||||
const AnimationData& animation = _animationData.at(i);
|
||||
settings->setValue("url", animation.url);
|
||||
settings->setValue("fps", animation.fps);
|
||||
const AnimationHandlePointer& pointer = _animationHandles.at(i);
|
||||
settings->setValue("url", pointer->getURL());
|
||||
settings->setValue("fps", pointer->getFPS());
|
||||
}
|
||||
settings->endArray();
|
||||
|
||||
|
@ -520,17 +533,20 @@ void MyAvatar::loadData(QSettings* settings) {
|
|||
settings->endArray();
|
||||
setAttachmentData(attachmentData);
|
||||
|
||||
QVector<AnimationData> animationData;
|
||||
int animationCount = settings->beginReadArray("animationData");
|
||||
int animationCount = settings->beginReadArray("animationHandles");
|
||||
while (_animationHandles.size() > animationCount) {
|
||||
_animationHandles.takeLast()->stop();
|
||||
}
|
||||
while (_animationHandles.size() < animationCount) {
|
||||
addAnimationHandle();
|
||||
}
|
||||
for (int i = 0; i < animationCount; i++) {
|
||||
settings->setArrayIndex(i);
|
||||
AnimationData animation;
|
||||
animation.url = settings->value("url").toUrl();
|
||||
animation.fps = loadSetting(settings, "fps", 30.0f);
|
||||
animationData.append(animation);
|
||||
const AnimationHandlePointer& handle = _animationHandles.at(i);
|
||||
handle->setURL(settings->value("url").toUrl());
|
||||
handle->setFPS(loadSetting(settings, "fps", 30.0f));
|
||||
}
|
||||
settings->endArray();
|
||||
setAnimationData(animationData);
|
||||
|
||||
setDisplayName(settings->value("displayName").toString());
|
||||
|
||||
|
@ -598,13 +614,6 @@ AttachmentData MyAvatar::loadAttachmentData(const QUrl& modelURL, const QString&
|
|||
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) {
|
||||
qDebug() << "Error: ignoring update packet for MyAvatar"
|
||||
<< " 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 <AnimationCache.h>
|
||||
|
||||
#include "Avatar.h"
|
||||
|
||||
class AnimationData;
|
||||
|
||||
enum AvatarHandState
|
||||
{
|
||||
HAND_STATE_NULL = 0,
|
||||
|
@ -66,6 +62,10 @@ public:
|
|||
glm::vec3 getUprightHeadPosition() const;
|
||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||
|
||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||
AnimationHandlePointer addAnimationHandle();
|
||||
void removeAnimationHandle(const AnimationHandlePointer& handle);
|
||||
|
||||
// get/set avatar data
|
||||
void saveData(QSettings* settings);
|
||||
void loadData(QSettings* settings);
|
||||
|
@ -73,9 +73,6 @@ public:
|
|||
void saveAttachmentData(const AttachmentData& attachment) 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
|
||||
void setDriveKeys(int key, float val) { _driveKeys[key] = val; };
|
||||
bool getDriveKeys(int key) { return _driveKeys[key] != 0.f; };
|
||||
|
@ -158,16 +155,7 @@ private:
|
|||
bool _billboardValid;
|
||||
float _oculusYawOffset;
|
||||
|
||||
QVector<AnimationData> _animationData;
|
||||
|
||||
class AnimationState {
|
||||
public:
|
||||
AnimationPointer animation;
|
||||
QVector<int> jointMappings;
|
||||
float frameIndex;
|
||||
};
|
||||
|
||||
QVector<AnimationState> _animationStates;
|
||||
QList<AnimationHandlePointer> _animationHandles;
|
||||
|
||||
// private methods
|
||||
void updateOrientation(float deltaTime);
|
||||
|
@ -185,15 +173,4 @@ private:
|
|||
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
|
||||
|
|
|
@ -404,6 +404,22 @@ QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance
|
|||
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) {
|
||||
Resource::setLoadPriority(owner, priority);
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <FBXReader.h>
|
||||
|
||||
#include <AnimationCache.h>
|
||||
|
||||
class Model;
|
||||
class NetworkGeometry;
|
||||
class NetworkMesh;
|
||||
|
@ -90,6 +92,8 @@ public:
|
|||
const FBXGeometry& getFBXGeometry() const { return _geometry; }
|
||||
const QVector<NetworkMesh>& getMeshes() const { return _meshes; }
|
||||
|
||||
QVector<int> getJointMappings(const AnimationPointer& animation);
|
||||
|
||||
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
||||
virtual void setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities);
|
||||
virtual void clearLoadPriority(const QPointer<QObject>& owner);
|
||||
|
@ -117,6 +121,8 @@ private:
|
|||
QVector<NetworkMesh> _meshes;
|
||||
|
||||
QWeakPointer<NetworkGeometry> _lodParent;
|
||||
|
||||
QHash<QWeakPointer<Animation>, QVector<int> > _jointMappings;
|
||||
};
|
||||
|
||||
/// The state associated with a single mesh part.
|
||||
|
|
|
@ -594,13 +594,15 @@ QStringList Model::getJointNames() const {
|
|||
return isActive() ? _geometry->getFBXGeometry().getJointNames() : QStringList();
|
||||
}
|
||||
|
||||
void Model::startAnimation(const QUrl& url, float fps, bool loop, float offset) {
|
||||
AnimationState state = { Application::getInstance()->getAnimationCache()->getAnimation(url), fps, loop, offset };
|
||||
_animationStates.append(state);
|
||||
uint qHash(const WeakAnimationHandlePointer& handle, uint seed) {
|
||||
return qHash(handle.data(), seed);
|
||||
}
|
||||
|
||||
void Model::stopAnimation() {
|
||||
_animationStates.clear();
|
||||
AnimationHandlePointer Model::createAnimationHandle() {
|
||||
AnimationHandlePointer handle(new AnimationHandle(this));
|
||||
handle->_self = handle;
|
||||
_animationHandles.insert(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Model::clearShapes() {
|
||||
|
@ -1015,19 +1017,8 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|
|||
|
||||
void Model::simulateInternal(float deltaTime) {
|
||||
// update animations
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
for (int i = 0; i < _animationStates.size(); i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (const AnimationHandlePointer& handle, _runningAnimations) {
|
||||
handle->simulate(deltaTime);
|
||||
}
|
||||
|
||||
// NOTE: this is a recursive call that walks all attachments, and their attachments
|
||||
|
@ -1038,6 +1029,7 @@ void Model::simulateInternal(float deltaTime) {
|
|||
_shapesAreDirty = true;
|
||||
|
||||
// update the attachment transforms and simulate them
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
for (int i = 0; i < _attachments.size(); i++) {
|
||||
const FBXAttachment& attachment = geometry.attachments.at(i);
|
||||
Model* model = _attachments.at(i);
|
||||
|
@ -1448,8 +1440,14 @@ void Model::deleteGeometry() {
|
|||
_meshStates.clear();
|
||||
clearShapes();
|
||||
|
||||
for (int i = 0; i < _animationStates.size(); i++) {
|
||||
_animationStates[i].jointMappings.clear();
|
||||
for (QSet<WeakAnimationHandlePointer>::iterator it = _animationHandles.begin(); it != _animationHandles.end(); ) {
|
||||
AnimationHandlePointer handle = it->toStrongRef();
|
||||
if (handle) {
|
||||
handle->_jointMappings.clear();
|
||||
it++;
|
||||
} else {
|
||||
it = _animationHandles.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
if (_geometry) {
|
||||
|
@ -1647,3 +1645,71 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent) {
|
|||
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 "TextureCache.h"
|
||||
|
||||
class AnimationHandle;
|
||||
class Shape;
|
||||
|
||||
typedef QSharedPointer<AnimationHandle> AnimationHandlePointer;
|
||||
typedef QWeakPointer<AnimationHandle> WeakAnimationHandlePointer;
|
||||
|
||||
/// A generic 3D model displaying geometry loaded from a URL.
|
||||
class Model : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -187,22 +191,7 @@ public:
|
|||
|
||||
QStringList getJointNames() const;
|
||||
|
||||
class AnimationState {
|
||||
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();
|
||||
AnimationHandlePointer createAnimationHandle();
|
||||
|
||||
void clearShapes();
|
||||
void rebuildShapes();
|
||||
|
@ -279,8 +268,6 @@ protected:
|
|||
|
||||
QVector<MeshState> _meshStates;
|
||||
|
||||
QVector<AnimationState> _animationStates;
|
||||
|
||||
// returns 'true' if needs fullUpdate after geometry change
|
||||
bool updateGeometry();
|
||||
|
||||
|
@ -320,6 +307,8 @@ protected:
|
|||
|
||||
private:
|
||||
|
||||
friend class AnimationHandle;
|
||||
|
||||
void applyNextGeometry();
|
||||
void deleteGeometry();
|
||||
void renderMeshes(float alpha, RenderMode mode, bool translucent);
|
||||
|
@ -343,6 +332,10 @@ private:
|
|||
|
||||
QVector<Model*> _attachments;
|
||||
|
||||
QSet<WeakAnimationHandlePointer> _animationHandles;
|
||||
|
||||
QList<AnimationHandlePointer> _runningAnimations;
|
||||
|
||||
static ProgramObject _program;
|
||||
static ProgramObject _normalMapProgram;
|
||||
static ProgramObject _specularMapProgram;
|
||||
|
@ -378,4 +371,40 @@ Q_DECLARE_METATYPE(QPointer<Model>)
|
|||
Q_DECLARE_METATYPE(QWeakPointer<NetworkGeometry>)
|
||||
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
|
||||
|
|
|
@ -39,8 +39,8 @@ AnimationsDialog::AnimationsDialog() :
|
|||
area->setWidget(container);
|
||||
_animations->addStretch(1);
|
||||
|
||||
foreach (const AnimationData& data, Application::getInstance()->getAvatar()->getAnimationData()) {
|
||||
addAnimation(data);
|
||||
foreach (const AnimationHandlePointer& handle, Application::getInstance()->getAvatar()->getAnimationHandles()) {
|
||||
_animations->insertWidget(_animations->count() - 1, new AnimationPanel(this, handle));
|
||||
}
|
||||
|
||||
QPushButton* newAnimation = new QPushButton("New Animation");
|
||||
|
@ -64,20 +64,14 @@ void AnimationsDialog::setVisible(bool visible) {
|
|||
}
|
||||
}
|
||||
|
||||
void AnimationsDialog::updateAnimationData() {
|
||||
QVector<AnimationData> data;
|
||||
for (int i = 0; i < _animations->count() - 1; i++) {
|
||||
data.append(static_cast<AnimationPanel*>(_animations->itemAt(i)->widget())->getAnimationData());
|
||||
}
|
||||
Application::getInstance()->getAvatar()->setAnimationData(data);
|
||||
void AnimationsDialog::addAnimation() {
|
||||
_animations->insertWidget(_animations->count() - 1, new AnimationPanel(
|
||||
this, Application::getInstance()->getAvatar()->addAnimationHandle()));
|
||||
}
|
||||
|
||||
void AnimationsDialog::addAnimation(const AnimationData& data) {
|
||||
_animations->insertWidget(_animations->count() - 1, new AnimationPanel(this, data));
|
||||
}
|
||||
|
||||
AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationData& data) :
|
||||
AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePointer& handle) :
|
||||
_dialog(dialog),
|
||||
_handle(handle),
|
||||
_applying(false) {
|
||||
setFrameStyle(QFrame::StyledPanel);
|
||||
|
||||
|
@ -87,8 +81,8 @@ AnimationPanel::AnimationPanel(AnimationsDialog* dialog, const AnimationData& da
|
|||
|
||||
QHBoxLayout* urlBox = new QHBoxLayout();
|
||||
layout->addRow("URL:", urlBox);
|
||||
urlBox->addWidget(_url = new QLineEdit(data.url.toString()), 1);
|
||||
dialog->connect(_url, SIGNAL(returnPressed()), SLOT(updateAnimationData()));
|
||||
urlBox->addWidget(_url = new QLineEdit(handle->getURL().toString()), 1);
|
||||
connect(_url, SIGNAL(returnPressed()), SLOT(updateHandle()));
|
||||
QPushButton* chooseURL = new QPushButton("Choose");
|
||||
urlBox->addWidget(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());
|
||||
_fps->setSingleStep(0.01);
|
||||
_fps->setMaximum(FLT_MAX);
|
||||
_fps->setValue(data.fps);
|
||||
dialog->connect(_fps, SIGNAL(valueChanged(double)), SLOT(updateAnimationData()));
|
||||
_fps->setValue(handle->getFPS());
|
||||
connect(_fps, SIGNAL(valueChanged(double)), SLOT(updateHandle()));
|
||||
|
||||
QPushButton* remove = new QPushButton("Delete");
|
||||
layout->addRow(remove);
|
||||
connect(remove, SIGNAL(clicked(bool)), SLOT(deleteLater()));
|
||||
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;
|
||||
connect(remove, SIGNAL(clicked(bool)), SLOT(removeHandle()));
|
||||
}
|
||||
|
||||
void AnimationPanel::chooseURL() {
|
||||
|
@ -125,3 +111,12 @@ void AnimationPanel::chooseURL() {
|
|||
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);
|
||||
|
||||
public slots:
|
||||
|
||||
void updateAnimationData();
|
||||
|
||||
private slots:
|
||||
|
||||
void addAnimation(const AnimationData& animation = AnimationData());
|
||||
|
||||
|
||||
void addAnimation();
|
||||
|
||||
private:
|
||||
|
||||
QVBoxLayout* _animations;
|
||||
|
@ -52,17 +48,18 @@ class AnimationPanel : public QFrame {
|
|||
|
||||
public:
|
||||
|
||||
AnimationPanel(AnimationsDialog* dialog, const AnimationData& data = AnimationData());
|
||||
|
||||
AnimationData getAnimationData() const;
|
||||
AnimationPanel(AnimationsDialog* dialog, const AnimationHandlePointer& handle);
|
||||
|
||||
private slots:
|
||||
|
||||
void chooseURL();
|
||||
void updateHandle();
|
||||
void removeHandle();
|
||||
|
||||
private:
|
||||
|
||||
AnimationsDialog* _dialog;
|
||||
AnimationHandlePointer _handle;
|
||||
QLineEdit* _url;
|
||||
QDoubleSpinBox* _fps;
|
||||
bool _applying;
|
||||
|
|
Loading…
Reference in a new issue