Added a bunch of new options and tools to the character editor

This commit is contained in:
parax0 2016-05-02 05:23:16 -06:00
parent 7880dd34f4
commit 2db740e572
10 changed files with 367 additions and 41 deletions

View File

@ -179,6 +179,18 @@ void CCamera::SetOrbit(const CAABox& OrbitTarget, float DistScale /*= 4.f*/)
}
}
void CCamera::SetOrbitTarget(const CVector3f& rkOrbitTarget)
{
mOrbitTarget = rkOrbitTarget;
if (mMode == eOrbitCamera)
{
mTransformDirty = true;
mViewDirty = true;
mFrustumPlanesDirty = true;
}
}
void CCamera::SetOrbitDistance(float Distance)
{
mOrbitDistance = Distance;

View File

@ -65,6 +65,7 @@ public:
void SetMoveMode(ECameraMoveMode Mode);
void SetOrbit(const CVector3f& rkOrbitTarget, float Distance);
void SetOrbit(const CAABox& rkOrbitTarget, float DistScale = 4.f);
void SetOrbitTarget(const CVector3f& rkOrbitTarget);
void SetOrbitDistance(float Distance);
// Inline Accessors

View File

@ -117,6 +117,7 @@ void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, fl
void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData *pkData)
{
glBlendFunc(GL_ONE, GL_ZERO);
glLineWidth(1.f);
// Draw all child links first to minimize model matrix swaps.
for (u32 iBone = 0; iBone < mBones.size(); iBone++)

View File

@ -4,6 +4,7 @@
CCharacterNode::CCharacterNode(CScene *pScene, u32 NodeID, CAnimSet *pChar /*= 0*/, CSceneNode *pParent /*= 0*/)
: CSceneNode(pScene, NodeID, pParent)
, mAnimated(true)
, mAnimTime(0.f)
{
SetCharSet(pChar);
@ -25,14 +26,15 @@ void CCharacterNode::PostLoad()
void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo)
{
if (!mpCharacter) return;
// todo: frustum check. Currently don't have a means of pulling the AABox for the
// current animation so this isn't in yet.
if (!mpCharacter) return;
UpdateTransformData();
CModel *pModel = mpCharacter->NodeModel(mActiveCharSet);
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
if (pModel)
if (pModel && rkViewInfo.ShowFlags.HasFlag(eShowObjectGeometry))
{
if (!pModel->HasTransparency(0))
pRenderer->AddMesh(this, -1, AABox(), false, eDrawMesh);
@ -42,9 +44,6 @@ void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkView
if (pSkel)
{
CAnimation *pAnim = mpCharacter->Animation(mActiveAnim);
pSkel->UpdateTransform(mTransformData, pAnim, mAnimTime, false);
if (rkViewInfo.ShowFlags.HasFlag(eShowSkeletons))
pRenderer->AddMesh(this, -2, AABox(), false, eDrawMesh, eForeground);
}
@ -57,6 +56,7 @@ void CCharacterNode::Draw(FRenderOptions Options, int ComponentIndex, const SVie
// Draw skeleton
if (ComponentIndex == -2)
{
LoadModelMatrix();
pSkel->Draw(Options, &mTransformData);
}
@ -70,9 +70,14 @@ void CCharacterNode::Draw(FRenderOptions Options, int ComponentIndex, const SVie
CGraphics::sPixelBlock.LightmapMultiplier = 1.f;
CGraphics::sPixelBlock.TevColor = CColor::skWhite;
CGraphics::sPixelBlock.TintColor = TintColor(rkViewInfo);
LoadModelMatrix();
// Draw surface OR draw entire model
if (mAnimated)
CGraphics::LoadBoneTransforms(mTransformData);
else
CGraphics::LoadIdentityBoneTransforms();
CModel *pModel = mpCharacter->NodeModel(mActiveCharSet);
if (ComponentIndex < 0)
@ -91,6 +96,7 @@ SRayIntersection CCharacterNode::RayNodeIntersectTest(const CRay& rkRay, u32 /*A
if (pSkel)
{
UpdateTransformData();
std::pair<s32,float> Hit = pSkel->RayIntersect(rkRay, mTransformData);
if (Hit.first != -1)
@ -109,10 +115,22 @@ SRayIntersection CCharacterNode::RayNodeIntersectTest(const CRay& rkRay, u32 /*A
return SRayIntersection();
}
CVector3f CCharacterNode::BonePosition(u32 BoneID)
{
UpdateTransformData();
CSkeleton *pSkel = (mpCharacter ? mpCharacter->NodeSkeleton(mActiveCharSet) : nullptr);
CBone *pBone = (pSkel ? pSkel->BoneByID(BoneID) : nullptr);
CVector3f Out = AbsolutePosition();
if (pBone) Out += pBone->TransformedPosition(mTransformData);
return Out;
}
void CCharacterNode::SetCharSet(CAnimSet *pChar)
{
mpCharacter = pChar;
SetActiveChar(0);
ConditionalSetDirty();
if (!mpCharacter)
mLocalAABox = CAABox::skOne;
@ -121,6 +139,7 @@ void CCharacterNode::SetCharSet(CAnimSet *pChar)
void CCharacterNode::SetActiveChar(u32 CharIndex)
{
mActiveCharSet = CharIndex;
ConditionalSetDirty();
if (mpCharacter)
{
@ -134,9 +153,16 @@ void CCharacterNode::SetActiveChar(u32 CharIndex)
void CCharacterNode::SetActiveAnim(u32 AnimIndex)
{
mActiveAnim = AnimIndex;
ConditionalSetDirty();
}
void CCharacterNode::SetAnimTime(float Time)
// ************ PROTECTED ************
void CCharacterNode::UpdateTransformData()
{
mAnimTime = Time;
if (mTransformDataDirty)
{
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
if (pSkel) pSkel->UpdateTransform(mTransformData, CurrentAnim(), mAnimTime, false);
mTransformDataDirty = false;
}
}

View File

@ -11,8 +11,11 @@ class CCharacterNode : public CSceneNode
CBoneTransformData mTransformData;
u32 mActiveCharSet;
u32 mActiveAnim;
bool mAnimated;
float mAnimTime;
mutable bool mTransformDataDirty;
public:
explicit CCharacterNode(CScene *pScene, u32 NodeID, CAnimSet *pChar = 0, CSceneNode *pParent = 0);
@ -21,14 +24,26 @@ public:
virtual void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo);
virtual void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo);
virtual SRayIntersection RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo);
inline CAnimSet* Character() const { return mpCharacter; }
inline u32 ActiveCharSet() const { return mActiveCharSet; }
inline u32 ActiveAnim() const { return mActiveAnim; }
CVector3f BonePosition(u32 BoneID);
void SetCharSet(CAnimSet *pChar);
void SetActiveChar(u32 CharIndex);
void SetActiveAnim(u32 AnimIndex);
void SetAnimTime(float Time);
inline CAnimSet* Character() const { return mpCharacter; }
inline u32 ActiveCharIndex() const { return mActiveCharSet; }
inline u32 ActiveAnimIndex() const { return mActiveAnim; }
inline CAnimation* CurrentAnim() const { return (mAnimated && mpCharacter ? mpCharacter->Animation(mActiveAnim) : nullptr); }
inline bool IsAnimated() const { return (mAnimated && CurrentAnim() != nullptr); }
void SetAnimated(bool Animated) { mAnimated = Animated; SetDirty(); }
void SetAnimTime(float Time) { mAnimTime = Time; ConditionalSetDirty(); }
protected:
inline bool IsDirty() { return mTransformDataDirty; }
inline void SetDirty() { mTransformDataDirty = true; }
inline void ConditionalSetDirty() { if (IsAnimated()) SetDirty(); }
void UpdateTransformData();
};
#endif // CCHARACTERNODE_H

View File

@ -4,14 +4,19 @@
#include <Common/Assert.h>
#include <Math/MathUtil.h>
#include <QFileDialog>
#include <QMessageBox>
#include <QTreeView>
const CVector3f CCharacterEditor::skDefaultOrbitTarget = CVector3f(0,0,1);
const float CCharacterEditor::skDefaultOrbitDistance = 4.f;
CCharacterEditor::CCharacterEditor(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::CCharacterEditor)
, mpScene(new CScene())
, mpCharNode(new CCharacterNode(mpScene, -1))
, mpSelectedBone(nullptr)
, mBindPose(false)
, mAnimTime(0.f)
, mPlayAnim(true)
, mLoopAnim(true)
@ -22,9 +27,9 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
ui->Viewport->SetNode(mpCharNode);
CCamera& rCamera = ui->Viewport->Camera();
rCamera.Snap(CVector3f(0, 3, 1));
rCamera.SetOrbit(CVector3f(0, 0, 1), 3.f);
rCamera.SetMoveSpeed(0.5f);
rCamera.SetPitch(-0.3f);
rCamera.SetMoveMode(eOrbitCamera);
// Init UI
ui->ToolBar->addSeparator();
@ -43,13 +48,24 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
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->ActionShowGrid, SIGNAL(toggled(bool)), this, SLOT(ToggleGrid(bool)));
connect(ui->ActionShowMesh, SIGNAL(toggled(bool)), this, SLOT(ToggleMeshVisible(bool)));
connect(ui->ActionShowSkeleton, SIGNAL(toggled(bool)), this, SLOT(ToggleSkeletonVisible(bool)));
connect(ui->ActionBindPose, SIGNAL(toggled(bool)), this, SLOT(ToggleBindPose(bool)));
connect(ui->ActionOrbit, SIGNAL(toggled(bool)), this, SLOT(ToggleOrbit(bool)));
connect(ui->ActionPlay, SIGNAL(triggered()), this, SLOT(TogglePlay()));
connect(ui->ActionRewind, SIGNAL(triggered()), this, SLOT(Rewind()));
connect(ui->ActionFastForward, SIGNAL(triggered()), this, SLOT(FastForward()));
connect(ui->ActionPrevAnim, SIGNAL(triggered()), this, SLOT(PrevAnim()));
connect(ui->ActionNextAnim, SIGNAL(triggered()), this, SLOT(NextAnim()));
connect(mpCharComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveCharacterIndex(int)));
connect(mpAnimComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveAnimation(int)));
connect(ui->AnimSlider, SIGNAL(valueChanged(int)), this, SLOT(SetAnimTime(int)));
connect(ui->PlayPauseButton, SIGNAL(pressed()), this, SLOT(TogglePlay()));
connect(ui->LoopButton, SIGNAL(toggled(bool)), this, SLOT(ToggleLoop(bool)));
connect(ui->RewindButton, SIGNAL(pressed()), this, SLOT(Rewind()));
connect(ui->FastForwardButton, SIGNAL(pressed()), this, SLOT(FastForward()));
connect(ui->AnimSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(AnimSpeedSpinBoxChanged(double)));
// Init skeleton tree view
@ -59,23 +75,6 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
ui->splitter->setSizes(SplitterSizes);
connect(ui->SkeletonHierarchyTreeView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnSkeletonTreeSelectionChanged(QModelIndex)));
// Set up keyboard shortcuts
QAction *pTogglePlayAction = new QAction(this);
pTogglePlayAction->setShortcut(QKeySequence("Space"));
connect(pTogglePlayAction, SIGNAL(triggered()), this, SLOT(TogglePlay()));
QAction *pPrevAnimAction = new QAction(this);
pPrevAnimAction->setShortcut(QKeySequence("R"));
connect(pPrevAnimAction, SIGNAL(triggered()), this, SLOT(PrevAnim()));
QAction *pNextAnimAction = new QAction(this);
pNextAnimAction->setShortcut(QKeySequence("F"));
connect(pNextAnimAction, SIGNAL(triggered()), this, SLOT(NextAnim()));
QList<QAction*> ShortcutActions;
ShortcutActions << pTogglePlayAction << pPrevAnimAction << pNextAnimAction;
addActions(ShortcutActions);
}
CCharacterEditor::~CCharacterEditor()
@ -91,7 +90,7 @@ void CCharacterEditor::UpdateAnimTime()
CAnimation *pAnim = CurrentAnimation();
if (pAnim && mPlayAnim && !ui->AnimSlider->isSliderDown())
if (pAnim && mPlayAnim && !mBindPose && !ui->AnimSlider->isSliderDown())
{
mAnimTime += DeltaTime * mPlaybackSpeed;
@ -128,6 +127,44 @@ void CCharacterEditor::UpdateAnimTime()
}
}
void CCharacterEditor::UpdateCameraOrbit()
{
CSkeleton *pSkel = CurrentSkeleton();
if (!pSkel)
{
// Center around character if we have one, otherwise fall back to default orbit.
if (mpSet)
ui->Viewport->Camera().SetOrbitTarget(mpCharNode->CenterPoint());
else
ui->Viewport->Camera().SetOrbit(skDefaultOrbitTarget, skDefaultOrbitDistance);
}
else
{
// If we have a selected bone, orbit around that.
if (mpSelectedBone)
ui->Viewport->Camera().SetOrbitTarget(mpCharNode->BonePosition(mpSelectedBone->ID()));
// Otherwise, try to find Skeleton_Root. Barring that, we can orbit the root bone.
else
{
CBone *pRoot = pSkel->RootBone();
CBone *pSkelRoot = (pRoot ? pRoot->ChildByIndex(0) : pRoot);
CVector3f OrbitTarget = (pSkelRoot ? mpCharNode->BonePosition(pSkelRoot->ID()) : mpCharNode->CenterPoint());
ui->Viewport->Camera().SetOrbitTarget(OrbitTarget);
}
}
}
CSkeleton* CCharacterEditor::CurrentSkeleton() const
{
if (mpSet)
return mpSet->NodeSkeleton(mCurrentChar);
else
return nullptr;
}
CAnimation* CCharacterEditor::CurrentAnimation() const
{
if (mpSet)
@ -152,10 +189,11 @@ void CCharacterEditor::Open()
QString CharFilename = QFileDialog::getOpenFileName(this, "Open Character", "", "Animation Character Set (*.ANCS)");
if (CharFilename.isEmpty()) return;
mpSet = gResCache.GetResource(CharFilename.toStdString());
CAnimSet *pSet = (CAnimSet*) gResCache.GetResource(CharFilename.toStdString());
if (mpSet)
if (pSet)
{
mpSet = pSet;
mpCharNode->SetCharSet(mpSet);
setWindowTitle("Prime World Editor - Character Editor: " + TO_QSTRING(mpSet->Source()));
@ -189,21 +227,67 @@ void CCharacterEditor::Open()
ui->SkeletonHierarchyTreeView->expandAll();
ui->SkeletonHierarchyTreeView->resizeColumnToContents(0);
// Would rather it just clear the selection on load, but it keeps selecting root by itself, so this is my workaround. :/
ui->SkeletonHierarchyTreeView->selectionModel()->setCurrentIndex( mSkeletonModel.index(0, 0, QModelIndex()), QItemSelectionModel::ClearAndSelect );
// Select first child bone of root (which should be Skeleton_Root) to line up the camera for orbiting.
QModelIndex RootIndex = mSkeletonModel.index(0, 0, QModelIndex());
ui->SkeletonHierarchyTreeView->selectionModel()->setCurrentIndex( mSkeletonModel.index(0, 0, RootIndex), QItemSelectionModel::ClearAndSelect );
// Run CCamera::SetOrbit to reset orbit distance.
ui->Viewport->Camera().SetOrbit(mpCharNode->AABox(), 4.f);
}
else
{
QMessageBox::warning(this, "Error", "Couldn't load file: " + CharFilename);
}
gResCache.Clean();
}
void CCharacterEditor::ToggleGrid(bool Enable)
{
ui->Viewport->SetGridEnabled(Enable);
}
void CCharacterEditor::ToggleMeshVisible(bool Visible)
{
// eShowObjectGeometry isn't the best fit, but close enough...?
ui->Viewport->SetShowFlag(eShowObjectGeometry, Visible);
}
void CCharacterEditor::ToggleSkeletonVisible(bool Visible)
{
ui->Viewport->SetShowFlag(eShowSkeletons, Visible);
}
void CCharacterEditor::ToggleBindPose(bool Enable)
{
mpCharNode->SetAnimated(!Enable);
if (sender() != ui->ActionBindPose)
{
ui->ActionBindPose->blockSignals(true);
ui->ActionBindPose->setChecked(Enable);
ui->ActionBindPose->blockSignals(false);
}
if (Enable && mPlayAnim)
{
SetAnimTime(0.f);
}
ui->AnimSlider->setEnabled(!Enable);
mBindPose = Enable;
}
void CCharacterEditor::ToggleOrbit(bool Enable)
{
ui->Viewport->Camera().SetMoveMode(Enable ? eOrbitCamera : eFreeCamera);
}
void CCharacterEditor::RefreshViewport()
{
UpdateAnimTime();
UpdateCameraOrbit();
ui->Viewport->ProcessInput();
ui->Viewport->Render();
}
@ -284,9 +368,10 @@ void CCharacterEditor::SetAnimTime(int Time)
void CCharacterEditor::SetAnimTime(float Time)
{
if (mBindPose) Time = 0.f;
mAnimTime = Time;
if (ui->AnimSlider != sender())
if (ui->AnimSlider != sender() || mBindPose)
{
int IntTime = (int) (Time * 1000);
ui->AnimSlider->setValue(IntTime);
@ -308,10 +393,19 @@ void CCharacterEditor::SetAnimTime(float Time)
void CCharacterEditor::TogglePlay()
{
if (mBindPose) ToggleBindPose(false);
mPlayAnim = !mPlayAnim;
QString NewText = (mPlayAnim ? "Pause" : "Play");
ui->PlayPauseButton->setText(NewText);
if (ui->ActionPlay != sender())
{
ui->ActionPlay->blockSignals(true);
ui->ActionPlay->setChecked(mPlayAnim);
ui->ActionPlay->blockSignals(false);
}
CAnimation *pAnim = CurrentAnimation();
if (pAnim && mPlayAnim)
@ -331,6 +425,17 @@ void CCharacterEditor::ToggleLoop(bool Loop)
ui->LoopButton->setChecked(Loop);
}
void CCharacterEditor::Rewind()
{
SetAnimTime(0.f);
}
void CCharacterEditor::FastForward()
{
CAnimation *pAnim = CurrentAnimation();
if (pAnim && !mBindPose) SetAnimTime(pAnim->Duration());
}
void CCharacterEditor::AnimSpeedSpinBoxChanged(double NewVal)
{
mPlaybackSpeed = (float) NewVal;

View File

@ -31,7 +31,7 @@ class CCharacterEditor : public QMainWindow
TResPtr<CAnimSet> mpSet;
u32 mCurrentChar;
u32 mCurrentAnim;
bool mShowSkeleton;
bool mBindPose;
// Playback Controls
double mLastAnimUpdate;
@ -40,16 +40,26 @@ class CCharacterEditor : public QMainWindow
bool mLoopAnim;
float mPlaybackSpeed;
// Constants
static const CVector3f skDefaultOrbitTarget;
static const float skDefaultOrbitDistance;
public:
explicit CCharacterEditor(QWidget *parent = 0);
~CCharacterEditor();
void UpdateAnimTime();
void UpdateCameraOrbit();
CSkeleton* CurrentSkeleton() const;
CAnimation* CurrentAnimation() const;
void SetSelectedBone(CBone *pBone);
public slots:
void Open();
void ToggleGrid(bool Enable);
void ToggleMeshVisible(bool Visible);
void ToggleSkeletonVisible(bool Visible);
void ToggleBindPose(bool Enable);
void ToggleOrbit(bool Enable);
void RefreshViewport();
void OnViewportHoverBoneChanged(u32 BoneID);
void OnViewportClick();
@ -63,6 +73,8 @@ public slots:
void SetAnimTime(float Time);
void TogglePlay();
void ToggleLoop(bool Loop);
void Rewind();
void FastForward();
void AnimSpeedSpinBoxChanged(double NewVal);
};

View File

@ -83,6 +83,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="RewindButton">
<property name="text">
<string>Rewind</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="PlayPauseButton">
<property name="text">
@ -90,6 +97,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="FastForwardButton">
<property name="text">
<string>Fast Forward</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
@ -180,7 +194,25 @@
</property>
<addaction name="ActionOpen"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>Animation</string>
</property>
<addaction name="ActionShowGrid"/>
<addaction name="ActionShowMesh"/>
<addaction name="ActionShowSkeleton"/>
<addaction name="ActionBindPose"/>
<addaction name="ActionOrbit"/>
<addaction name="separator"/>
<addaction name="ActionPlay"/>
<addaction name="ActionRewind"/>
<addaction name="ActionFastForward"/>
<addaction name="separator"/>
<addaction name="ActionPrevAnim"/>
<addaction name="ActionNextAnim"/>
</widget>
<addaction name="MenuFile"/>
<addaction name="menuView"/>
</widget>
<widget class="QStatusBar" name="StatusBar"/>
<widget class="QToolBar" name="ToolBar">
@ -195,7 +227,11 @@
</attribute>
<addaction name="ActionOpen"/>
<addaction name="separator"/>
<addaction name="ActionShowGrid"/>
<addaction name="ActionShowMesh"/>
<addaction name="ActionShowSkeleton"/>
<addaction name="ActionBindPose"/>
<addaction name="ActionOrbit"/>
</widget>
<action name="ActionOpen">
<property name="icon">
@ -222,6 +258,121 @@
<property name="toolTip">
<string>Show Skeleton</string>
</property>
<property name="shortcut">
<string>2</string>
</property>
</action>
<action name="ActionShowMesh">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Show Mesh</string>
</property>
<property name="toolTip">
<string>Show Mesh</string>
</property>
<property name="shortcut">
<string>1</string>
</property>
</action>
<action name="ActionBindPose">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Bind Pose</string>
</property>
<property name="toolTip">
<string>Bind Pose</string>
</property>
<property name="shortcut">
<string>B</string>
</property>
</action>
<action name="ActionOrbit">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Orbit</string>
</property>
<property name="toolTip">
<string>Orbit</string>
</property>
<property name="shortcut">
<string>Z</string>
</property>
</action>
<action name="ActionShowGrid">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/GridLight.png</normaloff>:/icons/GridLight.png</iconset>
</property>
<property name="text">
<string>Show Grid</string>
</property>
<property name="shortcut">
<string>G</string>
</property>
</action>
<action name="ActionPrevAnim">
<property name="text">
<string>Previous Anim</string>
</property>
<property name="shortcut">
<string>R</string>
</property>
</action>
<action name="ActionNextAnim">
<property name="text">
<string>Next Anim</string>
</property>
<property name="shortcut">
<string>F</string>
</property>
</action>
<action name="ActionPlay">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Play</string>
</property>
<property name="shortcut">
<string>Space</string>
</property>
</action>
<action name="ActionRewind">
<property name="text">
<string>Rewind</string>
</property>
<property name="shortcut">
<string>Ctrl+R</string>
</property>
</action>
<action name="ActionFastForward">
<property name="text">
<string>Fast Forward</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property>
</action>
</widget>
<customwidgets>

View File

@ -3,13 +3,14 @@
CCharacterEditorViewport::CCharacterEditorViewport(QWidget *pParent /*= 0*/)
: CBasicViewport(pParent)
, mpCharNode(nullptr)
, mGridEnabled(true)
{
mpRenderer = new CRenderer();
mpRenderer->SetViewportSize(width(), height());
mpRenderer->SetClearColor(CColor(0.3f, 0.3f, 0.3f));
mpRenderer->ToggleGrid(true);
mViewInfo.ShowFlags = eShowNone; // The mesh doesn't check any show flags so this just disables the skeleton.
mViewInfo.ShowFlags = eShowObjectGeometry; // This enables the mesh and not the skeleton by default
mViewInfo.pRenderer = mpRenderer;
mViewInfo.pScene = nullptr;
mViewInfo.GameMode = false;
@ -49,7 +50,7 @@ void CCharacterEditorViewport::Paint()
{
mpRenderer->BeginFrame();
mCamera.LoadMatrices();
mGrid.AddToRenderer(mpRenderer, mViewInfo);
if (mGridEnabled) mGrid.AddToRenderer(mpRenderer, mViewInfo);
if (mpCharNode)
{

View File

@ -13,6 +13,7 @@ class CCharacterEditorViewport : public CBasicViewport
CGridRenderable mGrid;
CRenderer *mpRenderer;
u32 mHoverBone;
bool mGridEnabled;
public:
CCharacterEditorViewport(QWidget *pParent = 0);
@ -24,6 +25,7 @@ public:
void OnMouseClick(QMouseEvent *pEvent);
inline u32 HoverBoneID() const { return mHoverBone; }
inline void SetGridEnabled(bool Enable) { mGridEnabled = Enable; }
signals:
void HoverBoneChanged(u32 BoneID);