Added support for bone selection in the character editor

This commit is contained in:
parax0 2016-05-01 21:01:15 -06:00
parent ed16d05136
commit 709087d2fe
10 changed files with 108 additions and 7 deletions

View File

@ -8,6 +8,7 @@
// ************ CBone ************
CBone::CBone(CSkeleton *pSkel)
: mpSkeleton(pSkel)
, mSelected(false)
{
}
@ -115,12 +116,23 @@ void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, fl
void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData *pkData)
{
glBlendFunc(GL_ONE, GL_ZERO);
// Draw all child links first to minimize model matrix swaps.
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
CBone *pBone = mBones[iBone];
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
// Draw the bone's local XYZ axes for selected bones
if (pBone->IsSelected())
{
CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation();
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::skRed);
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::skGreen);
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::skBlue);
}
// Draw child links
for (u32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
{
@ -143,7 +155,7 @@ void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData *pkDat
Transform.Translate(BonePos);
CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform;
CGraphics::UpdateMVPBlock();
CDrawUtil::DrawSphere(CColor::skWhite);
CDrawUtil::DrawSphere(pBone->IsSelected() ? CColor::skRed : CColor::skWhite);
}
}

View File

@ -61,6 +61,7 @@ class CBone
CQuaternion mLocalRotation;
TString mName;
CTransform4f mInvBind;
bool mSelected;
public:
CBone(CSkeleton *pSkel);
@ -80,6 +81,9 @@ public:
inline CQuaternion Rotation() const { return mRotation; }
inline CQuaternion LocalRotation() const { return mLocalRotation; }
inline TString Name() const { return mName; }
inline bool IsSelected() const { return mSelected; }
inline void SetSelected(bool Selected) { mSelected = Selected; }
};
#endif // CSKELETON_H

View File

