// NeL - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#include "std_afx.h"
#include "object_viewer.h"
#include "select_string.h"
#include "slot_dlg.h"
#include
#define DELTA_BLEND 0.1f
#define DELTA_TIME (getTimeIncrement ())
#define DELTA_MUL 0.1f
using namespace NLMISC;
using namespace NL3D;
/////////////////////////////////////////////////////////////////////////////
// CSlotDlg dialog
CSlotDlg::CSlotDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSlotDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CSlotDlg)
EndBlend = 1.0f;
Smoothness = 0.0f;
SpeedFactor = 1.0f;
StartBlend = 1.0f;
ClampMode = 0;
SkeletonWeightInverted = FALSE;
Offset = 0;
StartTime = 0;
EndTime = 0;
StartAnimTime=0.f;
EndAnimTime=1.f;
enable = TRUE;
//}}AFX_DATA_INIT
MainDlg=NULL;
}
void CSlotDlg::init (uint id, CObjectViewer* mainDlg)
{
Id=id;
MainDlg=mainDlg;
}
void CSlotDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSlotDlg)
DDX_Control(pDX, IDC_INVERT_SKELETON_WEIGHT, InvertSkeletonWeightCtrl);
DDX_Control(pDX, IDC_ALIGN_BLEND, AlignBlendCtrl);
DDX_Control(pDX, IDC_CLAMP, ClampCtrl);
DDX_Control(pDX, IDC_SCROLLBAR, ScrollBarCtrl);
DDX_Control(pDX, IDC_OFFSET_SPIN, OffsetSpinCtrl);
DDX_Control(pDX, IDC_OFFSET, OffsetCtrl);
DDX_Control(pDX, IDC_START_TIME_SPIN, StartTimeSpinCtrl);
DDX_Control(pDX, IDC_START_BLEND_SPIN, StartBlendSpinCtrl);
DDX_Control(pDX, IDC_SPEED_FACTOR_SPIN, SpeedFactorSpinCtrl);
DDX_Control(pDX, IDC_SMOOTHNESS_SPIN, SmoothnessSpinCtrl);
DDX_Control(pDX, IDC_END_TIME_SPIN, EndTimeSpinCtrl);
DDX_Control(pDX, IDC_END_BLEND_SPIN, EndBlendSpinCtrl);
DDX_Control(pDX, IDC_START_TIME, StartTimeCtrl);
DDX_Control(pDX, IDC_START_BLEND, StartBlendCtrl);
DDX_Control(pDX, IDC_SPEED_FACTOR, SpeddFactorCtrl);
DDX_Control(pDX, IDC_SMOOTHNESS, SmoothnessCtrl);
DDX_Control(pDX, IDC_END_TIME, EndTimeCtrl);
DDX_Control(pDX, IDC_END_BLEND, EndBlendCtrl);
DDX_Text(pDX, IDC_END_BLEND, EndBlend);
DDX_Text(pDX, IDC_SMOOTHNESS, Smoothness);
DDV_MinMaxFloat(pDX, Smoothness, 0.f, 1.f);
DDX_Text(pDX, IDC_SPEED_FACTOR, SpeedFactor);
DDV_MinMaxFloat(pDX, SpeedFactor, 1.e-002f, 100.f);
DDX_Text(pDX, IDC_START_BLEND, StartBlend);
DDV_MinMaxFloat(pDX, StartBlend, 0.f, 1.f);
DDX_Radio(pDX, IDC_CLAMP, ClampMode);
DDX_Check(pDX, IDC_INVERT_SKELETON_WEIGHT, SkeletonWeightInverted);
DDX_Text(pDX, IDC_OFFSET, Offset);
DDX_Text(pDX, IDC_START_TIME, StartTime);
DDX_Text(pDX, IDC_END_TIME, EndTime);
DDX_Check(pDX, IDC_ENABLE, enable);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSlotDlg, CDialog)
//{{AFX_MSG_MAP(CSlotDlg)
ON_WM_PAINT()
ON_NOTIFY(UDN_DELTAPOS, IDC_END_BLEND_SPIN, OnDeltaposEndBlendSpin)
ON_NOTIFY(UDN_DELTAPOS, IDC_END_TIME_SPIN, OnDeltaposEndTimeSpin)
ON_NOTIFY(UDN_DELTAPOS, IDC_SMOOTHNESS_SPIN, OnDeltaposSmoothnessSpin)
ON_NOTIFY(UDN_DELTAPOS, IDC_SPEED_FACTOR_SPIN, OnDeltaposSpeedFactorSpin)
ON_NOTIFY(UDN_DELTAPOS, IDC_START_BLEND_SPIN, OnDeltaposStartBlendSpin)
ON_NOTIFY(UDN_DELTAPOS, IDC_START_TIME_SPIN, OnDeltaposStartTimeSpin)
ON_EN_CHANGE(IDC_END_BLEND, OnChangeEndBlend)
ON_EN_CHANGE(IDC_END_TIME, OnChangeEndTime)
ON_EN_CHANGE(IDC_SMOOTHNESS, OnChangeSmoothness)
ON_EN_CHANGE(IDC_SPEED_FACTOR, OnChangeSpeedFactor)
ON_EN_CHANGE(IDC_START_BLEND, OnChangeStartBlend)
ON_EN_CHANGE(IDC_START_TIME, OnChangeStartTime)
ON_BN_CLICKED(IDC_SET_ANIMATION, OnSetAnimation)
ON_BN_CLICKED(IDC_SET_SKELETON, OnSetSkeleton)
ON_EN_CHANGE(IDC_OFFSET, OnChangeOffset)
ON_NOTIFY(UDN_DELTAPOS, IDC_OFFSET_SPIN, OnDeltaposOffsetSpin)
ON_WM_HSCROLL()
ON_BN_CLICKED(IDC_CLAMP, OnClamp)
ON_BN_CLICKED(IDC_REPEAT, OnRepeat)
ON_BN_CLICKED(IDC_DISABLE, OnDisable)
ON_BN_CLICKED(IDC_ALIGN_BLEND, OnAlignBlend)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_ENABLE, OnEnable)
ON_BN_CLICKED(IDC_INVERT_SKELETON_WEIGHT, OnInvertSkeletonWeight)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSlotDlg message handlers
BOOL CSlotDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Init the blend window
setWindowName ();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
// ***************************************************************************
void CSlotDlg::OnPaint()
{
//CPaintDC dc(this); // device context for painting
PAINTSTRUCT paint;
CDC* pDc=BeginPaint(&paint);
// TODO: Add your message handler code here
// Draw the blend
RECT rect;
GetDlgItem (IDC_DOOMY_BLEND)->GetWindowRect (&rect);
ScreenToClient (&rect);
Blend.OnPaint (rect, pDc, StartBlend, EndBlend, (float)StartTime, (float)EndTime,
Smoothness, StartAnimTime, EndAnimTime, !isEmpty());
// Do not call CDialog::OnPaint() for painting messages
EndPaint(&paint);
}
// ***************************************************************************
void CSlotDlg::OnDeltaposEndBlendSpin(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData ();
if (pNMUpDown->iDelta<0)
EndBlend+=DELTA_BLEND;
if (pNMUpDown->iDelta>0)
EndBlend-=DELTA_BLEND;
clamp (EndBlend, 0.f, 1.f);
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnDeltaposEndTimeSpin(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData ();
if (pNMUpDown->iDelta<0)
EndTime++;
if (pNMUpDown->iDelta>0)
EndTime--;
clamp (EndTime, (int)StartAnimTime, (int)EndAnimTime);
if (EndTimeiDelta<0)
Smoothness+=DELTA_BLEND;
if (pNMUpDown->iDelta>0)
Smoothness-=DELTA_BLEND;
clamp (Smoothness, 0.f, 1.f);
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnDeltaposSpeedFactorSpin(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData ();
if (pNMUpDown->iDelta<0)
SpeedFactor+=DELTA_MUL;
if (pNMUpDown->iDelta>0)
SpeedFactor-=DELTA_MUL;
clamp (SpeedFactor, 0.01f, 100.f);
refresh (FALSE);
validateTime ();
updateScrollBar ();
}
// ***************************************************************************
void CSlotDlg::OnDeltaposStartBlendSpin(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData ();
if (pNMUpDown->iDelta<0)
StartBlend+=DELTA_BLEND;
if (pNMUpDown->iDelta>0)
StartBlend-=DELTA_BLEND;
clamp (StartBlend, 0.f, 1.f);
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnDeltaposStartTimeSpin(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData ();
if (pNMUpDown->iDelta<0)
StartTime++;
if (pNMUpDown->iDelta>0)
StartTime--;
clamp (StartTime, (int)StartAnimTime, (int)EndAnimTime);
if (EndTime vectString;
// Build a list of string
for (uint a=0; agetNumAnimation (); a++)
vectString.push_back (getAnimationSetPointer()->getAnimationName (a));
// Select a string
CSelectString select (vectString, "Select your animation", this, true);
if (select.DoModal ()==IDOK)
{
// Set the animation
if (select.Selection!=-1)
{
getSlotInformation ()->Animation = vectString[select.Selection];
validateTime ();
updateScrollBar ();
}
else
getSlotInformation ()->Animation = "";
}
refresh (TRUE);
}
// ***************************************************************************
void CSlotDlg::OnSetSkeleton()
{
// List of string
std::vector vectString;
// Build a list of string
for (uint s=0; sgetNumSkeletonWeight (); s++)
vectString.push_back (getAnimationSetPointer()->getSkeletonWeightName (s));
// Select a string
CSelectString select (vectString, "Select your skeleton weight template", this, true);
if (select.DoModal ()==IDOK)
{
// Set the animation
if (select.Selection!=-1)
getSlotInformation ()->Skeleton = vectString[select.Selection].c_str();
else
getSlotInformation ()->Skeleton = "";
setWindowName ();
Invalidate ();
}
}
// ***************************************************************************
void CSlotDlg::setWindowName ()
{
std::string tmp = NLMISC::toString("Slot %d : ", Id);
if (isEmpty())
tmp += "empty";
else
tmp += getSlotInformation ()->Animation;
CSlotInfo *information = getSlotInformation ();
if (information)
{
std::string SkeletonName = information->Skeleton;
if (!SkeletonName.empty())
{
tmp += " (" + SkeletonName + ")";
}
}
GetDlgItem (IDC_SLOT_NAME)->SetWindowText (utf8ToTStr(tmp));
}
// ***************************************************************************
void CSlotDlg::OnChangeOffset()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.
// TODO: Add your control notification handler code here
validateTime ();
updateScrollBar ();
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnDeltaposOffsetSpin(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
// TODO: Add your control notification handler code here
UpdateData ();
if (pNMUpDown->iDelta<0)
Offset++;
if (pNMUpDown->iDelta>0)
Offset--;
validateTime ();
updateScrollBar ();
*pResult = 0;
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::validateTime ()
{
bool reinit=false;
if ((float)OffsetEndAnimTime)
{
EndAnimTime=(float)Offset+AnimationLength/SpeedFactor;
reinit=true;
}
if (reinit)
MainDlg->setAnimTime (StartAnimTime, EndAnimTime);
}
// ***************************************************************************
void CSlotDlg::updateScrollBar ()
{
// Scroll info
SCROLLINFO info;
memset (&info, 0, sizeof (info));
// Fill the infos
info.fMask=SIF_ALL;
info.nMin=0;
info.nMax=10000;
if (fabs(EndAnimTime-StartAnimTime)<0.00001f)
{
info.nPage=1;
info.nPos=0;
}
else
{
info.nPage=(int)(10000.f*(AnimationLength/SpeedFactor)/(EndAnimTime-StartAnimTime));
info.nPos=(int)(10000.f*((float)Offset-StartAnimTime)/(EndAnimTime-StartAnimTime));
}
// Set scrollbar infos
ScrollBarCtrl.SetScrollInfo (&info, TRUE);
// Invalidate blend bar
RECT bar;
GetDlgItem (IDC_DOOMY_BLEND)->GetWindowRect (&bar);
ScreenToClient (&bar);
InvalidateRect (&bar);
}
// ***************************************************************************
void CSlotDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
if (pScrollBar==GetDlgItem (IDC_SCROLLBAR))
{
// Only drag and drop
if (nSBCode==SB_THUMBTRACK)
{
int DeltaOffset=Offset;
UpdateData ();
Offset=(int)((EndAnimTime-StartAnimTime)*(float)nPos/10000.f+StartAnimTime);
DeltaOffset=Offset-DeltaOffset;
StartTime+=DeltaOffset;
EndTime+=DeltaOffset;
refresh (FALSE);
updateScrollBar ();
}
}
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
// ***************************************************************************
void CSlotDlg::setAnimTime (float animStart, float animEnd)
{
StartAnimTime=animStart;
EndAnimTime=animEnd;
updateScrollBar ();
computeLength ();
}
// ***************************************************************************
float CSlotDlg::getTimeIncrement ()
{
return (EndAnimTime-StartAnimTime)/100.f;
}
// ***************************************************************************
void CSlotDlg::OnClamp()
{
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnRepeat()
{
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnDisable()
{
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnAlignBlend()
{
// Refresh data
UpdateData ();
// Change some of them
StartTime=Offset;
EndTime=(int)((float)Offset+AnimationLength/SpeedFactor);
// Invalidate UI
refresh (FALSE);
// Invalidate blend bar
RECT bar;
GetDlgItem (IDC_DOOMY_BLEND)->GetWindowRect (&bar);
ScreenToClient (&bar);
InvalidateRect (&bar);
}
// ***************************************************************************
float CSlotDlg::getStartTime ()
{
return (float)StartTime/MainDlg->getFrameRate ();
}
// ***************************************************************************
float CSlotDlg::getEndTime ()
{
return (float)EndTime/MainDlg->getFrameRate ();
}
// ***************************************************************************
void CSlotDlg::computeLength ()
{
if (getAnimationPointer())
AnimationLength=(getAnimationPointer()->getEndTime()-getAnimationPointer()->getBeginTime())*MainDlg->getFrameRate();
}
// ***************************************************************************
void CSlotDlg::OnDestroy()
{
// TODO: Add your message handler code here
CDialog::OnDestroy();
}
// ***************************************************************************
void CSlotDlg::refresh (BOOL update)
{
CSlotInfo *slotInfo = getSlotInformation ();
if (update)
{
CDialog::UpdateData (update);
// Update from slot information
if (slotInfo)
{
EndBlend = slotInfo->EndBlend;
Smoothness = slotInfo->Smoothness;
SpeedFactor = slotInfo->SpeedFactor;
StartBlend = slotInfo->StartBlend;
ClampMode = slotInfo->ClampMode;
SkeletonWeightInverted = slotInfo->SkeletonInverted?TRUE:FALSE;
StartTime = slotInfo->StartTime;
Offset = slotInfo->Offset;
EndTime = slotInfo->EndTime;
enable = slotInfo->Enable?TRUE:FALSE;
}
else
{
EndBlend = 1;
Smoothness = 1;
SpeedFactor = 1;
StartBlend = 1;
ClampMode = 0;
SkeletonWeightInverted = FALSE;
StartTime = 0;
Offset = 0;
EndTime = 0;
enable = TRUE;
}
// Compute length
computeLength ();
// Slot frozen
bool frozen = (slotInfo == NULL) || (getAnimationPointer () == NULL);
// Enable / disable windows
OffsetCtrl.EnableWindow (!frozen);
StartTimeCtrl.EnableWindow (!frozen);
StartBlendCtrl.EnableWindow (!frozen);
SpeddFactorCtrl.EnableWindow (!frozen);
SmoothnessCtrl.EnableWindow (!frozen);
EndTimeCtrl.EnableWindow (!frozen);
EndBlendCtrl.EnableWindow (!frozen);
OffsetSpinCtrl.EnableWindow (!frozen);
StartTimeSpinCtrl.EnableWindow (!frozen);
StartBlendSpinCtrl.EnableWindow (!frozen);
SpeedFactorSpinCtrl.EnableWindow (!frozen);
SmoothnessSpinCtrl.EnableWindow (!frozen);
EndTimeSpinCtrl.EnableWindow (!frozen);
EndBlendSpinCtrl.EnableWindow (!frozen);
ScrollBarCtrl.EnableWindow (!frozen);
AlignBlendCtrl.EnableWindow (!frozen);
InvertSkeletonWeightCtrl.EnableWindow (!frozen);
GetDlgItem (IDC_CLAMP)->EnableWindow (!frozen);
GetDlgItem (IDC_REPEAT)->EnableWindow (!frozen);
GetDlgItem (IDC_DISABLE)->EnableWindow (!frozen);
setWindowName ();
updateScrollBar ();
RECT bar;
GetDlgItem (IDC_DOOMY_BLEND)->GetWindowRect (&bar);
ScreenToClient (&bar);
InvalidateRect (&bar);
CDialog::UpdateData (FALSE);
}
else
{
CDialog::UpdateData (TRUE);
// Update from slot information
slotInfo->EndBlend = EndBlend;
slotInfo->Smoothness = Smoothness;
slotInfo->SpeedFactor = SpeedFactor;
slotInfo->StartBlend = StartBlend;
slotInfo->ClampMode = ClampMode;
slotInfo->SkeletonInverted = SkeletonWeightInverted?true:false;
slotInfo->StartTime = StartTime;
slotInfo->Offset = Offset;
slotInfo->EndTime = EndTime;
slotInfo->Enable = enable?true:false;
CDialog::UpdateData (update);
RECT bar;
GetDlgItem (IDC_DOOMY_BLEND)->GetWindowRect (&bar);
ScreenToClient (&bar);
InvalidateRect (&bar);
}
}
// ***************************************************************************
const CAnimation *CSlotDlg::getAnimationPointer () const
{
// The animation pointer
const CAnimation *pointer = NULL;
// Get an instance pointer
CInstanceInfo *instance = getInstanceInformation ();
if (instance)
{
// Get a slot pointer
CSlotInfo *slot = getSlotInformation ();
uint animId = instance->AnimationSet.getAnimationIdByName (slot->Animation);
if (animId != CAnimationSet::NotFound)
{
// Get the animation pointer
pointer = instance->AnimationSet.getAnimation (animId);
}
}
// Return the pointer
return pointer;
}
// ***************************************************************************
const CSkeletonWeight *CSlotDlg::getSkeletonPointer () const
{
// The skeleton pointer
const CSkeletonWeight *pointer = NULL;
// Get an instance pointer
CInstanceInfo *instance = getInstanceInformation ();
if (instance)
{
// Get a slot pointer
CSlotInfo *slot = getSlotInformation ();
uint animId = instance->AnimationSet.getSkeletonWeightIdByName (slot->Skeleton);
if (animId != CAnimationSet::NotFound)
{
// Get the skeleton pointer
pointer = instance->AnimationSet.getSkeletonWeight (animId);
}
}
// Return the pointer
return pointer;
}
// ***************************************************************************
const NL3D::CAnimationSet *CSlotDlg::getAnimationSetPointer () const
{
// Get an instance pointer
CInstanceInfo *instance = getInstanceInformation ();
if (instance)
return &instance->AnimationSet;
else
return NULL;
}
// ***************************************************************************
CSlotInfo *CSlotDlg::getSlotInformation () const
{
// Get the instance
CInstanceInfo *instance = getInstanceInformation ();
if (instance)
{
return &instance->Saved.SlotInfo[Id];
}
else
return NULL;
}
// ***************************************************************************
CInstanceInfo *CSlotDlg::getInstanceInformation () const
{
if (MainDlg)
{
uint instance = MainDlg->getEditedObject ();
if (instance != 0xffffffff)
return MainDlg->getInstance (instance);
}
return NULL;
}
// ***************************************************************************
bool CSlotDlg::isEmpty()
{
return (getInstanceInformation () == NULL) || (getAnimationPointer () == NULL);
}
// ***************************************************************************
void CSlotDlg::OnEnable()
{
refresh (FALSE);
}
// ***************************************************************************
void CSlotDlg::OnInvertSkeletonWeight()
{
refresh (FALSE);
}