1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-15 06:52:34 +02:00

Animations working again

This commit is contained in:
Daniel Evans 2014-03-01 11:19:33 +00:00
parent bd96b0b190
commit 52d90a9b26
15 changed files with 289 additions and 29 deletions

View File

@ -11,6 +11,7 @@
class Animation;
class AnimationBone;
class Model;
class ModelFrame;
/**
* @brief The Animator class handles updating frame matricies for animations.
@ -46,6 +47,14 @@ public:
void setModel(Model* model);
/**
* @brief getFrameMatrix returns the matrix for frame at the current time
* @param t
* @param frame
* @return
*/
glm::mat4 getFrameMatrix(ModelFrame* frame, float alpha) const;
/**
* @brief tick Update animation paramters for server-side data.
* @param dt
@ -70,17 +79,12 @@ public:
*/
glm::quat getRootRotation() const;
/**
* @brief getFrameMatrix returns the matrix for a given frame index.
* @param frame
* @return
*/
glm::mat4 getFrameMatrix(size_t frame) const;
/**
* Returns true if the animation has finished playing.
*/
bool isCompleted() const;
float getAnimationTime(float alpha = 0.f) const;
};
#endif

View File

@ -43,10 +43,11 @@ struct GameObject
{
Instance,
Character,
Vehicle
Vehicle,
Unknown
};
virtual Type type() = 0;
virtual Type type() { return Unknown; }
virtual void setPosition(const glm::vec3& pos);

View File

@ -31,6 +31,7 @@ public:
void reset();
void setTransform(const glm::mat4& m);
const glm::mat4& getTransform() const { return matrix; }
void setName(const std::string& fname)
{ name = fname; }

View File

@ -2,6 +2,7 @@
#include <loaders/LoaderDFF.hpp>
#include <loaders/LoaderIFP.hpp>
#include <render/Model.hpp>
#include <glm/gtc/matrix_transform.hpp>
Animator::Animator()
: animation(nullptr), model(nullptr), time(0.f), serverTime(0.f), lastServerTime(0.f), repeat(true)
@ -53,11 +54,6 @@ void Animator::tick(float dt)
}
void Animator::render(float dt)
{
}
glm::vec3 Animator::getRootTranslation() const
{
if( model && model->rootFrameIdx != -1 ) {
@ -71,12 +67,40 @@ glm::quat Animator::getRootRotation() const
return glm::quat();
}
glm::mat4 Animator::getFrameMatrix(size_t frame) const
glm::mat4 Animator::getFrameMatrix(ModelFrame* frame, float alpha) const
{
return glm::mat4();
auto it = animation->bones.find(frame->getName());
if(it != animation->bones.end()) {
auto kf = it->second->getInterpolatedKeyframe(getAnimationTime(alpha));
glm::mat4 m;
if(it->second->type == AnimationBone::R00) {
m = glm::translate(m, frame->getDefaultTranslation());
m = m * glm::mat4_cast(kf.rotation);
}
else if(it->second->type == AnimationBone::RT0) {
m = glm::mat4_cast(kf.rotation);
m = glm::translate(m, kf.position);
}
else {
m = glm::mat4_cast(kf.rotation);
m = glm::translate(m, kf.position);
}
return m;
}
else {
return frame->getTransform();
}
}
bool Animator::isCompleted() const
{
return serverTime >= animation->duration;
}
}
float Animator::getAnimationTime(float alpha) const
{
if(repeat) {
return fmod(serverTime + alpha, this->animation->duration);
}
return serverTime + alpha;
}

View File

