1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2019 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "object_viewer.h"
22 #include "animation_set_dlg.h"
24 #include "nel/misc/file.h"
25 #include "nel/3d/track_keyframer.h"
28 using namespace NLMISC
;
31 /////////////////////////////////////////////////////////////////////////////
32 // CAnimationSetDlg dialog
35 CAnimationSetDlg::CAnimationSetDlg(CObjectViewer
* objView
, CWnd
* pParent
/*=NULL*/)
36 : CDialog(CAnimationSetDlg::IDD
, pParent
)
38 //{{AFX_DATA_INIT(CAnimationSetDlg)
46 void CAnimationSetDlg::DoDataExchange(CDataExchange
* pDX
)
48 CDialog::DoDataExchange(pDX
);
49 //{{AFX_DATA_MAP(CAnimationSetDlg)
50 DDX_Control(pDX
, IDC_EDITED_OBJECT
, EditedObject
);
51 DDX_Control(pDX
, IDC_PLAYLIST
, PlayList
);
52 DDX_Control(pDX
, IDC_TREE2
, SkelTree
);
53 DDX_Control(pDX
, IDC_TREE
, Tree
);
54 DDX_Radio(pDX
, IDC_USE_LIST
, UseMixer
);
59 BEGIN_MESSAGE_MAP(CAnimationSetDlg
, CDialog
)
60 //{{AFX_MSG_MAP(CAnimationSetDlg)
61 ON_BN_CLICKED(IDC_ADD_ANIMATION
, OnAddAnimation
)
62 ON_BN_CLICKED(IDC_RESET
, OnReset
)
63 ON_BN_CLICKED(IDC_ADD_SKEL_WT
, OnAddSkelWt
)
65 ON_BN_CLICKED(IDC_LIST_INSERT
, OnListInsert
)
66 ON_BN_CLICKED(IDC_LIST_UP
, OnListUp
)
67 ON_BN_CLICKED(IDC_LIST_DOWN
, OnListDown
)
68 ON_BN_CLICKED(IDC_LIST_DELETE
, OnListDelete
)
69 ON_BN_CLICKED(IDC_SET_ANIM_LENGTH
, OnSetAnimLength
)
70 ON_BN_CLICKED(IDC_USE_LIST
, OnUseList
)
71 ON_BN_CLICKED(IDC_USE_MIXER
, OnUseMixer
)
72 ON_CBN_SELCHANGE(IDC_EDITED_OBJECT
, OnSelchangeEditedObject
)
76 /////////////////////////////////////////////////////////////////////////////
77 // CAnimationSetDlg message handlers
79 // ***************************************************************************
81 void CAnimationSetDlg::OnAddAnimation ()
83 uint instance
= _ObjView
->getEditedObject ();
84 if (instance
!= 0xffffffff)
87 static TCHAR BASED_CODE szFilter
[] =
88 _T("NeL Animation Files (*.anim)\0*.anim\0")
89 _T("All Files (*.*)\0*.*\0\0");
95 OPENFILENAME openFile
;
96 memset (&openFile
, 0, sizeof (OPENFILENAME
));
97 openFile
.lStructSize
= sizeof (OPENFILENAME
);
98 openFile
.hwndOwner
= this->m_hWnd
;
99 openFile
.lpstrFilter
= szFilter
;
100 openFile
.nFilterIndex
= 0;
101 openFile
.lpstrFile
= buffer
;
102 openFile
.nMaxFile
= 65535;
103 openFile
.Flags
= OFN_HIDEREADONLY
|OFN_OVERWRITEPROMPT
|OFN_ALLOWMULTISELECT
|OFN_ENABLESIZING
|OFN_EXPLORER
;
104 openFile
.lpstrDefExt
= _T("*.anim");
107 if (GetOpenFileName(&openFile
))
116 CString path
= buffer
;
117 if (path
.GetLength()>openFile
.nFileOffset
)
119 // Double zero at the end
120 c
[path
.GetLength()+1]=0;
130 // Look for the next string
134 // For each file selected
150 CString name
= path
+ filename
;
152 // Load the animation
153 _ObjView
->loadAnimation (tStrToUtf8(name
), instance
);
155 // Touch the channel mixer
156 _ObjView
->reinitChannels ();
162 catch (const Exception
& e
)
164 MessageBox (nlUtf8ToTStr(e
.what()), _T("NeL object viewer"), MB_OK
|MB_ICONEXCLAMATION
);
170 // ***************************************************************************
172 void CAnimationSetDlg::OnAddSkelWt()
175 int instance
= _ObjView
->getEditedObject ();
176 if (instance
!= CB_ERR
)
178 // TODO: Add your control notification handler code here
179 static TCHAR BASED_CODE szFilter
[] = _T("NeL Skeleton Weight Template Files (*.swt)|*.swt|All Files (*.*)|*.*||");
180 CFileDialog
fileDlg( TRUE
, _T(".swt"), _T("*.swt"), OFN_ALLOWMULTISELECT
|OFN_HIDEREADONLY
|OFN_OVERWRITEPROMPT
, szFilter
);
181 if (fileDlg
.DoModal()==IDOK
)
187 POSITION pos
=fileDlg
.GetStartPosition( );
191 CString filename
=fileDlg
.GetNextPathName(pos
);
193 // Load the animation
194 _ObjView
->loadSWT (tStrToUtf8(filename
), instance
);
196 // Touch the channel mixer
197 _ObjView
->reinitChannels ();
203 catch (const Exception
& e
)
205 MessageBox(nlUtf8ToTStr(e
.what()), _T("NeL object viewer"), MB_OK
| MB_ICONEXCLAMATION
);
211 // ***************************************************************************
213 void CAnimationSetDlg::OnReset ()
216 uint instance
= _ObjView
->getEditedObject ();
217 if (instance
!=0xffffffff)
219 // Reset the channel mixer slots
220 _ObjView
->resetSlots (instance
);
224 // ***************************************************************************
226 void CAnimationSetDlg::refresh (BOOL update
)
230 CDialog::UpdateData (update
);
232 // Clear the combo box
233 EditedObject
.ResetContent ();
235 // Set edited object list
237 for (i
=0; i
<_ObjView
->getNumInstance (); i
++)
239 std::string name
= NLMISC::CFile::getFilenameWithoutExtension(_ObjView
->getInstance(i
)->Saved
.ShapeFilename
);
240 EditedObject
.InsertString(-1, nlUtf8ToTStr(name
));
244 uint instance
= _ObjView
->getEditedObject ();
246 // Selection combo box
247 EditedObject
.SetCurSel ((instance
==0xffffffff)?-1:(int)instance
);
250 Tree
.DeleteAllItems ();
253 SkelTree
.DeleteAllItems ();
255 // Clear the playlist
256 PlayList
.ResetContent ();
258 if (instance
!= 0xffffffff)
261 CInstanceInfo
*object
= _ObjView
->getInstance (instance
);
263 // For all tracks in the animation
265 for (i
=0; i
<object
->Saved
.AnimationFileName
.size(); i
++)
267 // Get the animation name
268 std::string name
= NLMISC::CFile::getFilenameWithoutExtension(object
->Saved
.AnimationFileName
[i
]);
270 // Get the animation pointer
271 CAnimation
*anim
= object
->AnimationSet
.getAnimation (object
->AnimationSet
.getAnimationIdByName (name
));
274 HTREEITEM item
= Tree
.InsertItem(nlUtf8ToTStr(name
));
275 Tree
.SetItemData (item
, i
);
276 nlassert (item
!=NULL
);
278 // For all tracks in the animation
279 std::set
<std::string
> setString
;
280 anim
->getTrackNames (setString
);
281 std::set
<std::string
>::iterator ite
=setString
.begin();
282 while (ite
!=setString
.end())
285 HTREEITEM newItem
= Tree
.InsertItem(nlUtf8ToTStr(*ite
), item
);
286 Tree
.SetItemData (newItem
, 0xffffffff);
289 ITrack
*track
=anim
->getTrack (anim
->getIdTrackByName (*ite
));
292 UTrackKeyframer
*keyTrack
=dynamic_cast<UTrackKeyframer
*>(track
);
296 // Get number of keys
297 std::vector
<TAnimationTime
> keys
;
298 keyTrack
->getKeysInRange (track
->getBeginTime ()-1, track
->getEndTime ()+1, keys
);
301 name
= toString("%s (%f - %f) %u keys", typeid(*track
).name(), track
->getBeginTime(), track
->getEndTime(), (uint32
)keys
.size());
306 name
= toString("%s (%f - %f)", typeid(*track
).name(), track
->getBeginTime(), track
->getEndTime());
309 HTREEITEM keyItem
= Tree
.InsertItem(nlUtf8ToTStr(name
), newItem
);
310 Tree
.SetItemData(keyItem
, 0xffffffff);
316 // For all tracks in the animation
317 for (i
=0; i
<object
->Saved
.SWTFileName
.size(); i
++)
319 // Get the animation name
320 std::string name
= NLMISC::CFile::getFilenameWithoutExtension(object
->Saved
.SWTFileName
[i
]);
322 // Get the animation pointer
323 CSkeletonWeight
*swt
= object
->AnimationSet
.getSkeletonWeight(object
->AnimationSet
.getSkeletonWeightIdByName(name
));
326 HTREEITEM item
= SkelTree
.InsertItem(nlUtf8ToTStr(name
));
327 nlassert (item
!=NULL
);
329 // Get number of node in this skeleton weight
330 uint numNode
=swt
->getNumNode ();
332 // Add the nodein the tree
333 for (uint n
=0; n
<numNode
; n
++)
335 std::string percent
= toString("%s (%f%%)", swt
->getNodeName(n
).c_str(), swt
->getNodeWeight(n
)*100);
338 SkelTree
.InsertItem(nlUtf8ToTStr(percent
), item
);
342 // For all tracks in the playlist
343 for (i
=0; i
<object
->Saved
.PlayList
.size(); i
++)
346 int item
= PlayList
.InsertString(-1, nlUtf8ToTStr(object
->Saved
.PlayList
[i
]));
347 nlassert (item
!=LB_ERR
);
351 CDialog::UpdateData (FALSE
);
355 CDialog::UpdateData (TRUE
);
358 uint instance
= _ObjView
->getEditedObject ();
359 if (instance
!= 0xffffffff)
362 CInstanceInfo
*object
= _ObjView
->getInstance (instance
);
364 // Clear the playlist
365 object
->Saved
.PlayList
.resize (PlayList
.GetCount ());
367 // For all tracks in the playlist
369 for (i
=0; i
<object
->Saved
.PlayList
.size(); i
++)
373 PlayList
.GetText( i
, text
);
374 object
->Saved
.PlayList
[i
] = tStrToUtf8(text
);
377 CDialog::UpdateData (update
);
381 _ObjView
->refreshAnimationListeners();
384 // ***************************************************************************
386 void CAnimationSetDlg::OnDestroy()
388 setRegisterWindowState (this, REGKEY_OBJ_VIEW_ANIMATION_SET_DLG
);
390 CDialog::OnDestroy();
393 // ***************************************************************************
395 void CAnimationSetDlg::OnListInsert()
397 // Get selected animation
398 HTREEITEM item
= Tree
.GetSelectedItem ();
399 if (item
&& (Tree
.GetItemData (item
)!=0xffffffff))
402 int itemList
= PlayList
.InsertString (-1, Tree
.GetItemText(item
));
403 PlayList
.SetItemData (itemList
, Tree
.GetItemData (item
));
406 Tree
.SelectItem (item
);
413 // ***************************************************************************
415 void CAnimationSetDlg::OnListUp()
418 int sel
= PlayList
.GetCurSel ();
419 if ((sel
!= LB_ERR
) && (sel
>0))
423 PlayList
.GetText (sel
, text
);
424 DWORD_PTR data
= PlayList
.GetItemData (sel
);
427 PlayList
.DeleteString (sel
);
430 int pos
= PlayList
.InsertString (sel
-1, text
);
431 PlayList
.SetItemData (pos
, data
);
432 PlayList
.SetCurSel (pos
);
439 // ***************************************************************************
441 void CAnimationSetDlg::OnListDown()
444 int sel
= PlayList
.GetCurSel ();
445 if ((sel
!= LB_ERR
) && (sel
<PlayList
.GetCount()-1))
449 PlayList
.GetText (sel
, text
);
450 DWORD_PTR data
= PlayList
.GetItemData (sel
);
453 PlayList
.DeleteString (sel
);
456 int pos
= PlayList
.InsertString (sel
+1, text
);
457 PlayList
.SetItemData (pos
, data
);
458 PlayList
.SetCurSel (pos
);
465 // ***************************************************************************
467 void CAnimationSetDlg::OnListDelete()
470 int sel
= PlayList
.GetCurSel ();
474 PlayList
.DeleteString (sel
);
476 if (sel
>=PlayList
.GetCount ())
479 PlayList
.SetCurSel (sel
);
486 // ***************************************************************************
488 void CAnimationSetDlg::OnSetAnimLength()
491 float longestLength
= 0;
494 for (uint instance
=0; instance
<_ObjView
->_ListInstance
.size(); instance
++)
496 // Ref on the instance
497 CInstanceInfo
&inst
= *_ObjView
->_ListInstance
[instance
];
499 // There is some anim ?
500 if (inst
.Saved
.PlayList
.size())
502 // Calculate the length
505 // For each animation in the list
506 for (uint i
=0; i
<(uint
)inst
.Saved
.PlayList
.size(); i
++)
509 CAnimation
*anim
= inst
.AnimationSet
.getAnimation (inst
.AnimationSet
.getAnimationIdByName (inst
.Saved
.PlayList
[i
]));
512 length
+= anim
->getEndTime () - anim
->getBeginTime ();
515 if (length
>longestLength
)
516 longestLength
=length
;
522 _ObjView
->setAnimTime (0, longestLength
* _ObjView
->getFrameRate ());
525 // ***************************************************************************
527 void CAnimationSetDlg::OnUseList()
530 _ObjView
->enableChannels ();
533 // ***************************************************************************
535 void CAnimationSetDlg::OnUseMixer()
538 _ObjView
->enableChannels ();
541 // ***************************************************************************
544 void CAnimationSetDlg::OnSelchangeEditedObject()
548 // Selection combo box
549 int selection
= EditedObject
.GetCurSel ();
550 _ObjView
->setEditedObject ((selection
==CB_ERR
)?0xffffffff:selection
);
553 _ObjView
->getSlotDlg ()->refresh (TRUE
);