Added support for bone selection in the character editor
This commit is contained in:
parent
ed16d05136
commit
709087d2fe
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -64,3 +64,11 @@ void CCharacterEditorViewport::OnResize()
|
|||
{
|
||||
mpRenderer->SetViewportSize(width(), height());
|
||||
}
|
||||
|
||||
void CCharacterEditorViewport::OnMouseClick(QMouseEvent *pEvent)
|
||||
{
|
||||
if (pEvent->button() == Qt::LeftButton)
|
||||
{
|
||||
emit ViewportClick(pEvent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include <math.h>
|
||||
|
||||
CQuaternion::CQuaternion()
|
||||
: W(0.f)
|
||||
: W(1.f)
|
||||
, X(0.f)
|
||||
, Y(0.f)
|
||||
, Z(0.f)
|
||||
|
|
Loading…
Reference in New Issue