@ -25,7 +25,7 @@ bool findKeyframes(float t, AnimationBone* bone, AnimationKeyframe& f1, Animatio
alpha = 1.f;
}
else {
alpha = (t - f1.starttime) / tdiff;
alpha = glm::clamp((t - f1.starttime) / tdiff, 0.f, 1.f);
}
return true;
@ -39,10 +39,9 @@ AnimationKeyframe AnimationBone::getInterpolatedKeyframe(float time)
AnimationKeyframe f1, f2;
float alpha;
if( findKeyframes(time, this, f1, f2, alpha) ) {
if( findKeyframes(time, this, f1, f2, alpha) ) {
return {
(1.f - abs(glm::dot( f1.rotation, f2.rotation )) < 0.001f) ? f1.rotation
: glm::normalize(glm::mix(f1.rotation, f2.rotation, alpha)),
glm::normalize(glm::lerp(f1.rotation, f2.rotation, alpha)),
glm::mix(f1.position, f2.position, alpha),
glm::mix(f1.scale, f2.scale, alpha),
time

View File

@ -444,7 +444,15 @@ void GTARenderer::renderGeometry(Model* model, size_t g, const glm::mat4& modelM
bool GTARenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix, GameObject* object, bool queueTransparent)
{
auto localmatrix = matrix * f->getMatrix();
auto localmatrix = matrix;
if(object && object->animator) {
localmatrix *= object->animator->getFrameMatrix(f, 0.f);
}
else {
localmatrix *= f->getTransform();
}
bool vis = object == nullptr || object->isFrameVisible(f);
for(size_t g : f->getGeometries()) {
if(!vis ) continue;
@ -464,7 +472,7 @@ bool GTARenderer::renderFrame(Model* m, ModelFrame* f, const glm::mat4& matrix,
}
for(ModelFrame* c : f->getChildren()) {
renderFrame(m, c, matrix, object, queueTransparent);
renderFrame(m, c, localmatrix, object, queueTransparent);
}
return true;
}

View File

@ -0,0 +1,35 @@
#include "AnimationListModel.hpp"
QVariant AnimationListModel::data(const QModelIndex& index, int role) const
{
if(role == Qt::DisplayRole) {
if(index.row() < animations.size()) {
auto& f = animations.at(index.row());
if(index.column() == 0) {
return QString(f.first.c_str());
}
}
}
return QVariant::Invalid;
}
QVariant AnimationListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(role == Qt::DisplayRole && orientation == Qt::Horizontal) {
if(section == 0) {
return "Name";
}
}
return QVariant::Invalid;
}
int AnimationListModel::rowCount(const QModelIndex& parent) const
{
return animations.size();
}
int AnimationListModel::columnCount(const QModelIndex& parent) const
{
return 1;
}

View File

@ -0,0 +1,32 @@
#pragma once
#ifndef _ANIMATIONLISTMODEL_HPP_
#define _ANIMATIONLISTMODEL_HPP_
#include <QAbstractItemModel>
#include <loaders/LoaderIFP.hpp>
typedef std::vector<std::pair<std::string, Animation*>> AnimationList;
class AnimationListModel : public QAbstractListModel
{
Q_OBJECT
AnimationList animations;
public:
AnimationListModel(const AnimationList& anims, QObject* parent = 0)
: QAbstractListModel(parent), animations(anims)
{}
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
virtual int columnCount(const QModelIndex& parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
const AnimationList& getAnimations() const { return animations; }
};
#endif

View File

@ -0,0 +1,48 @@
#include "AnimationListWidget.hpp"
#include <QVBoxLayout>
AnimationListWidget::AnimationListWidget(QWidget* parent, Qt::WindowFlags flags)
: QDockWidget(parent, flags), filter(nullptr), model(nullptr)
{
setWindowTitle("Animations");
QVBoxLayout* layout = new QVBoxLayout();
QWidget* intermediate = new QWidget();
searchbox = new QLineEdit();
searchbox->setPlaceholderText("Search");
table = new QListView();
layout->addWidget(searchbox);
layout->addWidget(table);
intermediate->setLayout(layout);
setWidget(intermediate);
filter = new QSortFilterProxyModel;
table->setModel(filter);
connect(table->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(selectedIndexChanged(QModelIndex)));
connect(searchbox, SIGNAL(textChanged(QString)), SLOT(setFilter(QString)));
}
void AnimationListWidget::setAnimations(const AnimationList& archive)
{
auto m = new AnimationListModel(archive);
filter->setSourceModel(m);
if(model) {
delete model;
}
model = m;
}
void AnimationListWidget::selectedIndexChanged(const QModelIndex& current)
{
auto mts = filter->mapToSource(current);
if(mts.row() < model->getAnimations().size()) {
auto& f = model->getAnimations().at(mts.row());
emit selectedAnimationChanged(f.second);
}
}
void AnimationListWidget::setFilter(const QString &f)
{
filter->setFilterRegExp(QRegExp(f, Qt::CaseInsensitive));
}

View File

@ -0,0 +1,35 @@
#pragma once
#ifndef _ANIMATIONLISTWIDGET_HPP_
#define _ANIMATIONLISTWIDGET_HPP_
#include <QDockWidget>
#include <QListView>
#include <QLineEdit>
#include <QSortFilterProxyModel>
#include "AnimationListModel.hpp"
class AnimationListWidget : public QDockWidget
{
Q_OBJECT
QSortFilterProxyModel* filter;
AnimationListModel* model;
QListView* table;
QLineEdit* searchbox;
public:
AnimationListWidget(QWidget* parent = 0, Qt::WindowFlags flags = 0);
void setAnimations(const AnimationList& anims);
signals:
void selectedAnimationChanged(Animation* anim);
public slots:
void selectedIndexChanged(const QModelIndex& current);
void setFilter(const QString& f);
};
#endif

View File

@ -10,7 +10,9 @@ add_executable(rwviewer
IMGArchiveModel.cpp
ArchiveContentsWidget.cpp
DFFFramesTreeModel.cpp
ModelFramesWidget.cpp)
ModelFramesWidget.cpp
AnimationListModel.cpp
AnimationListWidget.cpp)
include_directories("${CMAKE_SOURCE_DIR}/rwengine/include" /usr/include/bullet)

View File

@ -2,10 +2,13 @@
#include <render/Model.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <QMouseEvent>
#include <engine/GameObject.hpp>
#include <engine/Animator.hpp>
ViewerWidget::ViewerWidget(QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f)
: QGLWidget(parent, shareWidget, f), gworld(nullptr), cmodel(nullptr),
viewDistance(1.f), dragging(false), fm(ViewerWidget::UNK)
: QGLWidget(parent, shareWidget, f), gworld(nullptr), dummyObject(nullptr),
cmodel(nullptr), canimation(nullptr), viewDistance(1.f), dragging(false),
fm(ViewerWidget::UNK)
{
}
@ -41,6 +44,10 @@ void ViewerWidget::paintGL()
r.camera.frustum.near = 0.1f;
r.camera.frustum.fov = 60.f;
r.camera.frustum.aspectRatio = width()/(height()*1.f);
if(dummyObject && dummyObject->animator) {
dummyObject->animator->tick(1.f/60.f);
}
if(cmodel) {
glEnable(GL_DEPTH_TEST);
@ -64,7 +71,7 @@ void ViewerWidget::paintGL()
glUniformMatrix4fv(r.uniView, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(r.uniProj, 1, GL_FALSE, glm::value_ptr(proj));
gworld->renderer.renderModel(cmodel, m);
gworld->renderer.renderModel(cmodel, m, dummyObject);
}
}
@ -96,7 +103,9 @@ void ViewerWidget::showDFF(const QString& file)
auto mit = gworld->gameData.models.find(basename.toStdString());
if(mit != gworld->gameData.models.end()) {
// TODO better error handling
if(dummyObject) delete dummyObject;
cmodel = mit->second;
dummyObject = new GameObject(gworld, glm::vec3(), glm::quat(), cmodel);
float radius = 0.f;
for(auto& g
: cmodel->geometries) {
@ -115,6 +124,18 @@ void ViewerWidget::showTXD(const QString& file)
fm = ViewerWidget::TXD;
}
void ViewerWidget::showAnimation(Animation *anim)
{
canimation = anim;
if(dummyObject) {
if(dummyObject->animator == nullptr) {
dummyObject->animator = new Animator;
dummyObject->animator->setModel(dummyObject->model);
}
dummyObject->animator->setAnimation(canimation);
}
}
Model* ViewerWidget::currentModel() const
{
return cmodel;

View File

@ -5,6 +5,7 @@
#include <engine/GameWorld.hpp>
#include <QGLWidget>
#include <QTimer>
#include <loaders/LoaderIFP.hpp>
class Model;
class ViewerWidget : public QGLWidget
@ -15,8 +16,11 @@ class ViewerWidget : public QGLWidget
QTimer timer;
GameWorld* gworld;
GameObject* dummyObject;
Model* cmodel;
Animation* canimation;
float viewDistance;
glm::vec2 viewAngles;
@ -50,6 +54,8 @@ public slots:
void showDFF(const QString& file);
void showTXD(const QString& file);
void showAnimation(Animation* anim);
signals:
void fileOpened(const QString& file);
@ -65,4 +71,4 @@ private:
FileMode fm;
};
#endif
#endif

View File

@ -3,10 +3,12 @@
#include "ViewerWidget.hpp"
#include "ArchiveContentsWidget.hpp"
#include "ModelFramesWidget.hpp"
#include "AnimationListWidget.hpp"
#include <QMenuBar>
#include <QFileDialog>
#include <QApplication>
#include <QSettings>
#include <fstream>
static int MaxRecentArchives = 5;
@ -24,6 +26,10 @@ ViewerWindow::ViewerWindow(QWidget* parent, Qt::WindowFlags flags): QMainWindow(
frameswidget = new ModelFramesWidget;
frameswidget->setObjectName("frameswidget");
this->addDockWidget(Qt::RightDockWidgetArea, frameswidget);
animationswidget = new AnimationListWidget;
animationswidget->setObjectName("animationswidget");
this->addDockWidget(Qt::RightDockWidgetArea, animationswidget);
QMenuBar* mb = this->menuBar();
QMenu* file = mb->addMenu("&File");
@ -38,8 +44,12 @@ ViewerWindow::ViewerWindow(QWidget* parent, Qt::WindowFlags flags): QMainWindow(
auto ex = file->addAction("E&xit");
ex->setShortcut(QKeySequence::Quit);
connect(ex, SIGNAL(triggered()), QApplication::instance(), SLOT(closeAllWindows()));
QMenu* anim = mb->addMenu("&Animation");
anim->addAction("Load &Animations", this, SLOT(openAnimations()));
connect(archivewidget, SIGNAL(selectedFileChanged(QString)), viewer, SLOT(showFile(QString)));
connect(animationswidget, SIGNAL(selectedAnimationChanged(Animation*)), viewer, SLOT(showAnimation(Animation*)));
connect(viewer, SIGNAL(fileOpened(QString)), SLOT(openFileChanged(QString)));
updateRecentArchives();
@ -97,6 +107,35 @@ void ViewerWindow::openArchive()
}
}
void ViewerWindow::openAnimations()
{
QFileDialog dialog(this, "Open Animations", QDir::homePath(), "IFP Animations (*.ifp)");
if(dialog.exec()) {
std::ifstream dfile(dialog.selectedFiles().at(0).toStdString().c_str());
AnimationList anims;
if(dfile.is_open())
{
dfile.seekg(0, std::ios_base::end);
size_t length = dfile.tellg();
dfile.seekg(0);
char *file = new char[length];
dfile.read(file, length);
LoaderIFP loader;
if( loader.loadFromMemory(file) ) {
for(auto& f : loader.animations) {
anims.push_back(f);
}
}
delete[] file;
}
animationswidget->setAnimations(anims);
}
}
void ViewerWindow::openFileChanged(const QString& name)
{
setWindowTitle(name);

View File

@ -5,7 +5,9 @@
class ModelFramesWidget;
class ArchiveContentsWidget;
class AnimationListWidget;
class ViewerWidget;
class ViewerWindow : public QMainWindow
{
Q_OBJECT
@ -13,6 +15,7 @@ class ViewerWindow : public QMainWindow
ViewerWidget* viewer;
ArchiveContentsWidget* archivewidget;
ModelFramesWidget* frameswidget;
AnimationListWidget* animationswidget;
public:
ViewerWindow(QWidget* parent = 0, Qt::WindowFlags flags = 0);
@ -27,6 +30,8 @@ public slots:
void openArchive();
void openAnimations();
private slots:
void openFileChanged(const QString& name);
@ -39,4 +44,4 @@ private:
void updateRecentArchives();
};
#endif
#endif