Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3988 lines
111 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //
  9. // Half-Life Model Viewer (c) 1999 by Mete Ciragan
  10. //
  11. // file: ControlPanel.cpp
  12. // last modified: May 29 1999, Mete Ciragan
  13. // copyright: The programs and associated files contained in this
  14. // distribution were developed by Mete Ciragan. The programs
  15. // are not in the public domain, but they are freely
  16. // distributable without licensing fees. These programs are
  17. // provided without guarantee or warrantee expressed or
  18. // implied.
  19. //
  20. // version: 1.2
  21. //
  22. // email: [email protected]
  23. // web: http://www.swissquake.ch/chumbalum-soft/
  24. //
  25. #include "ControlPanel.h"
  26. #include "ViewerSettings.h"
  27. #include "StudioModel.h"
  28. #include "IStudioRender.h"
  29. #include "MatSysWin.h"
  30. #include "vphysics/constraints.h"
  31. #include "physmesh.h"
  32. #include "sys.h"
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <mxtk/mx.h>
  37. #include <mxtk/mxBmp.h>
  38. #include "vphysics_interface.h"
  39. #include "utlvector.h"
  40. #include "utlsymbol.h"
  41. #include "UtlBuffer.h"
  42. #include "attachments_window.h"
  43. #include "istudiorender.h"
  44. #include "studio_render.h"
  45. #include "SoundEmitterSystem/isoundemittersystembase.h"
  46. #include "tier1/KeyValues.h"
  47. #include "tier0/icommandline.h"
  48. #include "valve_ipc_win32.h"
  49. #include "mdlviewer.h"
  50. extern char g_appTitle[];
  51. extern IPhysicsSurfaceProps *physprop;
  52. extern bool LoadPhysicsProperties( void );
  53. extern ISoundEmitterSystemBase *g_pSoundEmitterBase;
  54. extern CValveIpcClientUtl g_HlmvIpcClient;
  55. extern bool g_bHlmvMaster;
  56. //-----------------------------------------------------------------------------
  57. // Reads all of the physics materials from surface property file
  58. //-----------------------------------------------------------------------------
  59. static void ReadPhysicsMaterials( mxChoice *plist )
  60. {
  61. LoadPhysicsProperties();
  62. plist->removeAll();
  63. if ( !physprop || !physprop->SurfacePropCount() )
  64. {
  65. plist->add("default");
  66. plist->select(0);
  67. return;
  68. }
  69. for ( int i = 0; i < physprop->SurfacePropCount(); i++ )
  70. {
  71. plist->add(physprop->GetPropName( i ) );
  72. }
  73. plist->select(0);
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Populates a control with all the physics bones
  77. //-----------------------------------------------------------------------------
  78. static bool PopulatePhysicsBoneList( mxChoice* pChoice )
  79. {
  80. pChoice->removeAll();
  81. if ( g_pStudioModel->Physics_GetBoneCount() )
  82. {
  83. for ( int i = 0; i < g_pStudioModel->Physics_GetBoneCount(); i++ )
  84. {
  85. pChoice->add (g_pStudioModel->Physics_GetBoneName( i ) );
  86. }
  87. }
  88. else
  89. {
  90. pChoice->add( "None" );
  91. pChoice->select (0);
  92. return false;
  93. }
  94. pChoice->select (0);
  95. return true;
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Populates a control with all the sound names
  99. //-----------------------------------------------------------------------------
  100. static void PopulateSoundNameList( mxListBox *pListBox )
  101. {
  102. pListBox->removeAll();
  103. if ( g_pSoundEmitterBase )
  104. {
  105. for ( int i = g_pSoundEmitterBase->First(); i != g_pSoundEmitterBase->InvalidIndex(); i = g_pSoundEmitterBase->Next( i ) )
  106. {
  107. pListBox->add( g_pSoundEmitterBase->GetSoundName( i ) );
  108. }
  109. }
  110. pListBox->select( 0 );
  111. pListBox->deselect( 0 );
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Populates a control with all the physics bones
  115. //-----------------------------------------------------------------------------
  116. bool PopulateBoneList( mxChoice* pChoice, bool bAlwaysAddNone = false )
  117. {
  118. pChoice->removeAll();
  119. if ( bAlwaysAddNone )
  120. {
  121. pChoice->add( "(None)" );
  122. }
  123. if ( g_pStudioModel )
  124. {
  125. CStudioHdr *pHdr = g_pStudioModel->GetStudioHdr();
  126. if ( pHdr && pHdr->numbones() > 0 )
  127. {
  128. for ( int i = 0; i < pHdr->numbones(); i++ )
  129. {
  130. pChoice->add ( pHdr->pBone(i)->pszName() );
  131. }
  132. pChoice->select(0);
  133. return true;
  134. }
  135. }
  136. if ( !bAlwaysAddNone )
  137. {
  138. pChoice->add( "(None)" );
  139. }
  140. pChoice->select(0);
  141. return false;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Populates a control with all the attachments
  145. //-----------------------------------------------------------------------------
  146. void PopulateAttachmentsList( mxChoice *pChoice )
  147. {
  148. pChoice->removeAll();
  149. pChoice->add( "(none)" );
  150. if ( g_pStudioModel )
  151. {
  152. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  153. if ( pHdr && pHdr->GetNumAttachments() > 0 )
  154. {
  155. for ( int i = 0; i < pHdr->GetNumAttachments(); i++ )
  156. {
  157. pChoice->add( pHdr->pAttachment(i).pszName() );
  158. }
  159. }
  160. }
  161. pChoice->select(0);
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Sets the text of a lineedit to the current frame
  165. //-----------------------------------------------------------------------------
  166. void SetFrameString( mxLineEdit2 *pLineEdit, int iLayer )
  167. {
  168. float flFrame = g_pStudioModel->GetFrame( iLayer );
  169. int nFrame = int( flFrame + 0.5f );
  170. char msg[ 16 ];
  171. sprintf( msg, "%d", nFrame );
  172. pLineEdit->setText( msg );
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Finds the index of a surface prop
  176. //-----------------------------------------------------------------------------
  177. static int FindSurfaceProp( const char* pSurfaceProp )
  178. {
  179. for (int i = 0; i < physprop->SurfacePropCount(); ++i)
  180. {
  181. if (!stricmp( physprop->GetPropName( i ), pSurfaceProp ))
  182. return i;
  183. }
  184. return -1;
  185. }
  186. //-----------------------------------------------------------------------------
  187. // The tab associated with bone control
  188. //-----------------------------------------------------------------------------
  189. class CBoneControlWindow : public mxWindow
  190. {
  191. public:
  192. CBoneControlWindow( ControlPanel* pParent );
  193. void Init( );
  194. // This gets called when the model is loaded and unloaded
  195. void OnLoadModel();
  196. void OnUnloadModel();
  197. // Handles various events
  198. int handleEvent (mxEvent *event);
  199. // Called when we're selected
  200. void OnTabSelected();
  201. int GetHitboxSet( void );
  202. private:
  203. // Called when the bone is selected
  204. void OnBoneSelected( int boneIndex );
  205. void OnBoneHighlighted( bool isChecked );
  206. void OnHitboxHighlighted( bool isChecked );
  207. void OnShowDefaultPose( bool isChecked );
  208. void OnHitboxSelected( int hitbox );
  209. void OnHitboxGroupChanged( );
  210. void OnHitboxChanged( );
  211. void OnHitboxSetChanged( void );
  212. void OnAddHitbox( );
  213. void OnDeleteHitbox( );
  214. void OnGenerateQC( );
  215. void OnAutogenerateHitboxes( bool isChecked );
  216. // Writes out qc-style text to a utlbuffer
  217. bool SerializeQC( CUtlBuffer& buf );
  218. // Sets the surface property
  219. void OnSurfaceProp( int propIndex );
  220. // Duplictes the surface property to all children
  221. void OnSurfacePropApplyToChildren( );
  222. void RefreshHitbox( );
  223. void ComputeHitboxList( );
  224. void ComputeHitboxSetList( void );
  225. void OnHitboxAddSet( void );
  226. void OnHitboxDeleteSet( void );
  227. void OnHitboxSetChangeName( void );
  228. // Generates a list of all hitboxes per bone
  229. void PopulateHitboxLists();
  230. // Applies a surface property to all children
  231. void OnSurfacePropApplyToChildren_R( int bone, CUtlSymbol prop );
  232. // Selects the bone
  233. mxChoice* m_cBone;
  234. mxChoice* m_cHitboxSet;
  235. mxLineEdit *m_eHitboxSetName;
  236. mxButton *m_bHitboxSetUpdateName;
  237. mxButton *m_bAddHitboxSet;
  238. mxButton *m_bDeleteHitboxSet;
  239. // Selects a hitbox associated with a bone
  240. mxChoice* m_cHitbox;
  241. // The materials to assign to the bone
  242. mxChoice* m_cSurfaceProp;
  243. // Are we highlighting bones?
  244. mxCheckBox* m_cBoneHighlight;
  245. // Are we highlighting hitboxes?
  246. mxCheckBox* m_cHitboxHighlight;
  247. // Should we show the default pose?
  248. mxCheckBox* m_cShowDefaultPose;
  249. // Should hitboxes be autogenerated?
  250. mxCheckBox* m_cAutoHitbox;
  251. // The control panel to which we're attached
  252. ControlPanel* m_pControlPanel;
  253. // Hitbox group
  254. mxLineEdit* m_eHitboxGroup;
  255. // Hitbox name
  256. mxLineEdit* m_eHitboxName;
  257. // Hitbox origin
  258. mxLineEdit* m_eOriginX;
  259. mxLineEdit* m_eOriginY;
  260. mxLineEdit* m_eOriginZ;
  261. // Hitbox size
  262. mxLineEdit* m_eSizeX;
  263. mxLineEdit* m_eSizeY;
  264. mxLineEdit* m_eSizeZ;
  265. // Hitbox buttons
  266. mxButton* m_bUpdateHitbox;
  267. mxButton* m_bAddHitbox;
  268. mxButton* m_bDeleteHitbox;
  269. // The list of hitboxes per bone...
  270. typedef CUtlVector< int > BoneHitboxList_t;
  271. typedef CUtlVector< BoneHitboxList_t > BoneHitboxes_t;
  272. CUtlVector< BoneHitboxes_t > m_SetBoneHitBoxes;
  273. // Currently selected hitbox + bone
  274. int m_Bone;
  275. int m_Hitbox;
  276. int m_nHitboxSet;
  277. };
  278. //-----------------------------------------------------------------------------
  279. // constructor
  280. //-----------------------------------------------------------------------------
  281. CBoneControlWindow::CBoneControlWindow( ControlPanel* pParent ) : mxWindow( pParent, 0, 0, 0, 0 )
  282. {
  283. m_pControlPanel = pParent;
  284. m_nHitboxSet = 0;
  285. }
  286. //-----------------------------------------------------------------------------
  287. // Sets up all the controls in the window
  288. //-----------------------------------------------------------------------------
  289. void CBoneControlWindow::Init( )
  290. {
  291. int left, top;
  292. left = 5;
  293. top = 0;
  294. // Bone selection list
  295. new mxLabel (this, left + 3, top + 4, 30, 18, "Bone");
  296. m_cBone = new mxChoice (this, left, top + 20, 260, 22, IDC_BONE_BONELIST);
  297. m_cBone->add ("None");
  298. m_cBone->select (0);
  299. mxToolTip::add (m_cBone, "Select a bone to modify");
  300. // Show bone checkbox
  301. m_cBoneHighlight = new mxCheckBox (this, left, top + 45, 140, 20, "Highlight Bone", IDC_BONE_HIGHLIGHT_BONE);
  302. mxToolTip::add (m_cBoneHighlight, "Toggle display of the bone being modified");
  303. // Bone surface property selection
  304. new mxLabel (this, left + 3, top + 68, 100, 18, "Bone Surface Prop");
  305. m_cSurfaceProp = new mxChoice( this, left, top + 85, 140, 22, IDC_BONE_SURFACEPROP );
  306. mxToolTip::add (m_cSurfaceProp, "Select a surface property to apply to the bone");
  307. // FIXME: We can't read the surface props yet because the vphysics path isn't known!!!
  308. // This will only add 'default' to the list
  309. ReadPhysicsMaterials( m_cSurfaceProp );
  310. // This button will apply the surface prop to all children
  311. mxButton *btnApplyChild = new mxButton( this, left, top + 115, 140, 20, "Apply to Children", IDC_BONE_APPLY_TO_CHILDREN );
  312. mxToolTip::add (btnApplyChild, "Apply the surface property to all child bones");
  313. // Use autogenerated hitboxes
  314. m_cAutoHitbox = new mxCheckBox (this, left, top + 140, 140, 20, "Autogenerate Hitboxes", IDC_BONE_USE_AUTOGENERATED_HITBOXES);
  315. mxToolTip::add (m_cAutoHitbox, "When this is checked, studiomdl will automatically generate hitboxes");
  316. m_cShowDefaultPose = new mxCheckBox (this, left, top + 160, 140, 20, "Show Default Pose", IDC_BONE_SHOW_DEFAULT_POSE);
  317. mxToolTip::add (m_cShowDefaultPose, "Toggles display of the default physics pose");
  318. left = 160;
  319. new mxLabel( this, left + 3, top + 50, 80, 18, "Hitbox Set" );
  320. m_cHitboxSet = new mxChoice (this, left, top + 66, 100, 22, IDC_BONE_HITBOXSET);
  321. m_cHitboxSet->add ("unnamed");
  322. m_cHitboxSet->select (0);
  323. mxToolTip::add (m_cHitboxSet, "Change hitbox set");
  324. m_eHitboxSetName = new mxLineEdit(this, left, top + 96, 100, 18, "", IDC_BONE_HITBOXSETNAME_EDIT);
  325. mxToolTip::add (m_eHitboxSetName, "Type in a name and hit the set button");
  326. m_bHitboxSetUpdateName = new mxButton( this, left, top + 116, 100, 16, "Set Name", IDC_BONE_HITBOXSETNAME );
  327. mxToolTip::add (m_bHitboxSetUpdateName, "Press to set hitbox set name from above text field");
  328. m_bAddHitboxSet = new mxButton( this, left, top + 140, 100, 20, "Add set", IDC_BONE_HITBOXADDSET );
  329. mxToolTip::add (m_bAddHitboxSet, "Add a hitbox set");
  330. m_bDeleteHitboxSet= new mxButton( this, left, top + 162, 100, 20, "Delete set", IDC_BONE_HITBOXDELETESET );
  331. mxToolTip::add (m_bDeleteHitboxSet, "Remove a hitbox set");
  332. left += 120;
  333. // Hitbox selection list
  334. new mxLabel (this, left + 3, top + 4, 30, 18, "Hitbox");
  335. m_cHitbox = new mxChoice (this, left, top + 20, 100, 22, IDC_BONE_HITBOXLIST);
  336. m_cHitbox->add ("None");
  337. m_cHitbox->select (0);
  338. mxToolTip::add (m_cHitbox, "Select a hitbox to modify");
  339. // Show hitbox checkbox
  340. m_cHitboxHighlight = new mxCheckBox (this, left + 3, top + 45, 100, 20, "Highlight Hitbox", IDC_BONE_HIGHLIGHT_HITBOX);
  341. mxToolTip::add (m_cHitboxHighlight, "Toggle display of the hitbox being modified");
  342. // Hitbox group
  343. new mxLabel (this, left + 3, top + 80, 80, 18, "Hitbox Group");
  344. m_eHitboxGroup = new mxLineEdit(this, left + 80, top + 75, 50, 22, "", IDC_BONE_HITBOX_GROUP);
  345. mxToolTip::add (m_eHitboxGroup, "The group of the current hitbox");
  346. // Hitbox name
  347. new mxLabel (this, left + 133, top + 80, 80, 18, "Hitbox Name");
  348. m_eHitboxName = new mxLineEdit(this, left + 133+80, top + 75, 50, 22, "", IDC_BONE_HITBOX_NAME);
  349. m_eHitboxName->setEnabled(false);
  350. mxToolTip::add (m_eHitboxName, "The name of the current hitbox");
  351. // Hitbox origin
  352. new mxLabel (this, left + 3, top + 110, 80, 18, "Hitbox Origin");
  353. new mxLabel (this, left + 133, top + 110, 10, 18, "X");
  354. new mxLabel (this, left + 198, top + 110, 10, 18, "Y");
  355. new mxLabel (this, left + 263, top + 110, 10, 18, "Z");
  356. m_eOriginX = new mxLineEdit(this, left + 80, top + 105, 50, 22, "", IDC_BONE_HITBOX_ORIGINX);
  357. m_eOriginY = new mxLineEdit(this, left + 145, top + 105, 50, 22, "", IDC_BONE_HITBOX_ORIGINY);
  358. m_eOriginZ = new mxLineEdit(this, left + 210, top + 105, 50, 22, "", IDC_BONE_HITBOX_ORIGINZ);
  359. // Hitbox size
  360. new mxLabel (this, left + 3, top + 140, 80, 18, "Hitbox Size");
  361. new mxLabel (this, left + 133, top + 140, 10, 18, "X");
  362. new mxLabel (this, left + 198, top + 140, 10, 18, "Y");
  363. new mxLabel (this, left + 263, top + 140, 10, 18, "Z");
  364. m_eSizeX = new mxLineEdit(this, left + 80, top + 135, 50, 22, "", IDC_BONE_HITBOX_SIZEX);
  365. m_eSizeY = new mxLineEdit(this, left + 145, top + 135, 50, 22, "", IDC_BONE_HITBOX_SIZEY);
  366. m_eSizeZ = new mxLineEdit(this, left + 210, top + 135, 50, 22, "", IDC_BONE_HITBOX_SIZEZ);
  367. // Update hitboxes here
  368. m_bUpdateHitbox = new mxButton( this, left, top + 163, 100, 20, "Update Hitbox", IDC_BONE_UPDATE_HITBOX );
  369. mxToolTip::add (m_bUpdateHitbox, "Apply hitbox group, origin, and size to the hitbox");
  370. left += 160;
  371. // Generate a QC file
  372. mxButton* btnGenerateQC = new mxButton (this, left, top + 10, 100, 20, "Generate QC", IDC_BONE_GENERATEQC );
  373. mxToolTip::add (btnGenerateQC, "Copy a .qc file snippet to the clipboard");
  374. // Add, remove hitboxes here
  375. m_bAddHitbox = new mxButton( this, left, top + 30, 100, 20, "Add Hitbox", IDC_BONE_ADD_HITBOX );
  376. m_bDeleteHitbox = new mxButton( this, left, top + 50, 100, 20, "Delete Hitbox", IDC_BONE_DELETE_HITBOX );
  377. mxToolTip::add (m_bAddHitbox, "Create a new hitbox attached to the current bone");
  378. mxToolTip::add (m_bDeleteHitbox, "Delete the currently selected hitbox");
  379. OnAutogenerateHitboxes( false );
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Generates a list of all hitboxes per bone
  383. //-----------------------------------------------------------------------------
  384. void CBoneControlWindow::PopulateHitboxLists()
  385. {
  386. // Find the surface prop associated with this bone
  387. if (!g_pStudioModel)
  388. return;
  389. m_SetBoneHitBoxes.RemoveAll();
  390. for (int set = 0; set < g_pStudioModel->m_HitboxSets.Count(); set++ )
  391. {
  392. m_SetBoneHitBoxes.AddToTail();
  393. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ set ].m_Hitboxes;
  394. for ( unsigned short i = list.Head(); i != list.InvalidIndex(); i = list.Next(i) )
  395. {
  396. mstudiobbox_t* pHitbox = &list[i].m_BBox;
  397. m_SetBoneHitBoxes[ set ].EnsureCount( pHitbox->bone + 1 );
  398. m_SetBoneHitBoxes[ set ][ pHitbox->bone ].AddToTail( i );
  399. }
  400. }
  401. }
  402. //-----------------------------------------------------------------------------
  403. // This gets called when the model is loaded and unloaded
  404. //-----------------------------------------------------------------------------
  405. void CBoneControlWindow::OnLoadModel()
  406. {
  407. // Now that the vphysics path is known, we can load the surface props
  408. ReadPhysicsMaterials( m_cSurfaceProp );
  409. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  410. m_cAutoHitbox->setChecked( (pHdr->flags() & STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX) != 0 );
  411. OnAutogenerateHitboxes( m_cAutoHitbox->isChecked() );
  412. // Determine all bones for this model
  413. PopulateBoneList( m_cBone );
  414. ComputeHitboxSetList();
  415. PopulateHitboxLists();
  416. OnBoneSelected( 0 );
  417. g_bDrawModelInfoValid = false;
  418. }
  419. void CBoneControlWindow::OnUnloadModel()
  420. {
  421. m_cBone->removeAll();
  422. m_cBone->add ("None");
  423. m_cBone->select (0);
  424. m_cAutoHitbox->setChecked( false );
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Called when we're selected
  428. //-----------------------------------------------------------------------------
  429. void CBoneControlWindow::OnTabSelected()
  430. {
  431. // Make the selected bone and highlight state match
  432. OnBoneSelected( m_cBone->getSelectedIndex() );
  433. OnBoneHighlighted( m_cBoneHighlight->isChecked() );
  434. OnHitboxHighlighted( m_cHitboxHighlight->isChecked() );
  435. OnShowDefaultPose( m_cShowDefaultPose->isChecked() );
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose:
  439. //-----------------------------------------------------------------------------
  440. int CBoneControlWindow::GetHitboxSet( void )
  441. {
  442. return m_nHitboxSet;
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose:
  446. //-----------------------------------------------------------------------------
  447. void CBoneControlWindow::ComputeHitboxSetList( void )
  448. {
  449. m_cHitboxSet->removeAll();
  450. for ( int i = 0 ; i < g_pStudioModel->m_HitboxSets.Count(); i++ )
  451. {
  452. const char *name = g_pStudioModel->m_HitboxSets[ i ].m_Name;
  453. m_cHitboxSet->add( name );
  454. }
  455. m_cHitboxSet->select( 0 );
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Recomputes the hitbox list
  459. //-----------------------------------------------------------------------------
  460. void CBoneControlWindow::ComputeHitboxList( )
  461. {
  462. // Reset the hitbox list
  463. m_cHitbox->removeAll();
  464. int count = 0;
  465. if ( m_SetBoneHitBoxes.Count() > 0 )
  466. {
  467. if (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() > m_Bone)
  468. count = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count();
  469. if (count > 0)
  470. {
  471. for (int i = 0; i < count; ++i )
  472. {
  473. char buf[32];
  474. sprintf( buf, "%d", m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][i] );
  475. m_cHitbox->add( buf );
  476. }
  477. }
  478. else
  479. {
  480. m_cHitbox->add ("None");
  481. }
  482. }
  483. else
  484. {
  485. m_cHitbox->add ("None");
  486. }
  487. OnHitboxSelected(0);
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Here's what we do when a new bone is selected
  491. //-----------------------------------------------------------------------------
  492. void CBoneControlWindow::OnBoneSelected( int boneIndex )
  493. {
  494. // Reset the surface prop
  495. if (!g_pStudioModel)
  496. return;
  497. if ( physprop && g_pStudioModel->m_SurfaceProps.Count() )
  498. {
  499. // Find the surface prop associated with this bone
  500. const char* pSurfaceProp = g_pStudioModel->m_SurfaceProps[boneIndex].String();
  501. int idx = FindSurfaceProp( pSurfaceProp );
  502. // Can't find it? Then apply the default one
  503. if (idx < 0)
  504. idx = FindSurfaceProp( "default" );
  505. if (idx < 0)
  506. idx = 0;
  507. m_cSurfaceProp->select(idx);
  508. }
  509. else
  510. {
  511. m_cSurfaceProp->select(0);
  512. }
  513. // Store off the bone
  514. m_Bone = boneIndex;
  515. if (m_cBoneHighlight->isChecked())
  516. g_viewerSettings.highlightBone = m_Bone;
  517. ComputeHitboxList();
  518. // select the render/highlight bone
  519. m_pControlPanel->redraw();
  520. }
  521. //-----------------------------------------------------------------------------
  522. // When the bone is highlighted or not
  523. //-----------------------------------------------------------------------------
  524. void CBoneControlWindow::OnShowDefaultPose( bool isChecked )
  525. {
  526. g_viewerSettings.showPhysicsPreview = isChecked;
  527. }
  528. //-----------------------------------------------------------------------------
  529. // When the bone is highlighted or not
  530. //-----------------------------------------------------------------------------
  531. void CBoneControlWindow::OnBoneHighlighted( bool isChecked )
  532. {
  533. g_viewerSettings.highlightBone = isChecked ? m_Bone : -1;
  534. }
  535. //-----------------------------------------------------------------------------
  536. // When the hitbox is highlighted or not
  537. //-----------------------------------------------------------------------------
  538. void CBoneControlWindow::OnHitboxHighlighted( bool isChecked )
  539. {
  540. g_viewerSettings.highlightHitbox = isChecked ? m_Hitbox : -1;
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Refreshes the hitbox size
  544. //-----------------------------------------------------------------------------
  545. void CBoneControlWindow::RefreshHitbox( )
  546. {
  547. if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Count() )
  548. {
  549. m_nHitboxSet = 0;
  550. }
  551. if ( m_Hitbox >= 0 && g_pStudioModel->m_HitboxSets.Count() > 0 )
  552. {
  553. // Set the hitbox size + origin + group
  554. mstudiobbox_t* pHitbox = &g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[ m_Hitbox ].m_BBox;
  555. Vector origin, size;
  556. VectorSubtract( pHitbox->bbmax, pHitbox->bbmin, size );
  557. VectorAdd( pHitbox->bbmax, pHitbox->bbmin, origin );
  558. origin *= 0.5f;
  559. m_eHitboxGroup->setLabel( "%i", pHitbox->group );
  560. const char *hitboxname = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[ m_Hitbox ].m_Name;
  561. m_eHitboxName->setLabel( hitboxname );
  562. m_eOriginX->setLabel("%.3f", origin.x );
  563. m_eOriginY->setLabel("%.3f", origin.y );
  564. m_eOriginZ->setLabel("%.3f", origin.z );
  565. m_eSizeX->setLabel("%.3f", size.x );
  566. m_eSizeY->setLabel("%.3f", size.y );
  567. m_eSizeZ->setLabel("%.3f", size.z );
  568. }
  569. else
  570. {
  571. m_eHitboxGroup->setLabel( "" );
  572. m_eHitboxName->setLabel( "" );
  573. m_eOriginX->setLabel("");
  574. m_eOriginY->setLabel("");
  575. m_eOriginZ->setLabel("");
  576. m_eSizeX->setLabel("");
  577. m_eSizeY->setLabel("");
  578. m_eSizeZ->setLabel("");
  579. }
  580. }
  581. //-----------------------------------------------------------------------------
  582. // When a hitbox is selected
  583. //-----------------------------------------------------------------------------
  584. void CBoneControlWindow::OnHitboxSelected( int hitbox )
  585. {
  586. if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Size() )
  587. {
  588. m_nHitboxSet = 0;
  589. }
  590. m_cHitbox->select(hitbox);
  591. if ( m_SetBoneHitBoxes.Count() == 0 ||
  592. (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() <= m_Bone) ||
  593. (m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() <= hitbox))
  594. {
  595. m_Hitbox = -1;
  596. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  597. // This'll cause no boxes to be drawn
  598. if (m_cHitboxHighlight->isChecked())
  599. g_viewerSettings.highlightHitbox = pHdr ? pHdr->numbones() + 1 : 1;
  600. }
  601. else
  602. {
  603. m_Hitbox = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][hitbox];
  604. if (m_cHitboxHighlight->isChecked())
  605. g_viewerSettings.highlightHitbox = m_Hitbox;
  606. }
  607. RefreshHitbox();
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Hitbox size/origin changed
  611. //-----------------------------------------------------------------------------
  612. void CBoneControlWindow::OnAutogenerateHitboxes( bool isChecked )
  613. {
  614. m_eHitboxGroup->setEnabled( !isChecked );
  615. m_eHitboxName->setEnabled( !isChecked );
  616. m_eOriginX->setEnabled( !isChecked );
  617. m_eOriginY->setEnabled( !isChecked );
  618. m_eOriginZ->setEnabled( !isChecked );
  619. m_eSizeX->setEnabled( !isChecked );
  620. m_eSizeY->setEnabled( !isChecked );
  621. m_eSizeZ->setEnabled( !isChecked );
  622. m_bUpdateHitbox->setEnabled( !isChecked );
  623. m_bAddHitbox->setEnabled( !isChecked );
  624. m_bDeleteHitbox->setEnabled( !isChecked );
  625. m_cHitboxSet->setEnabled( !isChecked );
  626. m_eHitboxSetName->setEnabled( !isChecked );
  627. m_bHitboxSetUpdateName->setEnabled( !isChecked );
  628. m_bAddHitboxSet->setEnabled( !isChecked );
  629. m_bDeleteHitboxSet->setEnabled( !isChecked );
  630. }
  631. //-----------------------------------------------------------------------------
  632. // Hitbox size/origin changed
  633. //-----------------------------------------------------------------------------
  634. void CBoneControlWindow::OnHitboxChanged( )
  635. {
  636. if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Count() )
  637. {
  638. m_nHitboxSet = 0;
  639. }
  640. if ( m_Hitbox < 0 || g_pStudioModel->m_HitboxSets.Count() <= 0 )
  641. {
  642. // Blat out the hitbox size + origin + group
  643. RefreshHitbox();
  644. return;
  645. }
  646. Vector size, origin;
  647. mstudiobbox_t* pHitbox;
  648. const char *pGroup;
  649. // Gotta do it this way since getLabel whacks the previous return result to getLable
  650. const char* pLabel = m_eOriginX->getLabel();
  651. if (!pLabel)
  652. goto errOut;
  653. origin.x = atof( pLabel );
  654. pLabel = m_eOriginY->getLabel();
  655. if (!pLabel)
  656. goto errOut;
  657. origin.y = atof( pLabel );
  658. pLabel = m_eOriginZ->getLabel();
  659. if (!pLabel)
  660. goto errOut;
  661. origin.z = atof( pLabel );
  662. pLabel = m_eSizeX->getLabel();
  663. if (!pLabel)
  664. goto errOut;
  665. size.x = atof( pLabel );
  666. pLabel = m_eSizeY->getLabel();
  667. if (!pLabel)
  668. goto errOut;
  669. size.y = atof( pLabel );
  670. pLabel = m_eSizeZ->getLabel();
  671. if (!pLabel)
  672. goto errOut;
  673. size.z = atof( pLabel );
  674. pHitbox = &g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[m_Hitbox].m_BBox;
  675. // Recompute the hitbox from the new data
  676. VectorMA( origin, -0.5f, size, pHitbox->bbmin );
  677. VectorMA( origin, 0.5f, size, pHitbox->bbmax );
  678. pGroup = m_eHitboxGroup->getLabel();
  679. if (pGroup)
  680. {
  681. pHitbox->group = atol( pGroup );
  682. }
  683. // Store off the hitbox name
  684. g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[m_Hitbox].m_Name = m_eHitboxName->getLabel();
  685. errOut:
  686. RefreshHitbox();
  687. }
  688. //-----------------------------------------------------------------------------
  689. // Purpose: Hitbox set changed
  690. //-----------------------------------------------------------------------------
  691. void CBoneControlWindow::OnHitboxSetChanged( void )
  692. {
  693. m_Hitbox = 0;
  694. m_nHitboxSet = m_cHitboxSet->getSelectedIndex();
  695. PopulateHitboxLists();
  696. // Repopulate other controls
  697. ComputeHitboxList();
  698. RefreshHitbox();
  699. //OnHitboxGroupChanged( ); // Refresh hitbox will update the group label from the hitbox's group. No need to turn that back into a group #
  700. }
  701. //-----------------------------------------------------------------------------
  702. // Hitbox size/origin changed
  703. //-----------------------------------------------------------------------------
  704. void CBoneControlWindow::OnHitboxGroupChanged( )
  705. {
  706. if ( m_Hitbox >= 0 && g_pStudioModel->m_HitboxSets.Count() > 0 )
  707. {
  708. const char *pGroup = m_eHitboxGroup->getLabel();
  709. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes;
  710. if ( pGroup && list.IsInList( m_Hitbox ) )
  711. {
  712. mstudiobbox_t* pHitbox = &list[m_Hitbox].m_BBox;
  713. pHitbox->group = atol( pGroup );
  714. }
  715. }
  716. }
  717. //-----------------------------------------------------------------------------
  718. // Add, remove hitboxes
  719. //-----------------------------------------------------------------------------
  720. void CBoneControlWindow::OnAddHitbox( )
  721. {
  722. if (!g_pStudioModel)
  723. return;
  724. // Remove the 'none' entry
  725. if (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() > 0 &&
  726. m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() == 0)
  727. {
  728. m_cHitbox->removeAll();
  729. }
  730. int i = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes.AddToTail();
  731. HitboxInfo_t &hitbox = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[i];
  732. hitbox.m_BBox.bone = m_Bone;
  733. hitbox.m_BBox.group = 0;
  734. hitbox.m_BBox.bbmin.Init( -8, -8, -8 );
  735. hitbox.m_BBox.bbmax.Init( 8, 8, 8 );
  736. hitbox.m_BBox.szhitboxnameindex = 0;
  737. m_SetBoneHitBoxes[ m_nHitboxSet ].EnsureCount( m_Bone + 1 );
  738. m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].AddToTail(i);
  739. char buf[32];
  740. sprintf(buf, "%d", i );
  741. m_cHitbox->add ( buf );
  742. OnHitboxSelected(m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() - 1);
  743. }
  744. void CBoneControlWindow::OnDeleteHitbox( )
  745. {
  746. if ( !g_pStudioModel || ( m_Hitbox < 0 ) )
  747. return;
  748. g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes.Remove(m_Hitbox);
  749. for (int i = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count(); --i >= 0; )
  750. {
  751. if (m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][i] == m_Hitbox)
  752. {
  753. m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Remove(i);
  754. break;
  755. }
  756. }
  757. // Recompute the list of hitboxes
  758. ComputeHitboxList();
  759. }
  760. //-----------------------------------------------------------------------------
  761. // Sets the surface property
  762. //-----------------------------------------------------------------------------
  763. void CBoneControlWindow::OnSurfaceProp( int propIndex )
  764. {
  765. if (g_pStudioModel->IsModelLoaded())
  766. {
  767. // Store off the new surface prop symbol
  768. CUtlSymbol prop( physprop->GetPropName( propIndex ) );
  769. g_pStudioModel->m_SurfaceProps[m_Bone] = prop;
  770. }
  771. }
  772. //-----------------------------------------------------------------------------
  773. // Duplictes the surface property to all children
  774. //-----------------------------------------------------------------------------
  775. void CBoneControlWindow::OnSurfacePropApplyToChildren_R( int bone, CUtlSymbol prop )
  776. {
  777. g_pStudioModel->m_SurfaceProps[bone] = prop;
  778. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  779. for ( int i = 0; i < pHdr->numbones(); i++ )
  780. {
  781. mstudiobone_t* pBone = pHdr->pBone(i);
  782. if (pBone->parent == bone)
  783. {
  784. OnSurfacePropApplyToChildren_R( i, prop );
  785. }
  786. }
  787. }
  788. void CBoneControlWindow::OnSurfacePropApplyToChildren( )
  789. {
  790. if (!g_pStudioModel)
  791. return;
  792. CUtlSymbol prop = g_pStudioModel->m_SurfaceProps[m_Bone];
  793. OnSurfacePropApplyToChildren_R( m_Bone, prop );
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Writes out qc-style text to a utlbuffer
  797. //-----------------------------------------------------------------------------
  798. bool CBoneControlWindow::SerializeQC( CUtlBuffer& buf )
  799. {
  800. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  801. if (!hdr)
  802. return false;
  803. buf.Printf("// .qc block generated by HLMV begins.\n\n");
  804. // Print out the surface props
  805. buf.Printf( "$surfaceprop \"%s\"\n", g_pStudioModel->m_SurfaceProps[0].String() );
  806. Assert( g_pStudioModel->m_SurfaceProps.Count() == hdr->numbones() );
  807. int i;
  808. for ( i = 1; i < g_pStudioModel->m_SurfaceProps.Count(); ++i)
  809. {
  810. mstudiobone_t* pBone = hdr->pBone(i);
  811. // Don't bother printing out the name if it's got the same
  812. // surface prop as the parent does
  813. if (pBone->parent >= 0)
  814. {
  815. if (!stricmp( g_pStudioModel->m_SurfaceProps[i].String(),
  816. g_pStudioModel->m_SurfaceProps[pBone->parent].String() ))
  817. continue;
  818. }
  819. buf.Printf( "$jointsurfaceprop \"%s\"\t \"%s\"\n", pBone->pszName(),
  820. g_pStudioModel->m_SurfaceProps[i].String() );
  821. }
  822. if (!m_cAutoHitbox->isChecked())
  823. {
  824. buf.Printf("\n");
  825. for ( i = 0 ; i < g_pStudioModel->m_HitboxSets.Count(); i++ )
  826. {
  827. buf.Printf( "\n$hboxset \"%s\"\n\n", g_pStudioModel->m_HitboxSets[ i ].m_Name.Get() );
  828. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ i ].m_Hitboxes;
  829. for ( unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) )
  830. {
  831. mstudiobbox_t &hitbox = list[j].m_BBox;
  832. mstudiobone_t* pBone = hdr->pBone( hitbox.bone );
  833. buf.Printf( "$hbox %d \"%s\"\t %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f",
  834. hitbox.group, pBone->pszName(),
  835. hitbox.bbmin.x, hitbox.bbmin.y, hitbox.bbmin.z,
  836. hitbox.bbmax.x, hitbox.bbmax.y, hitbox.bbmax.z );
  837. if ( !list[j].m_Name.IsEmpty() )
  838. {
  839. buf.Printf( " \"%s\"", list[j].m_Name.Get() );
  840. }
  841. buf.Printf( "\n" );
  842. }
  843. }
  844. }
  845. buf.Printf("\n// .qc block generated by HLMV ends.\n\n");
  846. return true;
  847. }
  848. //-----------------------------------------------------------------------------
  849. // Generates the QC file and copies it to the clipboard
  850. //-----------------------------------------------------------------------------
  851. void CBoneControlWindow::OnGenerateQC( )
  852. {
  853. CUtlBuffer outbuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  854. SerializeQC( outbuf );
  855. if ( outbuf.TellPut() )
  856. {
  857. // Null-terminate the string so CopyString works...
  858. outbuf.PutChar('\0');
  859. Sys_CopyStringToClipboard( (const char*)outbuf.Base() );
  860. }
  861. }
  862. //-----------------------------------------------------------------------------
  863. // Purpose:
  864. //-----------------------------------------------------------------------------
  865. void CBoneControlWindow::OnHitboxAddSet( void )
  866. {
  867. char sz[ 32 ];
  868. sprintf( sz, "set%02i", g_pStudioModel->m_HitboxSets.Count() + 1 );
  869. int newsetnumber = g_pStudioModel->m_HitboxSets.AddToTail();
  870. g_pStudioModel->m_HitboxSets[ newsetnumber ].m_Name = sz;
  871. ComputeHitboxSetList();
  872. m_cHitboxSet->select( newsetnumber );
  873. OnHitboxSetChanged();
  874. }
  875. //-----------------------------------------------------------------------------
  876. // Purpose:
  877. //-----------------------------------------------------------------------------
  878. void CBoneControlWindow::OnHitboxDeleteSet( void )
  879. {
  880. // Can't remove last element
  881. if ( m_nHitboxSet == 0 )
  882. {
  883. return;
  884. }
  885. g_pStudioModel->m_HitboxSets.Remove( m_nHitboxSet );
  886. ComputeHitboxSetList();
  887. m_cHitboxSet->select( 0 );
  888. OnHitboxSetChanged();
  889. }
  890. //-----------------------------------------------------------------------------
  891. // Purpose:
  892. //-----------------------------------------------------------------------------
  893. void CBoneControlWindow::OnHitboxSetChangeName( void )
  894. {
  895. if ( g_pStudioModel->m_HitboxSets.Count() <= 0 )
  896. return;
  897. char newname[ 512 ];
  898. strcpy( newname, m_eHitboxSetName->getLabel() );
  899. if ( !newname[ 0 ] )
  900. return;
  901. g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Name = newname;
  902. int oldsel = m_nHitboxSet;
  903. ComputeHitboxSetList();
  904. m_cHitboxSet->select( oldsel );
  905. OnHitboxSetChanged();
  906. }
  907. //-----------------------------------------------------------------------------
  908. // Responds to events on controls in the window
  909. //-----------------------------------------------------------------------------
  910. int CBoneControlWindow::handleEvent (mxEvent *event)
  911. {
  912. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  913. if ( event->event == mxEvent::KeyDown )
  914. {
  915. // FIXME: calling this forces the edit box to lose position
  916. // OnHitboxChanged( );
  917. return 1;
  918. }
  919. switch( event->action )
  920. {
  921. case IDC_BONE_BONELIST:
  922. if (g_pStudioModel->IsModelLoaded())
  923. {
  924. OnHitboxGroupChanged( );
  925. OnBoneSelected( m_cBone->getSelectedIndex() );
  926. }
  927. break;
  928. case IDC_BONE_HIGHLIGHT_BONE:
  929. OnBoneHighlighted( ((mxCheckBox *) event->widget)->isChecked() );
  930. break;
  931. case IDC_BONE_HIGHLIGHT_HITBOX:
  932. OnHitboxHighlighted( ((mxCheckBox *) event->widget)->isChecked() );
  933. break;
  934. case IDC_BONE_SHOW_DEFAULT_POSE:
  935. OnShowDefaultPose( ((mxCheckBox *) event->widget)->isChecked() );
  936. break;
  937. case IDC_BONE_HITBOXLIST:
  938. OnHitboxGroupChanged( );
  939. OnHitboxSelected( m_cHitbox->getSelectedIndex() );
  940. break;
  941. case IDC_BONE_HITBOXSET:
  942. OnHitboxSetChanged();
  943. break;
  944. case IDC_BONE_HITBOXADDSET:
  945. OnHitboxAddSet();
  946. break;
  947. case IDC_BONE_HITBOXDELETESET:
  948. OnHitboxDeleteSet();
  949. break;
  950. case IDC_BONE_HITBOXSETNAME:
  951. OnHitboxSetChangeName();
  952. break;
  953. case IDC_BONE_UPDATE_HITBOX:
  954. OnHitboxChanged( );
  955. break;
  956. case IDC_BONE_ADD_HITBOX:
  957. OnHitboxGroupChanged( );
  958. OnAddHitbox( );
  959. break;
  960. case IDC_BONE_DELETE_HITBOX:
  961. OnDeleteHitbox( );
  962. break;
  963. case IDC_BONE_USE_AUTOGENERATED_HITBOXES:
  964. if (g_pStudioModel->IsModelLoaded())
  965. OnAutogenerateHitboxes( m_cAutoHitbox->isChecked() );
  966. break;
  967. case IDC_BONE_SURFACEPROP:
  968. OnSurfaceProp( m_cSurfaceProp->getSelectedIndex() );
  969. break;
  970. case IDC_BONE_APPLY_TO_CHILDREN:
  971. if (g_pStudioModel->IsModelLoaded())
  972. OnSurfacePropApplyToChildren( );
  973. break;
  974. case IDC_BONE_GENERATEQC:
  975. if (g_pStudioModel->IsModelLoaded())
  976. {
  977. OnHitboxGroupChanged( );
  978. OnGenerateQC( );
  979. }
  980. break;
  981. default:
  982. return 0;
  983. }
  984. return 1;
  985. }
  986. //-----------------------------------------------------------------------------
  987. // Singleton instance
  988. //-----------------------------------------------------------------------------
  989. ControlPanel *g_ControlPanel = 0;
  990. ControlPanel::ControlPanel( mxWindow *parent )
  991. : mxWindow( parent, 0, 0, 0, 0, "Control Panel", mxWindow::Normal )
  992. {
  993. InitViewerSettings ( "hlmv" );
  994. // frame slider
  995. new mxLabel( this, 5, 220, 50, 18, "Frame" );
  996. slForceFrame = new mxSlider( this, 55, 220, 450, 18, IDC_FORCEFRAME );
  997. slForceFrame->setRange( 0, 1.0 );
  998. slForceFrame->setValue( 0.0 );
  999. slForceFrame->setSteps( 1, 1 );
  1000. mxToolTip::add( slForceFrame, "Force To Frame" );
  1001. lForcedFrame = new mxLabel( this, 505, 220, 30, 18, "0" );
  1002. // create tabcontrol with subdialog windows
  1003. tab = new mxTab( this, 0, 20, 0, 0, IDC_TAB );
  1004. #ifdef WIN32
  1005. SetWindowLong( ( HWND )tab->getHandle(), GWL_EXSTYLE, WS_EX_CLIENTEDGE );
  1006. #endif
  1007. SetupRenderWindow( tab );
  1008. SetupSequenceWindow( tab );
  1009. SetupBodyWindow( tab );
  1010. SetupFlexWindow( tab );
  1011. SetupPhysicsWindow( tab );
  1012. SetupBoneControlWindow( tab );
  1013. SetupAttachmentsWindow( tab );
  1014. SetupIKRuleWindow( tab );
  1015. SetupEventWindow( tab );
  1016. g_ControlPanel = this;
  1017. iSelectionToSequence = NULL;
  1018. iSequenceToSelection = NULL;
  1019. }
  1020. //-----------------------------------------------------------------------------
  1021. // Sets up the window dealing with render control
  1022. //-----------------------------------------------------------------------------
  1023. void ControlPanel::SetupRenderWindow( mxTab* pTab )
  1024. {
  1025. wRender = new mxWindow (this, 0, 0, 0, 0);
  1026. tab->add (wRender, "Render");
  1027. cRenderMode = new mxChoice (wRender, 5, 2, 100, 22, IDC_RENDERMODE);
  1028. cRenderMode->add ("Wireframe");
  1029. // cRenderMode->add ("Flatshaded");
  1030. cRenderMode->add ("Smoothshaded");
  1031. cRenderMode->add ("Textured");
  1032. cRenderMode->add ("BoneWeights");
  1033. cRenderMode->add ("BadVertexData");
  1034. cRenderMode->add ("UV Chart");
  1035. cRenderMode->select (2);
  1036. mxToolTip::add (cRenderMode, "Select Render Mode");
  1037. cbGround = new mxCheckBox (wRender, 125, 5, 150, 20, "Ground (Ctrl-G)", IDC_GROUND);
  1038. cbGround->setEnabled( true );
  1039. cbMovement = new mxCheckBox (wRender, 125, 25, 150, 20, "Movement (Ctrl-M)", IDC_MOVEMENT);
  1040. cbMovement->setEnabled( true );
  1041. cbBackground = new mxCheckBox (wRender, 125, 45, 150, 20, "Background (Ctrl-B)", IDC_BACKGROUND);
  1042. cbBackground->setEnabled( true );
  1043. cbHitBoxes = new mxCheckBox (wRender, 125, 65, 150, 20, "Hit Boxes (Ctrl-H)", IDC_HITBOXES);
  1044. cbSequenceBoxes = new mxCheckBox (wRender, 125, 85, 150, 20, "Seq. Boxes", IDC_SEQUENCEBOXES);
  1045. cbShadow = new mxCheckBox (wRender, 125, 105, 150, 20, "Shadow (Ctrl-S)", IDC_SHADOW);
  1046. cbSoftwareSkin = new mxCheckBox (wRender, 125, 125, 150, 20, "Software Skin", IDC_SOFTWARESKIN);
  1047. cbSoftwareSkin->setEnabled( true );
  1048. cbOverbright2 = new mxCheckBox (wRender, 125, 145, 150, 20, "Enable Overbrightening", IDC_OVERBRIGHT2);
  1049. cbOverbright2->setEnabled( true );
  1050. cbOverbright2->setChecked( true );
  1051. setOverbright( true );
  1052. cbAttachments = new mxCheckBox (wRender, 5, 45, 120, 20, "Attachments (Ctrl-A)", IDC_ATTACHMENTS);
  1053. cbAttachments->setEnabled( true );
  1054. cbBones = new mxCheckBox (wRender, 5, 65, 120, 20, "Bones (Ctrl-O)", IDC_BONES);
  1055. cbNormals = new mxCheckBox (wRender, 5, 85, 120, 20, "Normals (Ctrl-N)", IDC_NORMALS);
  1056. cbNormals->setEnabled( true );
  1057. cbNormals->setChecked( false );
  1058. cbTangentFrame = new mxCheckBox( wRender, 5, 105, 120, 20, "Tangents (Ctrl-T)", IDC_TANGENTFRAME );
  1059. cbTangentFrame->setEnabled( true );
  1060. cbTangentFrame->setChecked( false );
  1061. cbOverlayWireframe = new mxCheckBox (wRender, 5, 125, 120, 20, "Wireframe (Ctrl-W)", IDC_OVERLAY_WIREFRAME);
  1062. cbOverlayWireframe->setEnabled( true );
  1063. cbOverlayWireframe->setChecked( false );
  1064. // cbParallaxMap = new mxCheckBox (wRender, 5, 125, 100, 20, "Parallax Mapping", IDC_PARALLAXMAP);
  1065. // cbParallaxMap->setEnabled( true );
  1066. // cbParallaxMap->setChecked( true );
  1067. cbSpecular = new mxCheckBox (wRender, 5, 145, 120, 20, "Specular", IDC_SPECULAR);
  1068. cbSpecular->setEnabled( true );
  1069. cbSpecular->setChecked( true );
  1070. cbNormalMap = new mxCheckBox (wRender, 5, 25, 100, 20, "Normal Mapping", IDC_NORMALMAP);
  1071. cbNormalMap->setEnabled( true );
  1072. cbNormalMap->setChecked( true );
  1073. cbRunIK = new mxCheckBox (wRender, 275, 65, 150, 20, "Enable IK", IDC_RUNIK);
  1074. cbEnableHead = new mxCheckBox (wRender, 275, 85, 150, 20, "Head Turn", IDC_HEADTURN);
  1075. cbIllumPosition = new mxCheckBox (wRender, 275, 105, 150, 20, "Illum. Position", IDC_ILLUMPOSITION);
  1076. cbPlaySounds = new mxCheckBox (wRender, 275, 125, 150, 20, "Play Sounds", IDC_PLAYSOUNDS);
  1077. cbShowOriginAxis = new mxCheckBox (wRender, 275, 145, 150, 20, "Show Origin Axis", IDC_SHOWORIGINAXIS);
  1078. new mxLabel (wRender, 275, 170, 45, 18, "Axis Len:");
  1079. leOriginAxisLength = new mxSlider(wRender, 320, 165, 105, 22, IDC_ORIGINAXISLENGTH);
  1080. leOriginAxisLength->setRange( 1, 100 );
  1081. leOriginAxisLength->setValue( 10 );
  1082. new mxCheckBox (wRender, 275, 5, 150, 20, "Physics Model", IDC_PHYSICSMODEL);
  1083. cHighlightBone = new mxChoice (wRender, 275, 25, 150, 22, IDC_PHYSICSHIGHLIGHT);
  1084. cHighlightBone->add ("None");
  1085. cHighlightBone->select (0);
  1086. mxToolTip::add (cHighlightBone, "Select Physics Bone to highlight");
  1087. new mxLabel (wRender, 5, 170, 30, 18, "FOV:");
  1088. leFOV = new mxLineEdit(wRender, 35, 165, 30, 22, "65", IDC_RENDER_FOV);
  1089. }
  1090. //-----------------------------------------------------------------------------
  1091. // Sets up the window dealing with sequence control
  1092. //-----------------------------------------------------------------------------
  1093. void ControlPanel::SetupSequenceWindow( mxTab* pTab )
  1094. {
  1095. mxWindow *wSequence = new mxWindow (this, 0, 0, 0, 0);
  1096. tab->add (wSequence, "Sequence");
  1097. for ( int i = 0; i < MAX_SEQUENCES; i++ )
  1098. {
  1099. cSequence[i] = new mxChoice (wSequence, 5, 5 + i * 22, 200, 22, IDC_SEQUENCE0+i);
  1100. mxToolTip::add (cSequence[i], "Select Sequence");
  1101. slSequence[i] = new mxSlider (wSequence, 208, 5 + i * 22, 80, 18, IDC_SEQUENCESCALE0+i);
  1102. slSequence[i]->setRange (0, 1.0, 100);
  1103. slSequence[i]->setValue (0.0);
  1104. rbFrameSelection[i] = new mxRadioButton (wSequence, 300, 5 + i * 22, 35, 22, "", IDC_FRAMESELECTION0+i, i == 0);
  1105. }
  1106. slSequence[0]->setVisible( false );
  1107. laGroundSpeed = new mxLabel( wSequence, 208, 5, 80, 18, "" );
  1108. for ( int i = 0; i < NUM_POSEPARAMETERS; i++ )
  1109. {
  1110. int x, y;
  1111. x = 334;
  1112. y = 2 + (i % 8) * 17;
  1113. cPoseParameter[i] = new mxChoice (wSequence, 520, y, 96, 22, IDC_POSEPARAMETER+i);
  1114. cPoseParameter[i]->setVisible( false );
  1115. slPoseParameter[i] = new mxSlider (wSequence, x, y, 140, 16, IDC_POSEPARAMETER_SCALE+i);
  1116. slPoseParameter[i]->setRange (0.0, 1.0, 1000);
  1117. mxToolTip::add (slPoseParameter[i], "Parameter");
  1118. slPoseParameter[i]->setVisible( false );
  1119. lePoseParameter[i] = new mxLineEdit ( wSequence, x + 146, y, 40, 16, "X", IDC_POSEPARAMETER_VALUE+i );
  1120. lePoseParameter[i]->setVisible( false );
  1121. }
  1122. slSpeedScale = new mxSlider (wSequence, 5, 115, 200, 18, IDC_SPEEDSCALE);
  1123. slSpeedScale->setRange (0, 1.0, 100);
  1124. slSpeedScale->setValue (1.0);
  1125. mxToolTip::add (slSpeedScale, "Speed Scale");
  1126. laFPS = new mxLabel (wSequence, 208, 115, 128, 22, "" );
  1127. new mxCheckBox (wSequence, 5, 142, 150, 20, "Blend Sequence Changes", IDC_BLENDSEQUENCECHANGES);
  1128. new mxButton( wSequence, 155, 142, 80, 20, "Blend Now", IDC_BLENDNOW );
  1129. laBlendAmount = new mxLabel( wSequence, 240, 142, 60, 20, "" );
  1130. slBlendTime = new mxSlider( wSequence, 308, 142, 200, 18, IDC_BLENDTIME );
  1131. slBlendTime->setRange( 0, 1.0, 100 );
  1132. slBlendTime->setValue( DEFAULT_BLEND_TIME );
  1133. laBlendTime = new mxLabel( wSequence, 540, 142, 80, 22, "" );
  1134. new mxLabel (wSequence, 5, 170, 90, 18, "Activity modifiers:");
  1135. cActivityModifiers = new mxChoice (wSequence, 105, 166, 350, 22, IDC_ACTIVITY_MODIFIERS);
  1136. new mxCheckBox (wSequence, 460, 166, 350, 22, "Animate weapons", IDC_ANIMATEWEAPONS);
  1137. }
  1138. //-----------------------------------------------------------------------------
  1139. // Sets up the window dealing with body control
  1140. //-----------------------------------------------------------------------------
  1141. void ControlPanel::SetupBodyWindow( mxTab* pTab )
  1142. {
  1143. mxWindow *wBody = new mxWindow (this, 0, 0, 0, 0);
  1144. pTab->add (wBody, "Model");
  1145. cBodypart = new mxChoice (wBody, 5, 5, 100, 22, IDC_BODYPART);
  1146. mxToolTip::add (cBodypart, "Choose a bodypart");
  1147. cSubmodel = new mxChoice (wBody, 110, 5, 100, 22, IDC_SUBMODEL);
  1148. mxToolTip::add (cSubmodel, "Choose a submodel of current bodypart");
  1149. cController = new mxChoice (wBody, 5, 30, 100, 22, IDC_CONTROLLER);
  1150. mxToolTip::add (cController, "Choose a bone controller");
  1151. slController = new mxSlider (wBody, 105, 32, 100, 18, IDC_CONTROLLERVALUE);
  1152. slController->setRange (0, 255);
  1153. mxToolTip::add (slController, "Change current bone controller value");
  1154. lModelInfo1 = new mxLabel (wBody, 220, 5, 120, 80, "No Model.");
  1155. lModelInfo2 = new mxLabel (wBody, 340, 5, 120, 130, "");
  1156. cSkin = new mxChoice (wBody, 5, 55, 100, 22, IDC_SKINS);
  1157. mxToolTip::add (cSkin, "Choose a skin family");
  1158. new mxLabel (wBody, 5, 170, 90, 18, "Materials used:");
  1159. cMaterials = new mxChoice (wBody, 105, 166, 350, 22, IDC_MATERIALS);
  1160. mxToolTip::add (cMaterials, "Select material for UV Chart view");
  1161. lModelInfo3 = new mxLabel (wBody, 220, 100, 220, 18, "");
  1162. lModelInfo4 = new mxLabel (wBody, 220, 118, 260, 18, "");
  1163. lModelInfo5 = new mxLabel (wBody, 220, 136, 120, 18, "");
  1164. setTransparent( false );
  1165. cbAutoLOD = new mxCheckBox (wBody, 5, 80, 100, 20, "Auto LOD", IDC_AUTOLOD);
  1166. cbAutoLOD->setEnabled( true );
  1167. cLODChoice = new mxChoice( wBody, 5, 101, 100, 22, IDC_LODCHOICE);
  1168. mxToolTip::add (cLODChoice, "Select model LOD to render");
  1169. new mxLabel (wBody, 5, 126, 60, 18, "LOD Switch:");
  1170. leLODSwitch = new mxLineEdit(wBody, 70, 126, 35, 22, "", IDC_LODSWITCH);
  1171. new mxLabel (wBody, 5, 151, 60, 18, "LOD Metric:" );
  1172. lLODMetric = new mxLabel( wBody, 70, 151, 35, 22, "" );
  1173. new mxLabel( wBody, 505, 5, 100, 18, "VMTs Loaded:" );
  1174. cMessageList = new mxListBox( wBody, 500, 25, 540, 160, IDC_MESSAGES );
  1175. cMessageList->add ("None");
  1176. cMessageList->select (1);
  1177. mxToolTip::add (cMessageList, "Materials (VMT files) this model has loaded");
  1178. new mxLabel( wBody, 785, 5, 100, 18, "Shader:" );
  1179. cShaderUsed = new mxListBox( wBody, 830, 3, 210, 28, IDC_SHADERS );
  1180. cShaderUsed->add ("Select material to show shader");
  1181. cShaderUsed->select (0);
  1182. mxToolTip::add (cShaderUsed, "Shader Used");
  1183. }
  1184. //-----------------------------------------------------------------------------
  1185. // Sets up the window dealing with flexes
  1186. //-----------------------------------------------------------------------------
  1187. #define FLEX_DROPDOWN_WIDTH 90
  1188. #define FLEX_SLIDER_WIDTH 100
  1189. #define FLEX_ROWS_OF_SLIDERS 8
  1190. void ControlPanel::SetupFlexWindow( mxTab* pTab )
  1191. {
  1192. mxWindow *wFlex = new mxWindow (this, 0, 0, 0, 0);
  1193. pTab->add (wFlex, "Flex");
  1194. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  1195. {
  1196. int w = (i / FLEX_ROWS_OF_SLIDERS) * (FLEX_SLIDER_WIDTH + FLEX_DROPDOWN_WIDTH + 4) + 5;
  1197. int h = (i % FLEX_ROWS_OF_SLIDERS) * 20 + 5;
  1198. cFlex[i] = new mxChoice (wFlex, w, h, FLEX_DROPDOWN_WIDTH, 22, IDC_FLEX + i);
  1199. mxToolTip::add (cFlex[i], "Select Flex");
  1200. slFlexScale[i] = new mxSlider (wFlex, w + FLEX_DROPDOWN_WIDTH, h, FLEX_SLIDER_WIDTH, 18, IDC_FLEXSCALE + i);
  1201. slFlexScale[i]->setRange (0, 1.0);
  1202. slFlexScale[i]->setValue (0);
  1203. mxToolTip::add (slFlexScale[i], "Flex Scale");
  1204. }
  1205. {
  1206. int h = FLEX_ROWS_OF_SLIDERS * 20 + 5;
  1207. new mxButton( wFlex, 5, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Reset", IDC_FLEXDEFAULTS );
  1208. int w = ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
  1209. new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Random", IDC_FLEXRANDOM );
  1210. w += ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
  1211. new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Zero", IDC_FLEXZERO );
  1212. w += ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
  1213. new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "One", IDC_FLEXONE );
  1214. }
  1215. }
  1216. //-----------------------------------------------------------------------------
  1217. // Sets up the window dealing with physics
  1218. //-----------------------------------------------------------------------------
  1219. void ControlPanel::SetupPhysicsWindow( mxTab* pTab )
  1220. {
  1221. // Physics Window
  1222. mxWindow *wPhysics = new mxWindow (this, 0, 0, 0, 0);
  1223. pTab->add (wPhysics, "Physics");
  1224. new mxLabel (wPhysics, 5, 33, 30, 18, "Mass");
  1225. leMass = new mxLineEdit(wPhysics, 35, 30, 70, 22, "", IDC_PHYS_MASS);
  1226. cPhysicsBone = new mxChoice (wPhysics, 5, 5, 345, 22, IDC_PHYS_BONE);
  1227. cPhysicsBone->add ("None");
  1228. cPhysicsBone->select (0);
  1229. new mxCheckBox (wPhysics, 5, 55, 100, 20, "Highlight", IDC_PHYSICSMODEL);
  1230. int x = 5;
  1231. int y = 80;
  1232. rbConstraintAxis[0] = new mxRadioButton (wPhysics, x, y, 35, 22, "X", IDC_PHYS_CON_AXIS_X, true);
  1233. rbConstraintAxis[1] = new mxRadioButton (wPhysics, x+35, y, 35, 22, "Y", IDC_PHYS_CON_AXIS_Y);
  1234. rbConstraintAxis[2] = new mxRadioButton (wPhysics, x+70, y, 35, 22, "Z", IDC_PHYS_CON_AXIS_Z);
  1235. setPhysicsAxis( 0 );
  1236. y += 25;
  1237. new mxLabel (wPhysics, x, y, 45, 18, "Friction");
  1238. slPhysicsFriction = new mxSlider (wPhysics, x+50, y, 180, 18, IDC_PHYS_CON_FRICTION);
  1239. slPhysicsFriction->setRange (0, 1000.0, 1000);
  1240. slPhysicsFriction->setValue (0);
  1241. slPhysicsFriction->setSteps( 1, 1 );
  1242. lPhysicsFriction = new mxLabel (wPhysics, x+230, y, 30, 18, "0");
  1243. x = 135;
  1244. y = 30;
  1245. new mxLabel (wPhysics, 115, y, 30, 18, "Min");
  1246. slPhysicsConMin = new mxSlider (wPhysics, x, y, 180, 18, IDC_PHYS_CON_MIN);
  1247. slPhysicsConMin->setRange (-180, 180.0, 360);
  1248. slPhysicsConMin->setValue (-90);
  1249. slPhysicsConMin->setSteps( 1, 1 );
  1250. lPhysicsConMin = new mxLabel (wPhysics, x+180, y, 30, 18, "-90");
  1251. y += 25;
  1252. new mxLabel (wPhysics, 115, y, 30, 18, "Max");
  1253. slPhysicsConMax = new mxSlider (wPhysics, x, y, 180, 18, IDC_PHYS_CON_MAX);
  1254. slPhysicsConMax->setRange (-180.0, 180.0, 360);
  1255. slPhysicsConMax->setValue (90.0);
  1256. slPhysicsConMax->setSteps( 1, 1 );
  1257. lPhysicsConMax = new mxLabel (wPhysics, x+180, y, 30, 18, "90");
  1258. y += 25;
  1259. new mxLabel (wPhysics, 115, y, 30, 18, "Test");
  1260. slPhysicsConTest = new mxSlider (wPhysics, x, y, 55, 18, IDC_PHYS_CON_TEST);
  1261. slPhysicsConTest->setRange (0, 1.0, 100);
  1262. slPhysicsConTest->setValue (0);
  1263. cbLinked = new mxCheckBox (wPhysics, 200, y, 50, 20, "Link", IDC_PHYS_CON_LINK_LIMITS);
  1264. mxToolTip::add (cbLinked, "Link mins/maxs to be symmetric");
  1265. new mxButton (wPhysics, 250, y, 80, 22, "Generate QC", IDC_PHYS_QCFILE);
  1266. x += 220;
  1267. y = 5;
  1268. new mxLabel (wPhysics, x, y, 55, 18, "Mass Bias");
  1269. new mxLabel (wPhysics, x, y+25, 55, 18, "Inertia");
  1270. new mxLabel (wPhysics, x, y+50, 55, 18, "Damping");
  1271. new mxLabel (wPhysics, x, y+75, 55, 18, "Rot Damp");
  1272. new mxLabel (wPhysics, x, y+100+3, 55, 18, "Material");
  1273. x += 55;
  1274. slPhysicsParamMassBias = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_MASSBIAS );
  1275. slPhysicsParamMassBias->setRange (0, 10.0, 100);
  1276. slPhysicsParamMassBias->setValue (1.0);
  1277. slPhysicsParamMassBias->setSteps( 1, 1 );
  1278. lPhysicsParamMassBias = new mxLabel (wPhysics, x+80, y, 30, 18, "1.0");
  1279. y += 25;
  1280. slPhysicsParamInertia = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_INERTIA );
  1281. slPhysicsParamInertia->setRange (0, 10.0, 100);
  1282. slPhysicsParamInertia->setValue (1.0);
  1283. slPhysicsParamInertia->setSteps( 1, 1 );
  1284. lPhysicsParamInertia = new mxLabel (wPhysics, x+80, y, 30, 18, "1.0");
  1285. y += 25;
  1286. slPhysicsParamDamping = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_DAMPING );
  1287. slPhysicsParamDamping->setRange (0, 1.0, 100);
  1288. slPhysicsParamDamping->setValue (0.01);
  1289. slPhysicsParamDamping->setSteps( 1, 1 );
  1290. lPhysicsParamDamping = new mxLabel (wPhysics, x+80, y, 30, 18, "0.5");
  1291. y += 25;
  1292. slPhysicsParamRotDamping = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_ROT_DAMPING );
  1293. slPhysicsParamRotDamping->setRange (0, 10.0, 200);
  1294. slPhysicsParamRotDamping->setValue (0.2);
  1295. slPhysicsParamRotDamping->setSteps( 1, 1 );
  1296. lPhysicsParamRotDamping = new mxLabel (wPhysics, x+80, y, 30, 18, "0.2");
  1297. y += 25;
  1298. lPhysicsMaterial = new mxLabel( wPhysics, x, y+3, 110, 18, "default" );
  1299. }
  1300. //-----------------------------------------------------------------------------
  1301. // Sets up the window dealing with ik rules
  1302. //-----------------------------------------------------------------------------
  1303. void ControlPanel::SetupIKRuleWindow( mxTab *pTab )
  1304. {
  1305. mxWindow *wIKRule = new mxWindow( this, 0, 0, 0, 0 );
  1306. pTab->add( wIKRule, "IKRule" );
  1307. new mxLabel( wIKRule, 5, 5, 80, 20, "Chain:" );
  1308. cIKChain = new mxChoice( wIKRule, 90, 5, 50, 20, IDC_IKRULE_CHAIN );
  1309. cIKChain->add( "lfoot" );
  1310. cIKChain->add( "rfoot" );
  1311. cIKChain->add( "lhand" );
  1312. cIKChain->add( "rhand" );
  1313. cIKChain->select( 0 );
  1314. mxToolTip::add( cIKChain, "Select IK Chain" );
  1315. new mxLabel( wIKRule, 145, 5, 80, 20, "Type:" );
  1316. cIKType = new mxChoice( wIKRule, 230, 5, 80, 20, IDC_IKRULE_CHOICE );
  1317. cIKType->add( "footstep" );
  1318. cIKType->add( "touch" );
  1319. cIKType->add( "release" );
  1320. cIKType->add( "attachment" );
  1321. cIKType->add( "unlatch" );
  1322. cIKType->select( 0 );
  1323. mxToolTip::add( cIKType, "Select IK Type" );
  1324. lIKTouch = new mxLabel( wIKRule, 315, 5, 80, 20, "Bone:" );
  1325. cIKTouch = new mxChoice( wIKRule, 400, 5, 200, 20, IDC_IKRULE_TOUCH );
  1326. PopulateBoneList( cIKTouch );
  1327. mxToolTip::add( cIKTouch, "Select Touched Bone" );
  1328. lIKAttachment = new mxLabel( wIKRule, 315, 5, 80, 20, "Attachment:" );
  1329. leIKAttachment = new mxLineEdit( wIKRule, 400, 5, 80, 20, "", IDC_IKRULE_ATTACHMENT );
  1330. cbIKRangeToggle = new mxCheckBox( wIKRule, 5, 30, 80, 20, "Range", IDC_IKRULE_RANGE_TOGGLE );
  1331. mxToolTip::add( cbIKRangeToggle, "Toggle range option" );
  1332. new mxButton( wIKRule, 90, 30, 30, 20, "start", IDC_IKRULE_RANGE_START_NOW );
  1333. leIKRangeStart = new mxLineEdit2( wIKRule, 120, 30, 35, 20, "..", IDC_IKRULE_RANGE_START );
  1334. new mxButton( wIKRule, 160, 30, 30, 20, "peak", IDC_IKRULE_RANGE_PEAK_NOW );
  1335. leIKRangePeak = new mxLineEdit2( wIKRule, 190, 30, 35, 20, "..", IDC_IKRULE_RANGE_PEAK );
  1336. new mxButton( wIKRule, 230, 30, 30, 20, "tail", IDC_IKRULE_RANGE_TAIL_NOW );
  1337. leIKRangeTail = new mxLineEdit2( wIKRule, 260, 30, 35, 20, "..", IDC_IKRULE_RANGE_TAIL );
  1338. new mxButton( wIKRule, 300, 30, 30, 20, "end", IDC_IKRULE_RANGE_END_NOW );
  1339. leIKRangeEnd = new mxLineEdit2( wIKRule, 330, 30, 35, 20, "..", IDC_IKRULE_RANGE_END );
  1340. cbIKContactToggle = new mxCheckBox( wIKRule, 5, 55, 80, 20, "Contact", IDC_IKRULE_CONTACT_TOGGLE );
  1341. mxToolTip::add( cbIKContactToggle, "Toggle contact option" );
  1342. new mxButton( wIKRule, 90, 55, 30, 20, "frame", IDC_IKRULE_CONTACT_FRAME_NOW );
  1343. leIKContactFrame = new mxLineEdit2( wIKRule, 120, 55, 35, 20, "", IDC_IKRULE_CONTACT_FRAME );
  1344. new mxLabel( wIKRule, 5, 80, 80, 20, "Transform using:" );
  1345. cIKUsing = new mxChoice( wIKRule, 90, 80, 80, 20, IDC_IKRULE_USING );
  1346. cIKUsing->add( "neither" );
  1347. cIKUsing->add( "source" );
  1348. cIKUsing->add( "sequence" );
  1349. cIKUsing->select( 0 );
  1350. mxToolTip::add( cIKUsing, "Choose Transform To Use" );
  1351. new mxLabel( wIKRule, 5, 105, 80, 20, "QC String:" );
  1352. leIKQCString = new mxLineEdit2( wIKRule, 90, 105, 500, 20, "", IDC_IKRULE_QC_STRING );
  1353. UpdateIKRuleWindow();
  1354. }
  1355. //-----------------------------------------------------------------------------
  1356. // Sets up the window dealing with events
  1357. //-----------------------------------------------------------------------------
  1358. void ControlPanel::SetupEventWindow( mxTab *pTab )
  1359. {
  1360. mxWindow *wEvents = new mxWindow( this, 0, 0, 0, 0 );
  1361. pTab->add( wEvents, "Events" );
  1362. new mxLabel( wEvents, 5, 5, 80, 20, "Sound:" );
  1363. mxButton *bSoundFrameNow = new mxButton( wEvents, 90, 5, 30, 20, "frame", IDC_EVENT_SOUND_FRAME_NOW );
  1364. mxToolTip::add( bSoundFrameNow, "Set sound start at the current frame" );
  1365. leEventSoundFrame = new mxLineEdit2( wEvents, 120, 5, 35, 20, "0", IDC_EVENT_SOUND_FRAME );
  1366. lbEventSoundName = new mxListBox( wEvents, 160, 5, 300, 170, IDC_EVENT_SOUND_NAME );
  1367. PopulateSoundNameList( lbEventSoundName );
  1368. mxToolTip::add( lbEventSoundName, "Select Sound Name" );
  1369. new mxLabel( wEvents, 5, 170, 80, 20, "QC String:" );
  1370. leEventQCString = new mxLineEdit2( wEvents, 90, 170, 450, 20, "", IDC_EVENT_QC_STRING );
  1371. BuildEventQCString();
  1372. }
  1373. //-----------------------------------------------------------------------------
  1374. // Sets up the window dealing with bone control
  1375. //-----------------------------------------------------------------------------
  1376. void ControlPanel::SetupBoneControlWindow( mxTab* pTab )
  1377. {
  1378. m_pBoneWindow = new CBoneControlWindow(this);
  1379. pTab->add (m_pBoneWindow, "Bones");
  1380. m_pBoneWindow->Init();
  1381. }
  1382. void ControlPanel::SetupAttachmentsWindow( mxTab *pTab )
  1383. {
  1384. m_pAttachmentsWindow = new CAttachmentsWindow(this);
  1385. pTab->add( m_pAttachmentsWindow, "Attachments" );
  1386. m_pAttachmentsWindow->Init();
  1387. }
  1388. int ControlPanel::GetCurrentHitboxSet( void )
  1389. {
  1390. return m_pBoneWindow ? m_pBoneWindow->GetHitboxSet() : 0;
  1391. }
  1392. ControlPanel::~ControlPanel()
  1393. {
  1394. g_ControlPanel = NULL;
  1395. }
  1396. void ControlPanel::OnDelete()
  1397. {
  1398. // for some reason, the destructor only gets called from mx when breakpoints are set,
  1399. // so to be safe, clear the pointer (possibly twice)
  1400. g_ControlPanel = NULL;
  1401. }
  1402. void ControlPanel::BuildEventQCString()
  1403. {
  1404. if ( g_ControlPanel == NULL )
  1405. return;
  1406. char qcstr[ 256 ];
  1407. Q_strcpy( qcstr, "{ event AE_CL_PLAYSOUND " );
  1408. Q_strcat( qcstr, leEventSoundFrame->getLabel(), sizeof(qcstr) );
  1409. Q_strcat( qcstr, " \"", sizeof(qcstr) );
  1410. int i = lbEventSoundName->getSelectedIndex();
  1411. Q_strcat( qcstr, lbEventSoundName->getItemText( i ), sizeof(qcstr) );
  1412. Q_strcat( qcstr, "\" }", sizeof(qcstr) );
  1413. leEventQCString->setText( qcstr );
  1414. }
  1415. void ControlPanel::BuildIKRuleQCString()
  1416. {
  1417. if ( g_ControlPanel == NULL )
  1418. return;
  1419. char qcstr[ 256 ];
  1420. Q_strcpy( qcstr, "ikrule " );
  1421. Q_strcat( qcstr, cIKChain->getLabel(), sizeof(qcstr) );
  1422. Q_strcat( qcstr, " ", sizeof(qcstr) );
  1423. const char *pType = cIKType->getLabel();
  1424. Q_strcat( qcstr, pType, sizeof(qcstr) );
  1425. if ( Q_strcmp( pType, "touch" ) == 0 )
  1426. {
  1427. Q_strcat( qcstr, " \"", sizeof(qcstr) );
  1428. if ( cIKTouch->getSelectedIndex() > 0 )
  1429. {
  1430. Q_strcat( qcstr, cIKTouch->getLabel(), sizeof(qcstr) );
  1431. }
  1432. Q_strcat( qcstr, "\"", sizeof(qcstr) );
  1433. }
  1434. else if ( Q_strcmp( pType, "attachment" ) == 0 )
  1435. {
  1436. Q_strcat( qcstr, " \"", sizeof(qcstr) );
  1437. Q_strcat( qcstr, leIKAttachment->getLabel(), sizeof(qcstr) );
  1438. Q_strcat( qcstr, "\"", sizeof(qcstr) );
  1439. }
  1440. if ( cbIKRangeToggle->isChecked() )
  1441. {
  1442. Q_strcat( qcstr, " range ", sizeof(qcstr) );
  1443. char str[ 20 ];
  1444. leIKRangeStart->getText( str, sizeof( str ) );
  1445. Q_strcat( qcstr, str, sizeof(qcstr) );
  1446. Q_strcat( qcstr, " ", sizeof(qcstr) );
  1447. leIKRangePeak->getText( str, sizeof( str ) );
  1448. Q_strcat( qcstr, str, sizeof(qcstr) );
  1449. Q_strcat( qcstr, " ", sizeof(qcstr) );
  1450. leIKRangeTail->getText( str, sizeof( str ) );
  1451. Q_strcat( qcstr, str, sizeof(qcstr) );
  1452. Q_strcat( qcstr, " ", sizeof(qcstr) );
  1453. leIKRangeEnd->getText( str, sizeof( str ) );
  1454. Q_strcat( qcstr, str, sizeof(qcstr) );
  1455. }
  1456. if ( cbIKContactToggle->isChecked() )
  1457. {
  1458. Q_strcat( qcstr, " contact ", sizeof(qcstr) );
  1459. char str[ 20 ];
  1460. leIKContactFrame->getText( str, sizeof( str ) );
  1461. Q_strcat( qcstr, str, sizeof(qcstr) );
  1462. }
  1463. int nUsing = cIKUsing->getSelectedIndex();
  1464. if ( nUsing > 0 )
  1465. {
  1466. if ( nUsing == 1 ) // source
  1467. {
  1468. Q_strcat( qcstr, " usesource", sizeof(qcstr) );
  1469. }
  1470. else if ( nUsing == 2 ) // sequence
  1471. {
  1472. Q_strcat( qcstr, " usesequence", sizeof(qcstr) );
  1473. }
  1474. }
  1475. leIKQCString->setText( qcstr );
  1476. }
  1477. void ControlPanel::UpdateIKRuleWindow()
  1478. {
  1479. const char *pIKType = cIKType->getLabel();
  1480. bool bIsTouch = Q_strcmp( pIKType, "touch" ) == 0;
  1481. bool bIsAttachment = Q_strcmp( pIKType, "attachment" ) == 0;
  1482. lIKTouch->setVisible( bIsTouch );
  1483. cIKTouch->setVisible( bIsTouch );
  1484. lIKAttachment->setVisible( bIsAttachment );
  1485. leIKAttachment->setVisible( bIsAttachment );
  1486. BuildIKRuleQCString();
  1487. }
  1488. int
  1489. ControlPanel::handleEvent (mxEvent *event)
  1490. {
  1491. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1492. if ( !g_ControlPanel )
  1493. return 1;
  1494. if ( event->event == mxEvent::Size )
  1495. {
  1496. tab->setBounds( 0, 0, event->width, max( 0, event->height - 20 ) );
  1497. return 1;
  1498. }
  1499. if ( event->event == mxEvent::KeyDown )
  1500. {
  1501. if ( tab->getSelectedIndex() == 4 )
  1502. {
  1503. handlePhysicsKey( event );
  1504. }
  1505. if (event->action >= IDC_POSEPARAMETER_VALUE && event->action < IDC_POSEPARAMETER_VALUE + NUM_POSEPARAMETERS)
  1506. {
  1507. int index = event->action - IDC_POSEPARAMETER_VALUE;
  1508. int poseparam = cPoseParameter[index]->getSelectedIndex();
  1509. float value = atof( lePoseParameter[index]->getLabel() );
  1510. setBlend( poseparam, value );
  1511. slPoseParameter[index]->setValue( g_pStudioModel->GetPoseParameter( poseparam ) );
  1512. return 1;
  1513. }
  1514. switch (event->key)
  1515. {
  1516. case 27:
  1517. if (!getParent ()) // fullscreen mode ?
  1518. mx::quit ();
  1519. break;
  1520. case '1':
  1521. case '2':
  1522. case '3':
  1523. case '4':
  1524. g_viewerSettings.renderMode = event->key - '1';
  1525. break;
  1526. case '-':
  1527. g_viewerSettings.speedScale -= 0.1f;
  1528. if (g_viewerSettings.speedScale < 0.0f)
  1529. g_viewerSettings.speedScale = 0.0f;
  1530. break;
  1531. case '+':
  1532. g_viewerSettings.speedScale += 0.1f;
  1533. if (g_viewerSettings.speedScale > 5.0f)
  1534. g_viewerSettings.speedScale = 5.0f;
  1535. break;
  1536. default:
  1537. return 0;
  1538. }
  1539. return 1;
  1540. }
  1541. switch (event->action)
  1542. {
  1543. case IDC_TAB:
  1544. {
  1545. int tabIndex = tab->getSelectedIndex();
  1546. // g_viewerSettings.highlightBone = -1;
  1547. g_viewerSettings.highlightHitbox = -1;
  1548. g_viewerSettings.showTexture = (tabIndex == 3) ? true : false;
  1549. g_viewerSettings.showPhysicsPreview = (tabIndex == 4) ? true : false;
  1550. setHighlightBone(cHighlightBone->getSelectedIndex());
  1551. if (tabIndex == 4)
  1552. {
  1553. setupPhysicsBone(cPhysicsBone->getSelectedIndex());
  1554. }
  1555. if (tabIndex == 5)
  1556. {
  1557. m_pBoneWindow->OnTabSelected();
  1558. }
  1559. if ( tabIndex == 6 )
  1560. {
  1561. m_pAttachmentsWindow->OnTabSelected();
  1562. }
  1563. else
  1564. {
  1565. m_pAttachmentsWindow->OnTabUnselected();
  1566. }
  1567. }
  1568. break;
  1569. case IDC_RENDERMODE:
  1570. {
  1571. int index = cRenderMode->getSelectedIndex();
  1572. if (index >= 0)
  1573. {
  1574. setRenderMode (index);
  1575. }
  1576. }
  1577. break;
  1578. case IDC_PHYSICSHIGHLIGHT:
  1579. {
  1580. int index = cHighlightBone->getSelectedIndex();
  1581. setHighlightBone(index);
  1582. }
  1583. break;
  1584. case IDC_RENDER_FOV:
  1585. {
  1586. mxLineEdit *pLineEdit = ((mxLineEdit *) event->widget);
  1587. const char *pText = pLineEdit->getLabel();
  1588. float val = atof( pText );
  1589. g_viewerSettings.fov = val;
  1590. break;
  1591. }
  1592. case IDC_ORIGINAXISLENGTH:
  1593. {
  1594. g_viewerSettings.originAxisLength = reinterpret_cast< mxSlider * >( event->widget )->getValue();
  1595. break;
  1596. }
  1597. case IDC_LODCHOICE:
  1598. {
  1599. int index = cLODChoice->getSelectedIndex();
  1600. if( index >= 0 )
  1601. {
  1602. setLOD( index, false, false );
  1603. }
  1604. break;
  1605. }
  1606. case IDC_LODSWITCH:
  1607. {
  1608. mxLineEdit *pLineEdit = ((mxLineEdit *) event->widget);
  1609. const char *pText = pLineEdit->getLabel();
  1610. float val = atof( pText );
  1611. g_pStudioModel->SetLODSwitchValue( g_viewerSettings.lod, val );
  1612. break;
  1613. }
  1614. case IDC_AUTOLOD:
  1615. setAutoLOD (((mxCheckBox *) event->widget)->isChecked());
  1616. break;
  1617. case IDC_SOFTWARESKIN:
  1618. setSoftwareSkin(((mxCheckBox *) event->widget)->isChecked());
  1619. break;
  1620. case IDC_OVERBRIGHT2:
  1621. setOverbright(((mxCheckBox *) event->widget)->isChecked());
  1622. break;
  1623. case IDC_GROUND:
  1624. setShowGround (((mxCheckBox *) event->widget)->isChecked());
  1625. break;
  1626. case IDC_MOVEMENT:
  1627. setShowMovement (((mxCheckBox *) event->widget)->isChecked());
  1628. break;
  1629. case IDC_BACKGROUND:
  1630. setShowBackground (((mxCheckBox *) event->widget)->isChecked());
  1631. break;
  1632. case IDC_HITBOXES:
  1633. g_viewerSettings.showHitBoxes = ((mxCheckBox *) event->widget)->isChecked();
  1634. break;
  1635. case IDC_SEQUENCEBOXES:
  1636. g_viewerSettings.showSequenceBoxes = ((mxCheckBox *) event->widget)->isChecked();
  1637. break;
  1638. case IDC_SHADOW:
  1639. g_viewerSettings.showShadow = ((mxCheckBox *) event->widget)->isChecked();
  1640. break;
  1641. case IDC_ILLUMPOSITION:
  1642. g_viewerSettings.showIllumPosition = ((mxCheckBox *) event->widget)->isChecked();
  1643. break;
  1644. case IDC_RUNIK:
  1645. g_viewerSettings.enableIK = ((mxCheckBox *) event->widget)->isChecked();
  1646. g_viewerSettings.enableTargetIK = ((mxCheckBox *) event->widget)->isChecked();
  1647. break;
  1648. case IDC_HEADTURN:
  1649. g_pStudioModel->SetSolveHeadTurn( ((mxCheckBox *) event->widget)->isChecked() ? 1 : 0 );
  1650. break;
  1651. case IDC_PHYSICSMODEL:
  1652. g_viewerSettings.showPhysicsModel = ((mxCheckBox *) event->widget)->isChecked();
  1653. break;
  1654. case IDC_BONES:
  1655. g_viewerSettings.showBones = ((mxCheckBox *) event->widget)->isChecked();
  1656. break;
  1657. case IDC_PLAYSOUNDS:
  1658. g_viewerSettings.playSounds = ((mxCheckBox *) event->widget)->isChecked();
  1659. break;
  1660. case IDC_NORMALMAP:
  1661. g_viewerSettings.enableNormalMapping = ((mxCheckBox *) event->widget)->isChecked();
  1662. break;
  1663. // case IDC_PARALLAXMAP:
  1664. // g_viewerSettings.enableParallaxMapping = ((mxCheckBox *) event->widget)->isChecked();
  1665. // break;
  1666. case IDC_SPECULAR:
  1667. g_viewerSettings.enableSpecular = ((mxCheckBox *) event->widget)->isChecked();
  1668. break;
  1669. case IDC_NORMALS:
  1670. g_viewerSettings.showNormals = ((mxCheckBox *) event->widget)->isChecked();
  1671. break;
  1672. case IDC_TANGENTFRAME:
  1673. g_viewerSettings.showTangentFrame = ((mxCheckBox *) event->widget)->isChecked();
  1674. break;
  1675. case IDC_OVERLAY_WIREFRAME:
  1676. g_viewerSettings.overlayWireframe = ((mxCheckBox *) event->widget)->isChecked();
  1677. break;
  1678. case IDC_ATTACHMENTS:
  1679. g_viewerSettings.showAttachments = ((mxCheckBox *) event->widget)->isChecked();
  1680. break;
  1681. case IDC_SHOWORIGINAXIS:
  1682. setShowOriginAxis (((mxCheckBox *) event->widget)->isChecked());
  1683. break;
  1684. case IDC_MESSAGES:
  1685. {
  1686. int index = cMessageList->getSelectedIndex();
  1687. if (index >= 0)
  1688. {
  1689. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  1690. if ( pStudioR )
  1691. {
  1692. IMaterial *pMaterials[128];
  1693. g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  1694. cShaderUsed->removeAll();
  1695. if ( pMaterials[index]->IsErrorMaterial() )
  1696. {
  1697. cShaderUsed->add( "*** ERROR *** Can't load VMT");
  1698. }
  1699. else
  1700. {
  1701. cShaderUsed->add( pMaterials[index]->GetShaderName() );
  1702. }
  1703. }
  1704. }
  1705. }
  1706. break;
  1707. case IDC_SEQUENCE0:
  1708. case IDC_SEQUENCE1:
  1709. case IDC_SEQUENCE2:
  1710. case IDC_SEQUENCE3:
  1711. case IDC_SEQUENCE4:
  1712. {
  1713. int i = event->action - IDC_SEQUENCE0;
  1714. int index = ((mxChoice *) event->widget)->getSelectedIndex();
  1715. if (index >= 0)
  1716. {
  1717. index = iSelectionToSequence[index];
  1718. if (i == 0)
  1719. {
  1720. setSequence (index);
  1721. showActivityModifiers( index );
  1722. }
  1723. else
  1724. {
  1725. setOverlaySequence( i, index, slSequence[i]->getValue() );
  1726. }
  1727. }
  1728. }
  1729. break;
  1730. case IDC_SEQUENCESCALE0:
  1731. case IDC_SEQUENCESCALE1:
  1732. case IDC_SEQUENCESCALE2:
  1733. case IDC_SEQUENCESCALE3:
  1734. case IDC_SEQUENCESCALE4:
  1735. {
  1736. int i = event->action - IDC_SEQUENCESCALE0;
  1737. int index = cSequence[i]->getSelectedIndex();
  1738. if (index >= 0)
  1739. {
  1740. index = iSelectionToSequence[index];
  1741. if (i == 0)
  1742. {
  1743. setSequence (index);
  1744. showActivityModifiers( index );
  1745. }
  1746. else
  1747. {
  1748. setOverlaySequence( i, index, (float)((mxSlider *) event->widget)->getValue() );
  1749. }
  1750. }
  1751. }
  1752. break;
  1753. case IDC_FRAMESELECTION0:
  1754. case IDC_FRAMESELECTION1:
  1755. case IDC_FRAMESELECTION2:
  1756. case IDC_FRAMESELECTION3:
  1757. case IDC_FRAMESELECTION4:
  1758. {
  1759. updateFrameSelection();
  1760. }
  1761. break;
  1762. case IDC_BLENDTIME:
  1763. {
  1764. char sz[ 256 ];
  1765. sprintf( sz, "%.2f s", (float)((mxSlider *) event->widget)->getValue() );
  1766. g_pStudioModel->SetBlendTime( ((mxSlider *) event->widget)->getValue() );
  1767. laBlendTime->setLabel( sz );
  1768. }
  1769. break;
  1770. case IDC_BLENDSEQUENCECHANGES:
  1771. g_viewerSettings.blendSequenceChanges = ((mxCheckBox *) event->widget)->isChecked();
  1772. break;
  1773. case IDC_ANIMATEWEAPONS:
  1774. g_viewerSettings.animateWeapons = ((mxCheckBox *) event->widget)->isChecked();
  1775. break;
  1776. case IDC_BLENDNOW:
  1777. startBlending();
  1778. break;
  1779. case IDC_SPEEDSCALE:
  1780. {
  1781. setSpeedScale( ((mxSlider *) event->widget)->getValue() );
  1782. }
  1783. break;
  1784. case IDC_FORCEFRAME:
  1785. {
  1786. setFrame( ((mxSlider *) event->widget)->getValue() );
  1787. // stop the animation
  1788. setSpeedScale( 0 );
  1789. if ( g_bHlmvMaster && g_HlmvIpcClient.Connect() )
  1790. {
  1791. CUtlBuffer cmd;
  1792. CUtlBuffer res;
  1793. cmd.Printf( "%s %f", "hlmvForceFrame", reinterpret_cast< mxSlider * >( event->widget )->getValue() );
  1794. g_HlmvIpcClient.ExecuteCommand( cmd, res );
  1795. g_HlmvIpcClient.Disconnect();
  1796. }
  1797. }
  1798. break;
  1799. case IDC_BODYPART:
  1800. {
  1801. int index = cBodypart->getSelectedIndex();
  1802. if (index >= 0)
  1803. {
  1804. g_pStudioModel->SetBodygroup( cBodypart->getSelectedIndex() );
  1805. setBodypart (index);
  1806. }
  1807. }
  1808. break;
  1809. case IDC_SUBMODEL:
  1810. {
  1811. int index = cSubmodel->getSelectedIndex();
  1812. if (index >= 0)
  1813. {
  1814. setSubmodel (index);
  1815. }
  1816. }
  1817. break;
  1818. case IDC_CONTROLLER:
  1819. {
  1820. int index = cController->getSelectedIndex();
  1821. if (index >= 0)
  1822. setBoneController (index);
  1823. }
  1824. break;
  1825. case IDC_CONTROLLERVALUE:
  1826. {
  1827. int index = cController->getSelectedIndex();
  1828. if (index >= 0)
  1829. {
  1830. float flValue = slController->getValue();
  1831. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  1832. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
  1833. if (pbonecontroller->end < pbonecontroller->start)
  1834. {
  1835. flValue *= -1.0f;
  1836. }
  1837. setBoneControllerValue(index, flValue);
  1838. }
  1839. }
  1840. break;
  1841. case IDC_SKINS:
  1842. {
  1843. int index = cSkin->getSelectedIndex();
  1844. if (index >= 0)
  1845. {
  1846. g_pStudioModel->SetSkin (index);
  1847. g_viewerSettings.skin = index;
  1848. d_MatSysWindow->redraw();
  1849. }
  1850. }
  1851. break;
  1852. case IDC_MATERIALS:
  1853. {
  1854. int index = cMaterials->getSelectedIndex();
  1855. if (index >= 0)
  1856. {
  1857. g_viewerSettings.materialIndex = index;
  1858. }
  1859. }
  1860. break;
  1861. case IDC_IKRULE_CHAIN:
  1862. case IDC_IKRULE_CHOICE:
  1863. case IDC_IKRULE_RANGE_TOGGLE:
  1864. case IDC_IKRULE_RANGE_START:
  1865. case IDC_IKRULE_RANGE_PEAK:
  1866. case IDC_IKRULE_RANGE_TAIL:
  1867. case IDC_IKRULE_RANGE_END:
  1868. case IDC_IKRULE_CONTACT_TOGGLE:
  1869. case IDC_IKRULE_CONTACT_FRAME:
  1870. case IDC_IKRULE_USING:
  1871. UpdateIKRuleWindow();
  1872. break;
  1873. case IDC_IKRULE_TOUCH:
  1874. case IDC_IKRULE_ATTACHMENT:
  1875. BuildIKRuleQCString();
  1876. break;
  1877. case IDC_IKRULE_RANGE_START_NOW:
  1878. SetFrameString( leIKRangeStart, getFrameSelection() );
  1879. break;
  1880. case IDC_IKRULE_RANGE_PEAK_NOW:
  1881. SetFrameString( leIKRangePeak, getFrameSelection() );
  1882. break;
  1883. case IDC_IKRULE_RANGE_TAIL_NOW:
  1884. SetFrameString( leIKRangeTail, getFrameSelection() );
  1885. break;
  1886. case IDC_IKRULE_RANGE_END_NOW:
  1887. SetFrameString( leIKRangeEnd, getFrameSelection() );
  1888. break;
  1889. case IDC_IKRULE_CONTACT_FRAME_NOW:
  1890. SetFrameString( leIKContactFrame, getFrameSelection() );
  1891. break;
  1892. case IDC_IKRULE_QC_STRING:
  1893. // ignore edits to the qc text box
  1894. break;
  1895. case IDC_EVENT_SOUND_FRAME:
  1896. case IDC_EVENT_SOUND_NAME:
  1897. BuildEventQCString();
  1898. break;
  1899. case IDC_EVENT_SOUND_FRAME_NOW:
  1900. SetFrameString( leEventSoundFrame, getFrameSelection() );
  1901. break;
  1902. case IDC_EVENT_QC_STRING:
  1903. // ignore edits to the qc text box
  1904. break;
  1905. default:
  1906. {
  1907. if ( event->action == IDC_FLEXDEFAULTS )
  1908. {
  1909. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  1910. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  1911. {
  1912. g_pStudioModel->SetFlexController( i, 0 );
  1913. }
  1914. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  1915. {
  1916. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  1917. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  1918. }
  1919. }
  1920. else if ( event->action == IDC_FLEXRANDOM )
  1921. {
  1922. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  1923. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  1924. {
  1925. float r = rand() / float( VALVE_RAND_MAX );
  1926. g_pStudioModel->SetFlexController( i, r );
  1927. }
  1928. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  1929. {
  1930. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  1931. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  1932. }
  1933. }
  1934. else if ( event->action == IDC_FLEXZERO )
  1935. {
  1936. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  1937. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  1938. {
  1939. g_pStudioModel->SetFlexController( i, 0 );
  1940. }
  1941. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  1942. {
  1943. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  1944. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  1945. }
  1946. }
  1947. else if ( event->action == IDC_FLEXONE )
  1948. {
  1949. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  1950. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  1951. {
  1952. g_pStudioModel->SetFlexController( i, 1 );
  1953. }
  1954. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  1955. {
  1956. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  1957. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  1958. }
  1959. }
  1960. else if (event->action >= IDC_FLEX && event->action < IDC_FLEX + NUM_FLEX_SLIDERS)
  1961. {
  1962. int flex = (event->action - IDC_FLEX);
  1963. LocalFlexController_t index = (LocalFlexController_t)cFlex[flex]->getSelectedIndex();
  1964. if (index >= 0)
  1965. {
  1966. slFlexScale[flex]->setValue(g_pStudioModel->GetFlexControllerRaw(index));
  1967. }
  1968. }
  1969. else if (event->action >= IDC_FLEXSCALE && event->action < IDC_FLEXSCALE + NUM_FLEX_SLIDERS)
  1970. {
  1971. int flex = (event->action - IDC_FLEXSCALE);
  1972. LocalFlexController_t index = (LocalFlexController_t)cFlex[flex]->getSelectedIndex();
  1973. g_pStudioModel->SetFlexControllerRaw( index, ((mxSlider *) event->widget)->getValue() );
  1974. }
  1975. else if ( event->action >= IDC_PHYS_FIRST && event->action <= IDC_PHYS_LAST )
  1976. {
  1977. return handlePhysicsEvent( event );
  1978. }
  1979. else if (event->action >= IDC_POSEPARAMETER && event->action < IDC_POSEPARAMETER + NUM_POSEPARAMETERS)
  1980. {
  1981. int index = event->action - IDC_POSEPARAMETER;
  1982. int poseparam = cPoseParameter[index]->getSelectedIndex();
  1983. float flMin, flMax;
  1984. if (g_pStudioModel->GetPoseParameterRange( poseparam, &flMin, &flMax ))
  1985. {
  1986. slPoseParameter[index]->setRange( flMin, flMax, 1000 );
  1987. slPoseParameter[index]->setValue( g_pStudioModel->GetPoseParameter( poseparam ) );
  1988. lePoseParameter[index]->setLabel( "%.1f", g_pStudioModel->GetPoseParameter( poseparam ) );
  1989. }
  1990. }
  1991. else if (event->action >= IDC_POSEPARAMETER_SCALE && event->action < IDC_POSEPARAMETER_SCALE + NUM_POSEPARAMETERS)
  1992. {
  1993. int index = event->action - IDC_POSEPARAMETER_SCALE;
  1994. int poseparam = cPoseParameter[index]->getSelectedIndex();
  1995. setBlend( poseparam, ((mxSlider *) event->widget)->getValue() );
  1996. lePoseParameter[index]->setLabel( "%.1f", ((mxSlider *) event->widget)->getValue() );
  1997. }
  1998. }
  1999. break;
  2000. }
  2001. return 1;
  2002. }
  2003. void
  2004. ControlPanel::dumpModelInfo()
  2005. {
  2006. #if 0
  2007. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2008. if (hdr)
  2009. {
  2010. DeleteFile ("midump.txt");
  2011. FILE *file = fopen ("midump.txt", "wt");
  2012. if (file)
  2013. {
  2014. byte *phdr = (byte *) hdr;
  2015. int i;
  2016. fprintf (file, "id: %c%c%c%c\n", phdr[0], phdr[1], phdr[2], phdr[3]);
  2017. fprintf (file, "version: %d\n", hdr->version);
  2018. fprintf (file, "name: \"%s\"\n", hdr->name);
  2019. fprintf (file, "length: %d\n\n", hdr->length);
  2020. fprintf (file, "eyeposition: %f %f %f\n", hdr->eyeposition[0], hdr->eyeposition[1], hdr->eyeposition[2]);
  2021. fprintf (file, "min: %f %f %f\n", hdr->min[0], hdr->min[1], hdr->min[2]);
  2022. fprintf (file, "max: %f %f %f\n", hdr->max[0], hdr->max[1], hdr->max[2]);
  2023. fprintf (file, "bbmin: %f %f %f\n", hdr->bbmin[0], hdr->bbmin[1], hdr->bbmin[2]);
  2024. fprintf (file, "bbmax: %f %f %f\n", hdr->bbmax[0], hdr->bbmax[1], hdr->bbmax[2]);
  2025. fprintf (file, "flags: %d\n\n", hdr->flags);
  2026. fprintf (file, "numbones: %d\n", hdr->numbones);
  2027. for (i = 0; i < hdr->numbones; i++)
  2028. {
  2029. mstudiobone_t *pbones = (mstudiobone_t *) (phdr + hdr->boneindex);
  2030. fprintf (file, "\nbone %d.name: \"%s\"\n", i + 1, pbones[i].name);
  2031. fprintf (file, "bone %d.parent: %d\n", i + 1, pbones[i].parent);
  2032. fprintf (file, "bone %d.flags: %d\n", i + 1, pbones[i].flags);
  2033. fprintf (file, "bone %d.bonecontroller: %d %d %d %d %d %d\n", i + 1, pbones[i].bonecontroller[0], pbones[i].bonecontroller[1], pbones[i].bonecontroller[2], pbones[i].bonecontroller[3], pbones[i].bonecontroller[4], pbones[i].bonecontroller[5]);
  2034. fprintf (file, "bone %d.value: %f %f %f %f %f %f\n", i + 1, pbones[i].value[0], pbones[i].value[1], pbones[i].value[2], pbones[i].value[3], pbones[i].value[4], pbones[i].value[5]);
  2035. fprintf (file, "bone %d.scale: %f %f %f %f %f %f\n", i + 1, pbones[i].scale[0], pbones[i].scale[1], pbones[i].scale[2], pbones[i].scale[3], pbones[i].scale[4], pbones[i].scale[5]);
  2036. }
  2037. fprintf (file, "\nnumbonecontrollers: %d\n", hdr->numbonecontrollers);
  2038. for (i = 0; i < hdr->numbonecontrollers; i++)
  2039. {
  2040. mstudiobonecontroller_t *pbonecontrollers = (mstudiobonecontroller_t *) (phdr + hdr->bonecontrollerindex);
  2041. fprintf (file, "\nbonecontroller %d.bone: %d\n", i + 1, pbonecontrollers[i].bone);
  2042. fprintf (file, "bonecontroller %d.type: %d\n", i + 1, pbonecontrollers[i].type);
  2043. fprintf (file, "bonecontroller %d.start: %f\n", i + 1, pbonecontrollers[i].start);
  2044. fprintf (file, "bonecontroller %d.end: %f\n", i + 1, pbonecontrollers[i].end);
  2045. fprintf (file, "bonecontroller %d.rest: %d\n", i + 1, pbonecontrollers[i].rest);
  2046. fprintf (file, "bonecontroller %d.index: %d\n", i + 1, pbonecontrollers[i].index);
  2047. }
  2048. fprintf (file, "\nnumhitboxes: %d\n", hdr->numhitboxes);
  2049. for (i = 0; i < hdr->numhitboxes; i++)
  2050. {
  2051. mstudiobbox_t *pbboxes = (mstudiobbox_t *) (phdr + hdr->hitboxindex);
  2052. fprintf (file, "\nhitbox %d.bone: %d\n", i + 1, pbboxes[i].bone);
  2053. fprintf (file, "hitbox %d.group: %d\n", i + 1, pbboxes[i].group);
  2054. fprintf (file, "hitbox %d.bbmin: %f %f %f\n", i + 1, pbboxes[i].bbmin[0], pbboxes[i].bbmin[1], pbboxes[i].bbmin[2]);
  2055. fprintf (file, "hitbox %d.bbmax: %f %f %f\n", i + 1, pbboxes[i].bbmax[0], pbboxes[i].bbmax[1], pbboxes[i].bbmax[2]);
  2056. }
  2057. fprintf (file, "\nnumseq: %d\n", hdr->GetNumSeq());
  2058. for (i = 0; i < hdr->GetNumSeq(); i++)
  2059. {
  2060. mstudioseqdesc_t *pseqdescs = (mstudioseqdesc_t *) (phdr + hdr->seqindex);
  2061. fprintf (file, "\nseqdesc %d.label: \"%s\"\n", i + 1, pseqdescs[i].label);
  2062. fprintf (file, "seqdesc %d.fps: %f\n", i + 1, pseqdescs[i].fps);
  2063. fprintf (file, "seqdesc %d.flags: %d\n", i + 1, pseqdescs[i].flags);
  2064. fprintf (file, "<...>\n");
  2065. }
  2066. /*
  2067. fprintf (file, "\nnumseqgroups: %d\n", hdr->GetNumSeq()groups);
  2068. for (i = 0; i < hdr->GetNumSeq()groups; i++)
  2069. {
  2070. mstudioseqgroup_t *pseqgroups = (mstudioseqgroup_t *) (phdr + hdr->seqgroupindex);
  2071. fprintf (file, "\nseqgroup %d.label: \"%s\"\n", i + 1, pseqgroups[i].label);
  2072. fprintf (file, "\nseqgroup %d.namel: \"%s\"\n", i + 1, pseqgroups[i].name);
  2073. fprintf (file, "\nseqgroup %d.data: %d\n", i + 1, pseqgroups[i].data);
  2074. }
  2075. */
  2076. hdr = g_pStudioModel->getTextureHeader();
  2077. fprintf (file, "\nnumtextures: %d\n", hdr->numtextures);
  2078. fprintf (file, "textureindex: %d\n", hdr->textureindex);
  2079. fprintf (file, "texturedataindex: %d\n", hdr->texturedataindex);
  2080. for (i = 0; i < hdr->numtextures; i++)
  2081. {
  2082. mstudiotexture_t *ptextures = (mstudiotexture_t *) ((byte *) hdr + hdr->textureindex);
  2083. fprintf (file, "\ntexture %d.name: \"%s\"\n", i + 1, ptextures[i].name);
  2084. fprintf (file, "texture %d.flags: %d\n", i + 1, ptextures[i].flags);
  2085. fprintf (file, "texture %d.width: %d\n", i + 1, ptextures[i].width);
  2086. fprintf (file, "texture %d.height: %d\n", i + 1, ptextures[i].height);
  2087. fprintf (file, "texture %d.index: %d\n", i + 1, ptextures[i].index);
  2088. }
  2089. hdr = g_pStudioModel->GetStudioHdr();
  2090. fprintf (file, "\nnumskinref: %d\n", hdr->numskinref);
  2091. fprintf (file, "numskinfamilies: %d\n", hdr->numskinfamilies);
  2092. fprintf (file, "\nnumbodyparts: %d\n", hdr->numbodyparts);
  2093. for (i = 0; i < hdr->numbodyparts; i++)
  2094. {
  2095. mstudiobodyparts_t *pbodyparts = (mstudiobodyparts_t *) ((byte *) hdr + hdr->bodypartindex);
  2096. fprintf (file, "\nbodypart %d.name: \"%s\"\n", i + 1, pbodyparts[i].name);
  2097. fprintf (file, "bodypart %d.nummodels: %d\n", i + 1, pbodyparts[i].nummodels);
  2098. fprintf (file, "bodypart %d.base: %d\n", i + 1, pbodyparts[i].base);
  2099. fprintf (file, "bodypart %d.modelindex: %d\n", i + 1, pbodyparts[i].modelindex);
  2100. }
  2101. fprintf (file, "\nnumattachments: %d\n", hdr->numattachments);
  2102. for (i = 0; i < hdr->numattachments; i++)
  2103. {
  2104. mstudioattachment_t *pattachments = (mstudioattachment_t *) ((byte *) hdr + hdr->attachmentindex);
  2105. fprintf (file, "attachment %d.name: \"%s\"\n", i + 1, pattachments[i].name);
  2106. }
  2107. fclose (file);
  2108. ShellExecute ((HWND) getHandle(), "open", "midump.txt", 0, 0, SW_SHOW);
  2109. }
  2110. }
  2111. #endif
  2112. }
  2113. LoadModelResult_t ControlPanel::loadModel(const char *filename)
  2114. {
  2115. SaveViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
  2116. g_pStudioModel->FreeModel( false );
  2117. if (!g_pStudioModel->LoadModel( filename ))
  2118. {
  2119. return LoadModel_LoadFail;
  2120. }
  2121. if (!g_pStudioModel->PostLoadModel( filename ))
  2122. {
  2123. return LoadModel_PostLoadFail;
  2124. }
  2125. if (!g_pStudioModel->HasModel())
  2126. {
  2127. return LoadModel_NoModel;
  2128. }
  2129. OnLoadModel( );
  2130. return LoadModel_Success;
  2131. }
  2132. void ControlPanel::OnLoadModel( void )
  2133. {
  2134. int i;
  2135. m_bVMTInfoLoaded = false;
  2136. if (!g_pStudioModel->HasModel())
  2137. return;
  2138. initSequenceChoices();
  2139. initBodypartChoices();
  2140. initBoneControllers();
  2141. initSkinChoices();
  2142. initMaterialChoices();
  2143. initPhysicsBones();
  2144. initLODs();
  2145. initFlexes();
  2146. setModelInfo();
  2147. UnloadAllMergedModels();
  2148. const bool bNoModelSettings = LoadViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
  2149. if ( !bNoModelSettings )
  2150. {
  2151. InitViewerSettings( "hlmv" );
  2152. setSequence( 0 );
  2153. showActivityModifiers( 0 );
  2154. setSpeedScale( 1.0 );
  2155. }
  2156. resetControlPanel();
  2157. /*!!
  2158. for (i = 0; i < 32; i++)
  2159. g_viewerSettings.submodels[i] = 0;
  2160. for (i = 0; i < 8; i++)
  2161. g_viewerSettings.controllers[i] = 0;
  2162. */
  2163. setupPhysics();
  2164. m_pBoneWindow->OnLoadModel();
  2165. m_pAttachmentsWindow->OnLoadModel();
  2166. PopulateBoneList( cIKTouch, true );
  2167. mx_setcwd (mx_getpath (g_pStudioModel->GetFileName()));
  2168. for ( i = 0; i < HLMV_MAX_MERGED_MODELS; ++i )
  2169. {
  2170. if ( strlen( g_viewerSettings.mergeModelFile[i] ) != 0 )
  2171. {
  2172. loadModel( g_viewerSettings.mergeModelFile[i], i );
  2173. }
  2174. }
  2175. // Center the model if we don't have last view position data in the registry
  2176. if ( !bNoModelSettings )
  2177. {
  2178. // Need to call this twice for some reason. Really - I don't have OCD!
  2179. centerView();
  2180. centerView();
  2181. }
  2182. }
  2183. LoadModelResult_t ControlPanel::loadModel(const char *filename, int slot )
  2184. {
  2185. if (slot == -1)
  2186. {
  2187. return loadModel( filename );
  2188. }
  2189. if (g_pStudioExtraModel[slot] == NULL)
  2190. {
  2191. g_pStudioExtraModel[slot] = new StudioModel;
  2192. }
  2193. else
  2194. {
  2195. g_pStudioExtraModel[slot]->FreeModel( false );
  2196. }
  2197. if (g_pStudioExtraModel[slot]->LoadModel( filename ))
  2198. {
  2199. if (g_pStudioExtraModel[slot]->PostLoadModel( filename ))
  2200. {
  2201. connectFlexes( g_pStudioExtraModel[slot]->GetStudioHdr() );
  2202. if ( g_MDLViewer && g_MDLViewer->getMenuBar() )
  2203. {
  2204. g_MDLViewer->getMenuBar()->modify (IDC_FILE_UNLOADMERGEDMODEL1 + slot, IDC_FILE_UNLOADMERGEDMODEL1 + slot, filename);
  2205. g_MDLViewer->getMenuBar()->setEnabled (IDC_FILE_UNLOADMERGEDMODEL1 + slot, true);
  2206. }
  2207. return LoadModel_Success;
  2208. }
  2209. else
  2210. {
  2211. return LoadModel_PostLoadFail;
  2212. }
  2213. }
  2214. return LoadModel_LoadFail;
  2215. }
  2216. void
  2217. ControlPanel::resetControlPanel( void )
  2218. {
  2219. setSequence( g_pStudioModel->GetSequence() );
  2220. showActivityModifiers( g_pStudioModel->GetSequence() );
  2221. setOverlaySequence( 1, g_pStudioModel->GetOverlaySequence( 0 ), g_pStudioModel->GetOverlaySequenceWeight( 0 ) );
  2222. setOverlaySequence( 2, g_pStudioModel->GetOverlaySequence( 1 ), g_pStudioModel->GetOverlaySequenceWeight( 1 ) );
  2223. setOverlaySequence( 3, g_pStudioModel->GetOverlaySequence( 2 ), g_pStudioModel->GetOverlaySequenceWeight( 2 ) );
  2224. setOverlaySequence( 4, g_pStudioModel->GetOverlaySequence( 3 ), g_pStudioModel->GetOverlaySequenceWeight( 3 ) );
  2225. setSpeedScale( g_viewerSettings.speedScale );
  2226. cbGround->setChecked( g_viewerSettings.showGround );
  2227. cbMovement->setChecked( g_viewerSettings.showMovement );
  2228. cbShadow->setChecked( g_viewerSettings.showShadow );
  2229. cbNormalMap->setChecked( g_viewerSettings.enableNormalMapping );
  2230. cbIllumPosition->setChecked( g_viewerSettings.showIllumPosition );
  2231. cbHitBoxes->setChecked( g_viewerSettings.showHitBoxes );
  2232. cbBones->setChecked( g_viewerSettings.showBones );
  2233. cbPlaySounds->setChecked( g_viewerSettings.playSounds );
  2234. cbSequenceBoxes->setChecked( g_viewerSettings.showSequenceBoxes );
  2235. cbRunIK->setChecked( g_viewerSettings.enableIK );
  2236. cbBackground->setChecked( g_viewerSettings.showBackground );
  2237. cbSoftwareSkin->setChecked( g_viewerSettings.softwareSkin );
  2238. cbOverbright2->setChecked( g_viewerSettings.overbright );
  2239. cbAttachments->setChecked( g_viewerSettings.showAttachments );
  2240. cbNormals->setChecked( g_viewerSettings.showNormals );
  2241. cbEnableHead->setChecked( g_pStudioModel->GetSolveHeadTurn() ? 1 : 0 );
  2242. cbShowOriginAxis->setChecked( g_viewerSettings.showOriginAxis );
  2243. setOriginAxisLength( g_viewerSettings.originAxisLength );
  2244. }
  2245. void
  2246. ControlPanel::setRenderMode (int mode)
  2247. {
  2248. g_viewerSettings.renderMode = mode;
  2249. d_MatSysWindow->redraw();
  2250. }
  2251. void
  2252. ControlPanel::setHighlightBone( int index )
  2253. {
  2254. if ( index >= 0 )
  2255. {
  2256. g_viewerSettings.highlightPhysicsBone = index;
  2257. }
  2258. }
  2259. void
  2260. ControlPanel::setLOD( int index, bool setLODchoice, bool force )
  2261. {
  2262. #if 1
  2263. if( !force && ( g_viewerSettings.lod == index ) )
  2264. {
  2265. return;
  2266. }
  2267. #endif
  2268. g_viewerSettings.lod = index;
  2269. float lodSwitch = g_pStudioModel->GetLODSwitchValue( index );
  2270. char tmp[128];
  2271. sprintf( tmp, "%0.0f", lodSwitch );
  2272. leLODSwitch->setLabel( tmp );
  2273. HWND wnd = ( HWND )leLODSwitch->getHandle();
  2274. if( setLODchoice )
  2275. {
  2276. cLODChoice->select( index );
  2277. }
  2278. setModelInfo();
  2279. InvalidateRect( wnd, NULL, TRUE );
  2280. UpdateWindow( wnd );
  2281. }
  2282. void
  2283. ControlPanel::setLODMetric( float metric )
  2284. {
  2285. static int saveMetric = -10;
  2286. int intMetric = ( int )metric;
  2287. if( intMetric == saveMetric )
  2288. {
  2289. return;
  2290. }
  2291. saveMetric = intMetric;
  2292. char tmp[128];
  2293. sprintf( tmp, "%d", intMetric );
  2294. lLODMetric->setLabel( tmp );
  2295. }
  2296. void
  2297. ControlPanel::setPolycount( int polycount )
  2298. {
  2299. static int savePolycount = -10;
  2300. if( polycount == savePolycount )
  2301. {
  2302. return;
  2303. }
  2304. savePolycount = polycount;
  2305. char tmp[128];
  2306. sprintf( tmp, "Shader Draw Count: %d", polycount );
  2307. lModelInfo3->setLabel( tmp );
  2308. }
  2309. void ControlPanel::setModelInfo( int nVertCount, int nIndexCount, int nTriCount )
  2310. {
  2311. static int nSaveVertCount = -10;
  2312. static int nSaveIndexCount = -10;
  2313. static int nSaveTriCount = -10;
  2314. if ( nVertCount == nSaveVertCount && nIndexCount == nSaveIndexCount && nTriCount == nSaveTriCount )
  2315. {
  2316. return;
  2317. }
  2318. nSaveVertCount = nVertCount;
  2319. nSaveIndexCount = nIndexCount;
  2320. nSaveTriCount = nTriCount;
  2321. char tmp[ 128 ];
  2322. sprintf( tmp, "Verts: %d Indexes: %d Triangles: %d", nVertCount, nIndexCount, nTriCount );
  2323. lModelInfo4->setLabel( tmp );
  2324. }
  2325. void
  2326. ControlPanel::setTransparent( bool isTransparent )
  2327. {
  2328. static int saveTransparent = -1;
  2329. if( (int)isTransparent == saveTransparent )
  2330. return;
  2331. saveTransparent = isTransparent;
  2332. char tmp[128];
  2333. sprintf( tmp, "Model is: %s", isTransparent ? "transparent" : "opaque" );
  2334. lModelInfo5->setLabel( tmp );
  2335. }
  2336. void
  2337. ControlPanel::updatePoseParameters( )
  2338. {
  2339. for (int i = 0; i < NUM_POSEPARAMETERS; i++)
  2340. {
  2341. if (slPoseParameter[i]->isEnabled())
  2342. {
  2343. int j = cPoseParameter[i]->getSelectedIndex();
  2344. float value = g_pStudioModel->GetPoseParameter( j );
  2345. float temp = atof( lePoseParameter[i]->getLabel( ) );
  2346. if (fabs( temp - value ) > 0.1)
  2347. {
  2348. slPoseParameter[i]->setValue( value );
  2349. lePoseParameter[i]->setLabel( "%.1f", value );
  2350. }
  2351. }
  2352. }
  2353. }
  2354. void
  2355. ControlPanel::setShowGround (bool b)
  2356. {
  2357. g_viewerSettings.showGround = b;
  2358. cbGround->setChecked (b);
  2359. }
  2360. void
  2361. ControlPanel::setAutoLOD( bool b )
  2362. {
  2363. g_viewerSettings.autoLOD = b;
  2364. cbAutoLOD->setChecked( b );
  2365. }
  2366. void
  2367. ControlPanel::setSoftwareSkin( bool b )
  2368. {
  2369. g_viewerSettings.softwareSkin = b;
  2370. cbSoftwareSkin->setChecked( b );
  2371. }
  2372. void
  2373. ControlPanel::setOverbright( bool b )
  2374. {
  2375. g_viewerSettings.overbright = b;
  2376. cbOverbright2->setChecked( b );
  2377. }
  2378. void
  2379. ControlPanel::setShowMovement (bool b)
  2380. {
  2381. g_viewerSettings.showMovement = b;
  2382. cbMovement->setChecked (b);
  2383. }
  2384. void
  2385. ControlPanel::setShowBackground (bool b)
  2386. {
  2387. g_viewerSettings.showBackground = b;
  2388. cbBackground->setChecked (b);
  2389. }
  2390. void
  2391. ControlPanel::setShowNormals (bool b)
  2392. {
  2393. g_viewerSettings.showNormals = b;
  2394. cbNormals->setChecked (b);
  2395. }
  2396. void
  2397. ControlPanel::setShowTangentFrame (bool b)
  2398. {
  2399. g_viewerSettings.showTangentFrame = b;
  2400. cbTangentFrame->setChecked (b);
  2401. }
  2402. void
  2403. ControlPanel::setOverlayWireframe (bool b)
  2404. {
  2405. g_viewerSettings.overlayWireframe = b;
  2406. cbOverlayWireframe->setChecked (b);
  2407. }
  2408. void
  2409. ControlPanel::setShowShadow (bool b)
  2410. {
  2411. g_viewerSettings.showShadow = b;
  2412. cbShadow->setChecked (b);
  2413. }
  2414. void
  2415. ControlPanel::setShowHitBoxes (bool b)
  2416. {
  2417. g_viewerSettings.showHitBoxes = b;
  2418. cbHitBoxes->setChecked (b);
  2419. }
  2420. void
  2421. ControlPanel::setShowBones (bool b)
  2422. {
  2423. g_viewerSettings.showBones = b;
  2424. cbBones->setChecked (b);
  2425. }
  2426. void
  2427. ControlPanel::setShowAttachments (bool b)
  2428. {
  2429. g_viewerSettings.showAttachments = b;
  2430. cbAttachments->setChecked (b);
  2431. }
  2432. void
  2433. ControlPanel::setPlaySounds (bool b)
  2434. {
  2435. g_viewerSettings.playSounds = b;
  2436. cbPlaySounds->setChecked (b);
  2437. }
  2438. void
  2439. ControlPanel::setShowOriginAxis (bool b)
  2440. {
  2441. g_viewerSettings.showOriginAxis = b;
  2442. cbShowOriginAxis->setChecked (b);
  2443. }
  2444. struct SortInfo_t
  2445. {
  2446. int m_nSequence;
  2447. const char *m_pName;
  2448. int m_nType;
  2449. };
  2450. int SortSequenceFunc( const void *p1, const void *p2 )
  2451. {
  2452. const SortInfo_t* pSort1 = (const SortInfo_t*)p1;
  2453. const SortInfo_t* pSort2 = (const SortInfo_t*)p2;
  2454. if ( pSort1->m_nType < pSort2->m_nType )
  2455. return -10000;
  2456. if ( pSort1->m_nType > pSort2->m_nType )
  2457. return 10000;
  2458. return Q_stricmp( pSort1->m_pName, pSort2->m_pName );
  2459. }
  2460. void ControlPanel::CreateSortedSequenceList( CStudioHdr* hdr, int *pSequence )
  2461. {
  2462. int nSequenceCount = hdr->GetNumSeq();
  2463. SortInfo_t *pSort = (SortInfo_t*)_alloca( nSequenceCount * sizeof(SortInfo_t) );
  2464. // Set up sort info
  2465. for ( int j = 0; j < nSequenceCount; j++ )
  2466. {
  2467. pSort[j].m_nSequence = j;
  2468. if ( g_viewerSettings.showActivities )
  2469. {
  2470. pSort[j].m_pName = hdr->pSeqdesc(j).pszActivityName();
  2471. }
  2472. else
  2473. {
  2474. pSort[j].m_pName = hdr->pSeqdesc(j).pszLabel();
  2475. }
  2476. pSort[j].m_nType = 0;
  2477. const char *pKeyValuesText = Studio_GetKeyValueText( hdr, j );
  2478. if ( !pKeyValuesText )
  2479. continue;
  2480. KeyValues *pKeyValues = new KeyValues( "sort" );
  2481. if ( pKeyValues->LoadFromBuffer( "mdl", pKeyValuesText ) )
  2482. {
  2483. KeyValues *pFacePoserKeys = pKeyValues->FindKey( "faceposer" );
  2484. if ( pFacePoserKeys )
  2485. {
  2486. const char *pType = pFacePoserKeys->GetString( "type", "" );
  2487. if ( !Q_stricmp( pType, "posture" ) )
  2488. {
  2489. pSort[j].m_nType = 2;
  2490. }
  2491. else if ( !Q_stricmp( pType, "gesture" ) )
  2492. {
  2493. pSort[j].m_nType = 1;
  2494. }
  2495. }
  2496. }
  2497. pKeyValues->deleteThis();
  2498. }
  2499. if ( !CommandLine()->CheckParm( "-nosort" ) )
  2500. {
  2501. qsort( pSort, nSequenceCount, sizeof(SortInfo_t), SortSequenceFunc );
  2502. }
  2503. for ( int i = 0; i < nSequenceCount; ++i )
  2504. {
  2505. pSequence[i] = pSort[i].m_nSequence;
  2506. }
  2507. }
  2508. void ControlPanel::initSequenceChoices()
  2509. {
  2510. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2511. if (hdr)
  2512. {
  2513. int nSequenceCount = hdr->GetNumSeq();
  2514. int *pSequence = (int*)_alloca( nSequenceCount * sizeof(int) );
  2515. CreateSortedSequenceList( hdr, pSequence );
  2516. if (iSelectionToSequence)
  2517. {
  2518. free( iSelectionToSequence );
  2519. }
  2520. iSelectionToSequence = (int*)malloc( nSequenceCount * sizeof(int) );
  2521. if (iSequenceToSelection)
  2522. {
  2523. free( iSequenceToSelection );
  2524. }
  2525. iSequenceToSelection = (int*)malloc( nSequenceCount * sizeof(int) );
  2526. for (int i = 0; i < MAX_SEQUENCES; i++)
  2527. {
  2528. cSequence[i]->removeAll();
  2529. int k = 0;
  2530. for (int j = 0; j < nSequenceCount; j++)
  2531. {
  2532. int nSequence = pSequence[j];
  2533. if (g_viewerSettings.showHidden || !(hdr->pSeqdesc(nSequence).flags & STUDIO_HIDDEN))
  2534. {
  2535. if (g_viewerSettings.showActivities)
  2536. {
  2537. cSequence[i]->add( hdr->pSeqdesc(nSequence).pszActivityName() );
  2538. }
  2539. else
  2540. {
  2541. cSequence[i]->add( hdr->pSeqdesc(nSequence).pszLabel() );
  2542. }
  2543. iSelectionToSequence[k] = nSequence;
  2544. iSequenceToSelection[nSequence] = k;
  2545. k++;
  2546. }
  2547. else
  2548. {
  2549. // previous valid selection
  2550. iSequenceToSelection[nSequence] = (k > 0) ? (k - 1) : 0;
  2551. }
  2552. }
  2553. cSequence[i]->select( 0 );
  2554. slSequence[i]->setValue( 0 );
  2555. }
  2556. }
  2557. float flMin, flMax;
  2558. for (int i = 0; i < NUM_POSEPARAMETERS; i++)
  2559. {
  2560. if (g_pStudioModel->GetPoseParameterRange( i, &flMin, &flMax ))
  2561. {
  2562. cPoseParameter[i]->removeAll();
  2563. for (int j = 0; j < hdr->GetNumPoseParameters(); j++)
  2564. {
  2565. cPoseParameter[i]->add( hdr->pPoseParameter(j).pszName() );
  2566. }
  2567. cPoseParameter[i]->select( i );
  2568. cPoseParameter[i]->setEnabled( true );
  2569. cPoseParameter[i]->setVisible( true );
  2570. slPoseParameter[i]->setEnabled( true );
  2571. slPoseParameter[i]->setRange( flMin, flMax, 1000 );
  2572. mxToolTip::add (slPoseParameter[i], hdr->pPoseParameter(i).pszName() );
  2573. slPoseParameter[i]->setVisible( true );
  2574. lePoseParameter[i]->setVisible( true );
  2575. lePoseParameter[i]->setLabel( "%.1f", 0.0 );
  2576. }
  2577. else
  2578. {
  2579. cPoseParameter[i]->setEnabled( false );
  2580. cPoseParameter[i]->setVisible( false );
  2581. slPoseParameter[i]->setEnabled( false );
  2582. slPoseParameter[i]->setVisible( false );
  2583. lePoseParameter[i]->setVisible( false );
  2584. }
  2585. slPoseParameter[i]->setValue( 0.0 );
  2586. setBlend( i, 0.0 );
  2587. }
  2588. if ( hdr )
  2589. {
  2590. for (int i = 0; i < hdr->GetNumPoseParameters(); i++)
  2591. {
  2592. setBlend( i, 0.0 );
  2593. }
  2594. }
  2595. }
  2596. void ControlPanel::setSequence(int index)
  2597. {
  2598. cSequence[0]->select( iSequenceToSelection[index] );
  2599. g_pStudioModel->SetSequence(index);
  2600. updateFrameSelection();
  2601. updateGroundSpeed();
  2602. }
  2603. void ControlPanel::updateGroundSpeed( void )
  2604. {
  2605. char sz[100];
  2606. float flGroundSpeed = g_pStudioModel->GetCurrentVelocity();
  2607. sprintf( sz, "Speed: %.2f", flGroundSpeed );
  2608. laGroundSpeed->setLabel( sz );
  2609. }
  2610. void
  2611. ControlPanel::setOverlaySequence(int num, int index, float weight)
  2612. {
  2613. cSequence[num]->select( iSequenceToSelection[index] );
  2614. g_pStudioModel->SetOverlaySequence( num-1, index, weight );
  2615. slSequence[num]->setValue( weight );
  2616. updateFrameSelection();
  2617. }
  2618. void ControlPanel::startBlending( void )
  2619. {
  2620. g_pStudioModel->StartBlending();
  2621. }
  2622. void ControlPanel::updateTransitionAmount( void )
  2623. {
  2624. char sz[ 256 ];
  2625. sprintf( sz, "%.3f %%", 100.0f * g_pStudioModel->GetTransitionAmount() );
  2626. laBlendAmount->setLabel( sz );
  2627. }
  2628. int ControlPanel::getFrameSelection( void )
  2629. {
  2630. for ( int i = 0; i < MAX_SEQUENCES; i++ )
  2631. if ( rbFrameSelection[i]->isChecked() )
  2632. return i;
  2633. return 0;
  2634. }
  2635. void ControlPanel::setFrame( float frame )
  2636. {
  2637. int iLayer = getFrameSelection();
  2638. int iFrame = g_pStudioModel->SetFrame( iLayer, frame );
  2639. char buf[128];
  2640. sprintf(buf, "%3d", iFrame );
  2641. lForcedFrame->setLabel( buf );
  2642. }
  2643. void ControlPanel::updateFrameSelection( void )
  2644. {
  2645. int iLayer = getFrameSelection();
  2646. int maxFrame = g_pStudioModel->GetMaxFrame( iLayer );
  2647. slForceFrame->setRange( 0, maxFrame, maxFrame );
  2648. slForceFrame->setSteps(1,1);
  2649. }
  2650. void ControlPanel::updateFrameSlider( void )
  2651. {
  2652. int iLayer = getFrameSelection();
  2653. float flFrame = g_pStudioModel->GetFrame( iLayer );
  2654. char buf[128];
  2655. sprintf(buf, "%3.1f", flFrame );
  2656. lForcedFrame->setLabel( buf );
  2657. slForceFrame->setValue( flFrame );
  2658. }
  2659. void ControlPanel::setSpeedScale( float scale )
  2660. {
  2661. slSpeedScale->setValue( scale );
  2662. g_viewerSettings.speedScale = scale;
  2663. updateSpeedScale( );
  2664. }
  2665. void ControlPanel::updateSpeedScale( void )
  2666. {
  2667. char szFPS[32];
  2668. sprintf( szFPS, "x %.2f = %.1f fps", g_viewerSettings.speedScale, g_viewerSettings.speedScale * g_pStudioModel->GetFPS( ) );
  2669. laFPS->setLabel( szFPS );
  2670. }
  2671. void ControlPanel::setBlend(int index, float value )
  2672. {
  2673. g_pStudioModel->SetPoseParameter( index, value );
  2674. // reset number of frames....
  2675. updateFrameSelection( );
  2676. updateGroundSpeed( );
  2677. }
  2678. void
  2679. ControlPanel::initBodypartChoices()
  2680. {
  2681. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2682. if (hdr)
  2683. {
  2684. int i;
  2685. mstudiobodyparts_t *pbodyparts = hdr->pBodypart(0);
  2686. cBodypart->removeAll();
  2687. if (hdr->numbodyparts() > 0)
  2688. {
  2689. for (i = 0; i < hdr->numbodyparts(); i++)
  2690. cBodypart->add (pbodyparts[i].pszName());
  2691. cBodypart->select (0);
  2692. cSubmodel->removeAll();
  2693. for (i = 0; i < pbodyparts[0].nummodels; i++)
  2694. {
  2695. char str[64];
  2696. sprintf (str, "Submodel %d", i );
  2697. cSubmodel->add (str);
  2698. }
  2699. cSubmodel->select (0);
  2700. }
  2701. }
  2702. }
  2703. void
  2704. ControlPanel::setBodypart (int index)
  2705. {
  2706. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2707. if (hdr)
  2708. {
  2709. //cBodypart->setEn
  2710. cBodypart->select (index);
  2711. if (index < hdr->numbodyparts())
  2712. {
  2713. mstudiobodyparts_t *pbodyparts = hdr->pBodypart(0);
  2714. cSubmodel->removeAll();
  2715. for (int i = 0; i < pbodyparts[index].nummodels; i++)
  2716. {
  2717. char str[64];
  2718. sprintf (str, "Submodel %d", i );
  2719. cSubmodel->add (str);
  2720. }
  2721. cSubmodel->select (0);
  2722. //g_pStudioModel->SetBodygroup (index, 0);
  2723. }
  2724. }
  2725. setModelInfo();
  2726. }
  2727. void
  2728. ControlPanel::setSubmodel (int index)
  2729. {
  2730. g_pStudioModel->SetBodygroup (cBodypart->getSelectedIndex(), index);
  2731. //!!g_viewerSettings.submodels[cBodypart->getSelectedIndex()] = index;
  2732. setModelInfo();
  2733. }
  2734. void
  2735. ControlPanel::initPhysicsBones()
  2736. {
  2737. cHighlightBone->removeAll();
  2738. cHighlightBone->add( "None" );
  2739. for ( int i = 0; i < g_pStudioModel->Physics_GetBoneCount(); i++ )
  2740. {
  2741. cHighlightBone->add (g_pStudioModel->Physics_GetBoneName( i ) );
  2742. }
  2743. cHighlightBone->select (0);
  2744. }
  2745. void
  2746. ControlPanel::initLODs()
  2747. {
  2748. cLODChoice->removeAll();
  2749. for ( int i = 0; i < g_pStudioModel->GetNumLODs(); i++ )
  2750. {
  2751. char tmp[10];
  2752. sprintf( tmp, "%d", i );
  2753. cLODChoice->add( tmp );
  2754. }
  2755. setLOD( 0, true, true );
  2756. }
  2757. void
  2758. ControlPanel::initBoneControllers()
  2759. {
  2760. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2761. if (hdr)
  2762. {
  2763. cController->setEnabled (hdr->numbonecontrollers() > 0);
  2764. slController->setEnabled (hdr->numbonecontrollers() > 0);
  2765. cController->removeAll();
  2766. int i = 0;
  2767. for (i; i < hdr->numbonecontrollers(); i++)
  2768. {
  2769. char str[32];
  2770. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(i);
  2771. sprintf (str, "Controller %d", pbonecontroller->inputfield);
  2772. cController->add (str);
  2773. }
  2774. if (hdr->numbonecontrollers() > 0)
  2775. {
  2776. cController->select (0);
  2777. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(0);
  2778. slController->setRange (pbonecontroller->start, pbonecontroller->end);
  2779. slController->setValue (0);
  2780. }
  2781. }
  2782. }
  2783. void
  2784. ControlPanel::setBoneController (int index)
  2785. {
  2786. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2787. if (hdr)
  2788. {
  2789. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
  2790. slController->setRange ( pbonecontroller->start, pbonecontroller->end);
  2791. slController->setValue (0);
  2792. }
  2793. }
  2794. void
  2795. ControlPanel::setBoneControllerValue (int index, float value)
  2796. {
  2797. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2798. if (hdr)
  2799. {
  2800. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
  2801. g_pStudioModel->SetController (pbonecontroller->inputfield, value);
  2802. }
  2803. }
  2804. void
  2805. ControlPanel::initSkinChoices()
  2806. {
  2807. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2808. if (hdr)
  2809. {
  2810. cSkin->setEnabled (hdr->numskinfamilies() > 0);
  2811. cSkin->removeAll();
  2812. for (int i = 0; i < hdr->numskinfamilies(); i++)
  2813. {
  2814. char str[32];
  2815. sprintf (str, "Skin %d", i );
  2816. cSkin->add (str);
  2817. }
  2818. cSkin->select (0);
  2819. g_pStudioModel->SetSkin (0);
  2820. g_viewerSettings.skin = 0;
  2821. }
  2822. }
  2823. void ControlPanel::initMaterialChoices()
  2824. {
  2825. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2826. if (hdr)
  2827. {
  2828. const studiohdr_t *pStudioHdr = hdr->GetRenderHdr();
  2829. if (pStudioHdr)
  2830. {
  2831. cMaterials->setEnabled(pStudioHdr->numtextures > 0);
  2832. cMaterials->removeAll();
  2833. for (int i = 0; i < pStudioHdr->numtextures; i++)
  2834. {
  2835. char str[512];
  2836. sprintf (str, "%s", pStudioHdr->pTexture(i)->pszName() );
  2837. cMaterials->add (str);
  2838. }
  2839. cMaterials->select (0);
  2840. g_viewerSettings.materialIndex = 0;
  2841. }
  2842. }
  2843. }
  2844. void ControlPanel::showActivityModifiers( int sequence )
  2845. {
  2846. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2847. if ( !hdr->SequencesAvailable() )
  2848. return;
  2849. if ( sequence < 0 || sequence >= hdr->GetNumSeq() )
  2850. return;
  2851. mstudioseqdesc_t &desc = hdr->pSeqdesc( sequence );
  2852. cActivityModifiers->setEnabled( desc.numactivitymodifiers > 0);
  2853. cActivityModifiers->removeAll();
  2854. for (int i = 0; i < desc.numactivitymodifiers; i++)
  2855. {
  2856. char str[512];
  2857. sprintf (str, "%s", desc.pActivityModifier( i )->pszName() );
  2858. cActivityModifiers->add (str);
  2859. }
  2860. cActivityModifiers->select (0);
  2861. }
  2862. void
  2863. ControlPanel::setModelInfo()
  2864. {
  2865. static char str[2048];
  2866. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  2867. if (!hdr)
  2868. return;
  2869. static int checkSum = 0;
  2870. static int boneLODCount = 0;
  2871. static int numBatches = 0;
  2872. if ( g_pStudioModel && !m_bVMTInfoLoaded )
  2873. {
  2874. UpdateMaterialList();
  2875. }
  2876. if( checkSum == hdr->GetRenderHdr()->checksum && boneLODCount == g_DrawModelResults.m_NumHardwareBones && numBatches == g_DrawModelResults.m_NumBatches)
  2877. {
  2878. return;
  2879. }
  2880. checkSum = hdr->GetRenderHdr()->checksum;
  2881. boneLODCount = g_DrawModelResults.m_NumHardwareBones;
  2882. numBatches = g_DrawModelResults.m_NumBatches;
  2883. int hbcount = 0;
  2884. for ( int s = 0; s < hdr->numhitboxsets(); s++ )
  2885. {
  2886. hbcount += hdr->iHitboxCount( s );
  2887. }
  2888. sprintf (str,
  2889. "Total bones: %d\n"
  2890. "HW Bones: %d\n"
  2891. "Batches: %d\n"
  2892. "Bone Controllers: %d\n"
  2893. "Hit Boxes: %d in %d sets\n"
  2894. "Sequences: %d\n",
  2895. hdr->numbones(),
  2896. boneLODCount,
  2897. numBatches,
  2898. hdr->numbonecontrollers(),
  2899. hbcount,
  2900. hdr->numhitboxsets(),
  2901. hdr->GetNumSeq()
  2902. );
  2903. lModelInfo1->setLabel (str);
  2904. sprintf (str,
  2905. "Materials: %d\n"
  2906. "Skin Families: %d\n"
  2907. "Bodyparts: %d\n"
  2908. "Attachments: %d\n",
  2909. g_DrawModelResults.m_NumMaterials,
  2910. hdr->numskinfamilies(),
  2911. hdr->numbodyparts(),
  2912. hdr->GetNumAttachments());
  2913. lModelInfo2->setLabel (str);
  2914. }
  2915. void ControlPanel::UpdateMaterialList( )
  2916. {
  2917. cMessageList->removeAll();
  2918. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2919. if ( pStudioR )
  2920. {
  2921. IMaterial *pMaterials[128];
  2922. int nMaterials = g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  2923. for ( int i = 0; i < nMaterials; i++ )
  2924. {
  2925. char c_MaterialLine[256];
  2926. Q_strcpy( c_MaterialLine, "" );
  2927. if ( pMaterials[i]->IsErrorMaterial() )
  2928. {
  2929. Q_strcat( c_MaterialLine, "*** ERROR *** Model attempted to load one or more VMTs it can't find." , sizeof( c_MaterialLine ) );
  2930. }
  2931. else
  2932. {
  2933. Q_strcat( c_MaterialLine, pMaterials[i]->GetName() , sizeof( c_MaterialLine ) );
  2934. }
  2935. cMessageList->add( c_MaterialLine );
  2936. }
  2937. m_bVMTInfoLoaded = true;
  2938. }
  2939. }
  2940. extern matrix3x4_t g_viewtransform;
  2941. void ControlPanel::centerView( )
  2942. {
  2943. Vector min, max;
  2944. int hitboxset = 0; //g_MDLViewer->GetCurrentHitboxSet();
  2945. min.Init( 999999,999999,999999);
  2946. max.Init( -999999,-999999,-999999);
  2947. matrix3x4_t rootxform;
  2948. MatrixInvert( g_viewtransform, rootxform );
  2949. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ hitboxset ].m_Hitboxes;
  2950. for (unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) )
  2951. {
  2952. mstudiobbox_t *pBBox = &list[j].m_BBox;
  2953. Vector tmpmin, tmpmax;
  2954. matrix3x4_t bonesetup;
  2955. ConcatTransforms( rootxform, *g_pStudioModel->BoneToWorld( pBBox->bone ), bonesetup );
  2956. TransformAABB( bonesetup, pBBox->bbmin, pBBox->bbmax, tmpmin, tmpmax );
  2957. if (tmpmin.x < min.x) min.x = tmpmin.x;
  2958. if (tmpmin.y < min.y) min.y = tmpmin.y;
  2959. if (tmpmin.z < min.z) min.z = tmpmin.z;
  2960. if (tmpmax.x > max.x) max.x = tmpmax.x;
  2961. if (tmpmax.y > max.y) max.y = tmpmax.y;
  2962. if (tmpmax.z > max.z) max.z = tmpmax.z;
  2963. }
  2964. if (min.x > max.x)
  2965. {
  2966. g_pStudioModel->ExtractBbox(min, max);
  2967. }
  2968. float dx = max[0] - min[0];
  2969. float dy = max[1] - min[1];
  2970. float dz = max[2] - min[2];
  2971. // Determine the distance from the model such that it will fit in the screen.
  2972. float d = dx;
  2973. if (dy > d)
  2974. d = dy;
  2975. if (dz > d)
  2976. d = dz;
  2977. g_pStudioModel->m_origin[0] = d * 1.34f;
  2978. g_pStudioModel->m_origin[1] = 0.0f;
  2979. g_pStudioModel->m_origin[2] = min[2] + dz / 2;
  2980. g_pStudioModel->m_angles[0] = 0.0f;
  2981. g_pStudioModel->m_angles[1] = 0.0f;
  2982. g_pStudioModel->m_angles[2] = 0.0f;
  2983. g_viewerSettings.lightrot[0] = 0.0f;
  2984. g_viewerSettings.lightrot[1] = 180.0f; // light should aim at models front
  2985. g_viewerSettings.lightrot[2] = 0.0f;
  2986. setFOV( 65.0f );
  2987. d_MatSysWindow->redraw();
  2988. }
  2989. void ControlPanel::viewmodelView()
  2990. {
  2991. // Sit the camera at the origin with a 54 degree FOV for viewmodels
  2992. g_pStudioModel->m_origin[0] = 0.0f;
  2993. g_pStudioModel->m_origin[1] = 0.0f;
  2994. g_pStudioModel->m_origin[2] = 0.0f;
  2995. g_pStudioModel->m_angles[0] = 0.0f;
  2996. g_pStudioModel->m_angles[1] = 180.0f;
  2997. g_pStudioModel->m_angles[2] = 0.0f;
  2998. g_viewerSettings.lightrot[0] = 0.0f;
  2999. g_viewerSettings.lightrot[1] = 180.0f; // light should aim at models front
  3000. g_viewerSettings.lightrot[2] = 0.0f;
  3001. setFOV( 54.0f );
  3002. d_MatSysWindow->redraw();
  3003. }
  3004. void ControlPanel::setFOV( float fov )
  3005. {
  3006. char buf[64];
  3007. g_viewerSettings.fov = fov;
  3008. sprintf( buf, "%.0f", fov );
  3009. leFOV->setLabel( buf );
  3010. }
  3011. void ControlPanel::setOriginAxisLength( float originAxisLength )
  3012. {
  3013. leOriginAxisLength->setValue( originAxisLength );
  3014. }
  3015. void ControlPanel::initFlexes()
  3016. {
  3017. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3018. LocalFlexController_t i;
  3019. int j;
  3020. if (hdr)
  3021. {
  3022. for (j = 0; j < NUM_FLEX_SLIDERS; j++)
  3023. {
  3024. cFlex[j]->removeAll();
  3025. for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  3026. {
  3027. cFlex[j]->add( hdr->pFlexcontroller(i)->pszName() );
  3028. }
  3029. if ( false ) // TODO: Add a configuration option to do it the sensible way
  3030. {
  3031. cFlex[j]->select( j );
  3032. }
  3033. else
  3034. {
  3035. cFlex[j]->select( hdr->numflexcontrollers() - NUM_FLEX_SLIDERS + j );
  3036. }
  3037. }
  3038. }
  3039. for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  3040. {
  3041. g_pStudioModel->SetFlexController( i, 0.0f );
  3042. hdr->pFlexcontroller( i )->localToGlobal = i;
  3043. }
  3044. for (j = 0; j < NUM_FLEX_SLIDERS; j++)
  3045. {
  3046. i = (LocalFlexController_t)cFlex[j]->getSelectedIndex();
  3047. if (i >= 0)
  3048. {
  3049. slFlexScale[j]->setValue( g_pStudioModel->GetFlexControllerRaw( i ) );
  3050. }
  3051. }
  3052. }
  3053. void ControlPanel::connectFlexes( CStudioHdr *hdr )
  3054. {
  3055. if ( !g_pStudioModel )
  3056. return;
  3057. LocalFlexController_t i;
  3058. LocalFlexController_t j;
  3059. CStudioHdr *root = g_pStudioModel->GetStudioHdr();
  3060. if (hdr && root)
  3061. {
  3062. for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  3063. {
  3064. for ( j = LocalFlexController_t(0); j < root->numflexcontrollers(); j++)
  3065. {
  3066. if ( stricmp( hdr->pFlexcontroller(i)->pszName(), root->pFlexcontroller(j)->pszName() ) == 0 )
  3067. {
  3068. hdr->pFlexcontroller(i)->localToGlobal = root->pFlexcontroller(j)->localToGlobal;
  3069. break;
  3070. }
  3071. }
  3072. }
  3073. }
  3074. }
  3075. static void UpdateSliderLabel( mxSlider *slider, mxLabel *label )
  3076. {
  3077. float value = slider->getValue();
  3078. char buf[80];
  3079. sprintf( buf, "%0.2f", value );
  3080. label->setLabel( buf );
  3081. }
  3082. void ControlPanel::UpdateConstraintSliders( int clamp )
  3083. {
  3084. float vmin = slPhysicsConMin->getValue();
  3085. float vmax = slPhysicsConMax->getValue();
  3086. // reflect mins/maxs
  3087. if ( cbLinked->isChecked() )
  3088. {
  3089. if ( clamp == IDC_PHYS_CON_MIN && vmin <= 0 )
  3090. {
  3091. vmax = -vmin;
  3092. }
  3093. else if ( vmax >= 0 )
  3094. {
  3095. vmin = -vmax;
  3096. }
  3097. }
  3098. if ( vmax < vmin )
  3099. {
  3100. if ( clamp == IDC_PHYS_CON_MIN )
  3101. vmin = vmax;
  3102. else
  3103. vmax = vmin;
  3104. }
  3105. slPhysicsConMin->setValue( vmin );
  3106. slPhysicsConMax->setValue( vmax );
  3107. UpdateSliderLabel( slPhysicsConMin, lPhysicsConMin );
  3108. UpdateSliderLabel( slPhysicsConMax, lPhysicsConMax );
  3109. UpdateSliderLabel( slPhysicsFriction, lPhysicsFriction );
  3110. }
  3111. int ControlPanel::handlePhysicsEvent( mxEvent *event )
  3112. {
  3113. switch( event->action )
  3114. {
  3115. case IDC_PHYS_BONE:
  3116. setupPhysicsBone( cPhysicsBone->getSelectedIndex() );
  3117. break;
  3118. case IDC_PHYS_CON_AXIS_X:
  3119. case IDC_PHYS_CON_AXIS_Y:
  3120. case IDC_PHYS_CON_AXIS_Z:
  3121. setupPhysicsAxis( cPhysicsBone->getSelectedIndex(), event->action - IDC_PHYS_CON_AXIS_X );
  3122. break;
  3123. case IDC_PHYS_CON_TYPE_FREE:
  3124. case IDC_PHYS_CON_TYPE_FIXED:
  3125. case IDC_PHYS_CON_TYPE_LIMIT:
  3126. break;
  3127. case IDC_PHYS_CON_MIN:
  3128. case IDC_PHYS_CON_MAX:
  3129. case IDC_PHYS_CON_FRICTION:
  3130. UpdateConstraintSliders( event->action );
  3131. break;
  3132. case IDC_PHYS_CON_TEST:
  3133. g_pStudioModel->Physics_SetPreview( cPhysicsBone->getSelectedIndex(), getPhysicsAxis(), slPhysicsConTest->getValue() );
  3134. break;
  3135. case IDC_PHYS_P_MASSBIAS:
  3136. UpdateSliderLabel( slPhysicsParamMassBias, lPhysicsParamMassBias );
  3137. break;
  3138. case IDC_PHYS_P_INERTIA:
  3139. UpdateSliderLabel( slPhysicsParamInertia, lPhysicsParamInertia );
  3140. break;
  3141. case IDC_PHYS_P_DAMPING:
  3142. UpdateSliderLabel( slPhysicsParamDamping, lPhysicsParamDamping );
  3143. break;
  3144. case IDC_PHYS_P_ROT_DAMPING:
  3145. UpdateSliderLabel( slPhysicsParamRotDamping, lPhysicsParamRotDamping );
  3146. break;
  3147. case IDC_PHYS_QCFILE:
  3148. {
  3149. writePhysicsData();
  3150. char *pOut = g_pStudioModel->Physics_DumpQC();
  3151. if ( pOut )
  3152. {
  3153. Sys_CopyStringToClipboard( pOut );
  3154. }
  3155. delete[] pOut;
  3156. return 1;
  3157. }
  3158. break;
  3159. }
  3160. writePhysicsData();
  3161. return 1;
  3162. }
  3163. void ControlPanel::handlePhysicsKey( mxEvent *event )
  3164. {
  3165. if ( event->key == '[' || event->key == ']' )
  3166. {
  3167. int boneIndex = cPhysicsBone->getSelectedIndex();
  3168. int boneCount = cPhysicsBone->getItemCount();
  3169. int axisIndex = getPhysicsAxis();
  3170. int axisCount = 3;
  3171. if ( event->key == '[' )
  3172. {
  3173. axisIndex = (axisIndex+axisCount-1) % axisCount;
  3174. if ( axisIndex == (axisCount-1) )
  3175. {
  3176. boneIndex = (boneIndex+boneCount-1) % boneCount;
  3177. }
  3178. }
  3179. else
  3180. {
  3181. axisIndex = (axisIndex+1) % axisCount;
  3182. if ( axisIndex == 0 )
  3183. {
  3184. boneIndex = (boneIndex+1) % boneCount;
  3185. }
  3186. }
  3187. setPhysicsAxis( axisIndex );
  3188. cPhysicsBone->select( boneIndex );
  3189. setupPhysicsBone( boneIndex );
  3190. }
  3191. }
  3192. void ControlPanel::setupPhysics( void )
  3193. {
  3194. if (!PopulatePhysicsBoneList( cPhysicsBone) )
  3195. return;
  3196. cPhysicsBone->select (0);
  3197. setPhysicsAxis(0);
  3198. setupPhysicsBone( 0 );
  3199. char buf[64];
  3200. sprintf( buf, "%.2f", g_pStudioModel->Physics_GetMass() );
  3201. leMass->setLabel( buf );
  3202. // Default to "None"
  3203. setHighlightBone(0);
  3204. }
  3205. static void SetSlider( mxSlider *slider, mxLabel *label, float value )
  3206. {
  3207. slider->setValue( value );
  3208. UpdateSliderLabel( slider, label );
  3209. }
  3210. int ControlPanel::getPhysicsAxis( void )
  3211. {
  3212. for ( int i = 0; i < 3; i++ )
  3213. if ( rbConstraintAxis[i]->isChecked() )
  3214. return i;
  3215. return 0;
  3216. }
  3217. void ControlPanel::setPhysicsAxis( int axisIndex )
  3218. {
  3219. for ( int i = 0; i < 3; i++ )
  3220. {
  3221. rbConstraintAxis[i]->setChecked( (i==axisIndex)?true : false );
  3222. }
  3223. }
  3224. void ControlPanel::setupPhysicsBone( int boneIndex )
  3225. {
  3226. if (!g_pStudioModel->m_pPhysics)
  3227. return;
  3228. int axisIndex = getPhysicsAxis();
  3229. setupPhysicsAxis( boneIndex, axisIndex );
  3230. // read per-bone data
  3231. hlmvsolid_t solid;
  3232. g_pStudioModel->Physics_GetData( boneIndex, &solid, NULL );
  3233. SetSlider( slPhysicsParamMassBias, lPhysicsParamMassBias, solid.massBias );
  3234. SetSlider( slPhysicsParamInertia, lPhysicsParamInertia, solid.params.inertia );
  3235. SetSlider( slPhysicsParamDamping, lPhysicsParamDamping, solid.params.damping );
  3236. SetSlider( slPhysicsParamRotDamping, lPhysicsParamRotDamping, solid.params.rotdamping );
  3237. // Find the bone
  3238. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  3239. for ( int i = 0; i < pHdr->numbones(); i++ )
  3240. {
  3241. mstudiobone_t* pBone = pHdr->pBone(i);
  3242. if (!stricmp(pBone->pszName(), solid.name ))
  3243. {
  3244. // Once found, set the surface property accordingly
  3245. lPhysicsMaterial->setLabel( g_pStudioModel->m_SurfaceProps[i].String() );
  3246. break;
  3247. }
  3248. }
  3249. // select the render/highlight bone
  3250. setHighlightBone( boneIndex + 1 );
  3251. redraw();
  3252. }
  3253. void ControlPanel::setupPhysicsAxis( int boneIndex, int axis )
  3254. {
  3255. // read the per-axis data
  3256. constraint_ragdollparams_t constraint;
  3257. g_pStudioModel->Physics_GetData( boneIndex, NULL, &constraint );
  3258. setPhysicsAxis( axis );
  3259. SetSlider( slPhysicsConMin, lPhysicsConMin, constraint.axes[axis].minRotation );
  3260. SetSlider( slPhysicsConMax, lPhysicsConMax, constraint.axes[axis].maxRotation );
  3261. SetSlider( slPhysicsFriction, lPhysicsFriction, constraint.axes[axis].torque );
  3262. g_pStudioModel->Physics_SetPreview( -1, 0, 0 );
  3263. redraw();
  3264. }
  3265. void ControlPanel::writePhysicsData( void )
  3266. {
  3267. int boneIndex = cPhysicsBone->getSelectedIndex();
  3268. int axis = getPhysicsAxis();
  3269. hlmvsolid_t solid;
  3270. constraint_ragdollparams_t constraint;
  3271. // read the existing data
  3272. g_pStudioModel->Physics_GetData( boneIndex, &solid, &constraint );
  3273. const char *pMass = leMass->getLabel();
  3274. float mass = 0;
  3275. if ( pMass )
  3276. {
  3277. mass = atof( pMass );
  3278. }
  3279. g_pStudioModel->Physics_SetMass( mass );
  3280. // write back the data we're editing on this dialog
  3281. constraint.axes[axis].minRotation = slPhysicsConMin->getValue();
  3282. constraint.axes[axis].maxRotation = slPhysicsConMax->getValue();
  3283. constraint.axes[axis].torque = slPhysicsFriction->getValue();
  3284. solid.massBias = slPhysicsParamMassBias->getValue();
  3285. solid.index = boneIndex;
  3286. //solid.params.mass;
  3287. solid.params.inertia = slPhysicsParamInertia->getValue();
  3288. solid.params.damping = slPhysicsParamDamping->getValue();
  3289. solid.params.rotdamping = slPhysicsParamRotDamping->getValue();
  3290. // store it in the model
  3291. g_pStudioModel->Physics_SetData( boneIndex, &solid, &constraint );
  3292. }
  3293. //-----------------------------------------------------------------------------
  3294. //
  3295. //-----------------------------------------------------------------------------
  3296. void ControlPanel::SetFrameSlider( float flFrame )
  3297. {
  3298. slForceFrame->setValue( flFrame );
  3299. }
  3300. //-----------------------------------------------------------------------------
  3301. //
  3302. //-----------------------------------------------------------------------------
  3303. void ControlPanel::UnloadAllMergedModels()
  3304. {
  3305. for ( int i = 0; i < HLMV_MAX_MERGED_MODELS; ++i )
  3306. {
  3307. g_MDLViewer->getMenuBar()->modify( IDC_FILE_UNLOADMERGEDMODEL1 + i, IDC_FILE_UNLOADMERGEDMODEL1 + i, "(empty)" );
  3308. g_MDLViewer->getMenuBar()->setEnabled( IDC_FILE_UNLOADMERGEDMODEL1 + i, false );
  3309. V_strcpy_safe( g_viewerSettings.mergeModelFile[i], "" );
  3310. if ( g_pStudioExtraModel[i] )
  3311. {
  3312. g_pStudioExtraModel[i]->FreeModel( false );
  3313. delete g_pStudioExtraModel[i];
  3314. g_pStudioExtraModel[i] = NULL;
  3315. }
  3316. }
  3317. }