@ -1,6 +1,7 @@
#include "CCharacterEditor.h"
#include "ui_CCharacterEditor.h"
#include "Editor/UICommon.h"
#include <Common/Assert.h>
#include <Math/MathUtil.h>
#include <QFileDialog>
#include <QTreeView>
@ -10,6 +11,7 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
, ui(new Ui::CCharacterEditor)
, mpScene(new CScene())
, mpCharNode(new CCharacterNode(mpScene, -1))
, mpSelectedBone(nullptr)
, mAnimTime(0.f)
, mPlayAnim(true)
, mLoopAnim(true)
@ -38,7 +40,8 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
connect(&mRefreshTimer, SIGNAL(timeout()), this, SLOT(RefreshViewport()));
mRefreshTimer.start(0);
connect(ui->Viewport, SIGNAL(HoverBoneChanged(u32)), this, SLOT(HoverBoneChanged(u32)));
connect(ui->Viewport, SIGNAL(HoverBoneChanged(u32)), this, SLOT(OnViewportHoverBoneChanged(u32)));
connect(ui->Viewport, SIGNAL(ViewportClick(QMouseEvent*)), this, SLOT(OnViewportClick()));
connect(ui->ActionOpen, SIGNAL(triggered()), this, SLOT(Open()));
connect(ui->ActionShowSkeleton, SIGNAL(toggled(bool)), this, SLOT(ToggleSkeletonVisible(bool)));
connect(mpCharComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveCharacterIndex(int)));
@ -54,6 +57,8 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
QList<int> SplitterSizes;
SplitterSizes << width() * 0.2 << width() * 0.8;
ui->splitter->setSizes(SplitterSizes);
connect(ui->SkeletonHierarchyTreeView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex,QModelIndex)), this, SLOT(OnSkeletonTreeSelectionChanged(QModelIndex)));
}
CCharacterEditor::~CCharacterEditor()
@ -114,6 +119,16 @@ CAnimation* CCharacterEditor::CurrentAnimation() const
return nullptr;
}
void CCharacterEditor::SetSelectedBone(CBone *pBone)
{
if (pBone != mpSelectedBone)
{
if (mpSelectedBone) mpSelectedBone->SetSelected(false);
mpSelectedBone = pBone;
if (mpSelectedBone) mpSelectedBone->SetSelected(true);
}
}
// ************ PUBLIC SLOTS ************
void CCharacterEditor::Open()
{
@ -127,6 +142,10 @@ void CCharacterEditor::Open()
mpCharNode->SetCharSet(mpSet);
setWindowTitle("Prime World Editor - Character Editor: " + TO_QSTRING(mpSet->Source()));
// Clear selected bone
ui->SkeletonHierarchyTreeView->selectionModel()->clear();
SetSelectedBone(nullptr);
// Set up character combo box
mpCharComboBox->blockSignals(true);
mpCharComboBox->clear();
@ -169,7 +188,7 @@ void CCharacterEditor::RefreshViewport()
ui->Viewport->Render();
}
void CCharacterEditor::HoverBoneChanged(u32 BoneID)
void CCharacterEditor::OnViewportHoverBoneChanged(u32 BoneID)
{
if (BoneID == 0xFFFFFFFF)
ui->StatusBar->clearMessage();
@ -177,6 +196,32 @@ void CCharacterEditor::HoverBoneChanged(u32 BoneID)
ui->StatusBar->showMessage(QString("Bone %1: %2").arg(BoneID).arg( TO_QSTRING(mpSet->NodeSkeleton(mCurrentChar)->BoneByID(BoneID)->Name()) ));
}
void CCharacterEditor::OnViewportClick()
{
u32 HoverBoneID = ui->Viewport->HoverBoneID();
CSkeleton *pSkel = (mpSet ? mpSet->NodeSkeleton(mCurrentChar) : nullptr);
CBone *pBone = (pSkel ? pSkel->BoneByID(HoverBoneID) : nullptr);
if (!pBone || !pBone->IsSelected())
{
if (pBone)
{
QModelIndex NewBoneIndex = mSkeletonModel.IndexForBone(pBone);
ui->SkeletonHierarchyTreeView->selectionModel()->setCurrentIndex(NewBoneIndex, QItemSelectionModel::ClearAndSelect);
}
else
ui->SkeletonHierarchyTreeView->selectionModel()->clear();
SetSelectedBone(pBone);
}
}
void CCharacterEditor::OnSkeletonTreeSelectionChanged(const QModelIndex& rkIndex)
{
CBone *pBone = mSkeletonModel.BoneForIndex(rkIndex);
SetSelectedBone(pBone);
}
void CCharacterEditor::SetActiveCharacterIndex(int CharIndex)
{
mCurrentChar = CharIndex;

View File

@ -21,6 +21,7 @@ class CCharacterEditor : public QMainWindow
Ui::CCharacterEditor *ui;
CScene *mpScene;
CCharacterNode *mpCharNode;
CBone *mpSelectedBone;
CSkeletonHierarchyModel mSkeletonModel;
QComboBox *mpCharComboBox;
@ -44,17 +45,20 @@ public:
~CCharacterEditor();
void UpdateAnimTime();
CAnimation* CurrentAnimation() const;
void SetSelectedBone(CBone *pBone);
public slots:
void Open();
void ToggleSkeletonVisible(bool Visible);
void RefreshViewport();
void HoverBoneChanged(u32 BoneID);
void OnViewportHoverBoneChanged(u32 BoneID);
void OnViewportClick();
void OnSkeletonTreeSelectionChanged(const QModelIndex& rkIndex);
void SetActiveCharacterIndex(int CharIndex);
void SetActiveAnimation(int AnimIndex);
void SetAnimTime(int Time);
void SetAnimTime(float Time);
void TogglePlay();
void ToggleLoop(bool Loop);
void AnimSpeedSpinBoxChanged(double NewVal);

View File

@ -31,7 +31,7 @@
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>

View File

@ -64,3 +64,11 @@ void CCharacterEditorViewport::OnResize()
{
mpRenderer->SetViewportSize(width(), height());
}
void CCharacterEditorViewport::OnMouseClick(QMouseEvent *pEvent)
{
if (pEvent->button() == Qt::LeftButton)
{
emit ViewportClick(pEvent);
}
}

View File

@ -21,9 +21,13 @@ public:
void CheckUserInput();
void Paint();
void OnResize();
void OnMouseClick(QMouseEvent *pEvent);
inline u32 HoverBoneID() const { return mHoverBone; }
signals:
void HoverBoneChanged(u32 BoneID);
void ViewportClick(QMouseEvent *pEvent);
};
#endif // CCHARACTEREDITORVIEWPORT_H

View File

@ -76,6 +76,27 @@ QVariant CSkeletonHierarchyModel::data(const QModelIndex& rkIndex, int Role) con
return QVariant::Invalid;
}
CBone* CSkeletonHierarchyModel::BoneForIndex(const QModelIndex& rkIndex) const
{
return (CBone*) (rkIndex.internalPointer());
}
QModelIndex CSkeletonHierarchyModel::IndexForBone(CBone *pBone) const
{
CBone *pParent = pBone->Parent();
if (!pParent) return index(0, 0, QModelIndex());
QModelIndex ParentIndex = IndexForBone(pParent);
for (u32 iChild = 0; iChild < pParent->NumChildren(); iChild++)
{
if (pParent->ChildByIndex(iChild) == pBone)
return index(iChild, 0, ParentIndex);
}
return QModelIndex();
}
void CSkeletonHierarchyModel::SetSkeleton(CSkeleton *pSkel)
{
if (mpSkeleton != pSkel)

View File

@ -15,6 +15,9 @@ public:
int rowCount(const QModelIndex& rkParent) const;
int columnCount(const QModelIndex& rkParent) const;
QVariant data(const QModelIndex& rkIndex, int Role) const;
CBone* BoneForIndex(const QModelIndex& rkIndex) const;
QModelIndex IndexForBone(CBone *pBone) const;
void SetSkeleton(CSkeleton *pSkel);
};

View File

@ -5,7 +5,7 @@
#include <math.h>
CQuaternion::CQuaternion()
: W(0.f)
: W(1.f)
, X(0.f)
, Y(0.f)
, Z(0.f)