Counter Strike : Global Offensive Source Code
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.

6209 lines
179 KiB

  1. //===== Copyright � 1996-2005, 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 "mdlobjects/dmehitbox.h"
  49. #include "mdlobjects/dmehitboxset.h"
  50. #include "mdlobjects/dmehitboxsetlist.h"
  51. #include "datamodel/idatamodel.h"
  52. #include "tier2/tier2.h"
  53. #include "tier2/p4helpers.h"
  54. #include "valve_ipc_win32.h"
  55. #include "mdlviewer.h"
  56. #include "materialsystem/imaterialvar.h"
  57. #include "tier1/fmtstr.h"
  58. #include "mathlib/softbodyenvironment.h"
  59. extern char g_appTitle[];
  60. extern IPhysicsSurfaceProps *physprop;
  61. extern void LoadPhysicsProperties( void );
  62. extern ISoundEmitterSystemBase *g_pSoundEmitterBase;
  63. extern CValveIpcClientUtl g_HlmvIpcClient;
  64. extern bool g_bHlmvMaster;
  65. extern CSoftbodyEnvironment g_SoftbodyEnvironment;
  66. bool g_OnlyEditMaterialsThatWantToBeEdited = false;
  67. class CTextBuffer
  68. {
  69. public:
  70. CTextBuffer( void ) {}
  71. ~CTextBuffer( void ) {}
  72. inline int GetSize( void ) { return m_buffer.Count(); }
  73. inline char *GetData( void ) { return m_buffer.Base(); }
  74. void WriteText( const char *pText )
  75. {
  76. int len = strlen( pText );
  77. CopyData( pText, len );
  78. }
  79. void Terminate( void ) { CopyData( "\0", 1 ); }
  80. void CopyData( const char *pData, int len )
  81. {
  82. int offset = m_buffer.AddMultipleToTail( len );
  83. memcpy( m_buffer.Base() + offset, pData, len );
  84. }
  85. private:
  86. CUtlVector<char> m_buffer;
  87. };
  88. //-----------------------------------------------------------------------------
  89. // Reads all of the physics materials from surface property file
  90. //-----------------------------------------------------------------------------
  91. static void ReadPhysicsMaterials( mxChoice *plist )
  92. {
  93. LoadPhysicsProperties();
  94. plist->removeAll();
  95. if ( !physprop || !physprop->SurfacePropCount() )
  96. {
  97. plist->add("default");
  98. plist->select(0);
  99. return;
  100. }
  101. for ( int i = 0; i < physprop->SurfacePropCount(); i++ )
  102. {
  103. plist->add(physprop->GetPropName( i ) );
  104. }
  105. plist->select(0);
  106. }
  107. //-----------------------------------------------------------------------------
  108. // Populates a control with all the physics bones
  109. //-----------------------------------------------------------------------------
  110. static bool PopulatePhysicsBoneList( mxChoice* pChoice )
  111. {
  112. pChoice->removeAll();
  113. if ( g_pStudioModel->Physics_GetBoneCount() )
  114. {
  115. for ( int i = 0; i < g_pStudioModel->Physics_GetBoneCount(); i++ )
  116. {
  117. pChoice->add (g_pStudioModel->Physics_GetBoneName( i ) );
  118. }
  119. }
  120. else
  121. {
  122. pChoice->add( "None" );
  123. pChoice->select (0);
  124. return false;
  125. }
  126. pChoice->select (0);
  127. return true;
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Populates a control with all the sound names
  131. //-----------------------------------------------------------------------------
  132. static void PopulateSoundNameList( mxListBox *pListBox )
  133. {
  134. pListBox->removeAll();
  135. if ( g_pSoundEmitterBase )
  136. {
  137. for ( int i = g_pSoundEmitterBase->First(); i != g_pSoundEmitterBase->InvalidIndex(); i = g_pSoundEmitterBase->Next( i ) )
  138. {
  139. pListBox->add( g_pSoundEmitterBase->GetSoundName( i ) );
  140. }
  141. }
  142. pListBox->select( 0 );
  143. pListBox->deselect( 0 );
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Populates a control with all the physics bones
  147. //-----------------------------------------------------------------------------
  148. bool PopulateBoneList( mxChoice* pChoice, bool bAlwaysAddNone = false )
  149. {
  150. pChoice->removeAll();
  151. if ( bAlwaysAddNone )
  152. {
  153. pChoice->add( "(None)" );
  154. }
  155. if ( g_pStudioModel )
  156. {
  157. CStudioHdr *pHdr = g_pStudioModel->GetStudioHdr();
  158. if ( pHdr && pHdr->numbones() > 0 )
  159. {
  160. for ( int i = 0; i < pHdr->numbones(); i++ )
  161. {
  162. pChoice->add ( pHdr->pBone(i)->pszName() );
  163. }
  164. pChoice->select(0);
  165. return true;
  166. }
  167. }
  168. if ( !bAlwaysAddNone )
  169. {
  170. pChoice->add( "(None)" );
  171. }
  172. pChoice->select(0);
  173. return false;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Populates a control with all the attachments
  177. //-----------------------------------------------------------------------------
  178. void PopulateAttachmentsList( mxChoice *pChoice )
  179. {
  180. pChoice->removeAll();
  181. pChoice->add( "(none)" );
  182. if ( g_pStudioModel )
  183. {
  184. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  185. if ( pHdr && pHdr->GetNumAttachments() > 0 )
  186. {
  187. for ( int i = 0; i < pHdr->GetNumAttachments(); i++ )
  188. {
  189. pChoice->add( pHdr->pAttachment(i).pszName() );
  190. }
  191. }
  192. }
  193. pChoice->select(0);
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Sets the text of a lineedit to the current frame
  197. //-----------------------------------------------------------------------------
  198. void SetFrameString( mxLineEdit2 *pLineEdit, int iLayer )
  199. {
  200. float flFrame = g_pStudioModel->GetFrame( iLayer );
  201. int nFrame = int( flFrame + 0.5f );
  202. char msg[ 16 ];
  203. sprintf( msg, "%d", nFrame );
  204. pLineEdit->setText( msg );
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Finds the index of a surface prop
  208. //-----------------------------------------------------------------------------
  209. static int FindSurfaceProp( const char* pSurfaceProp )
  210. {
  211. for (int i = 0; i < physprop->SurfacePropCount(); ++i)
  212. {
  213. if (!stricmp( physprop->GetPropName( i ), pSurfaceProp ))
  214. return i;
  215. }
  216. return -1;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // The tab associated with bone control
  220. //-----------------------------------------------------------------------------
  221. class CBoneControlWindow : public mxWindow
  222. {
  223. public:
  224. CBoneControlWindow( ControlPanel* pParent );
  225. void Init( );
  226. // This gets called when the model is loaded and unloaded
  227. void OnLoadModel();
  228. void OnUnloadModel();
  229. // Handles various events
  230. int handleEvent (mxEvent *event);
  231. // Called when we're selected
  232. void OnTabSelected();
  233. int GetHitboxSet( void );
  234. private:
  235. // Called when the bone is selected
  236. void OnBoneSelected( int boneIndex );
  237. void OnBoneHighlighted( bool isChecked );
  238. void OnHitboxHighlighted( bool isChecked );
  239. void OnShowDefaultPose( bool isChecked );
  240. void OnHitboxSelected( int hitbox );
  241. void OnHitboxGroupChanged( );
  242. void OnHitboxChanged( );
  243. void OnHitboxSetChanged( void );
  244. void OnAddHitbox( );
  245. void OnDeleteHitbox( );
  246. void OnGenerateQC( );
  247. void OnSaveHitboxes( );
  248. void OnLoadHitboxes( );
  249. void OnAutogenerateHitboxes( bool isChecked );
  250. // Writes out qc-style text to a utlbuffer
  251. bool SerializeQC( CUtlBuffer& buf );
  252. // Sets the surface property
  253. void OnSurfaceProp( int propIndex );
  254. // Duplictes the surface property to all children
  255. void OnSurfacePropApplyToChildren( );
  256. void RefreshHitbox( );
  257. void ComputeHitboxList( );
  258. void ComputeHitboxSetList( void );
  259. void OnHitboxAddSet( void );
  260. void OnHitboxDeleteSet( void );
  261. void OnHitboxSetChangeName( void );
  262. // Generates a list of all hitboxes per bone
  263. void PopulateHitboxLists();
  264. // Applies a surface property to all children
  265. void OnSurfacePropApplyToChildren_R( int bone, CUtlSymbol prop );
  266. // Selects the bone
  267. mxChoice* m_cBone;
  268. mxChoice* m_cHitboxSet;
  269. mxLineEdit *m_eHitboxSetName;
  270. mxButton *m_bHitboxSetUpdateName;
  271. mxButton *m_bAddHitboxSet;
  272. mxButton *m_bDeleteHitboxSet;
  273. // Selects a hitbox associated with a bone
  274. mxChoice* m_cHitbox;
  275. // The materials to assign to the bone
  276. mxChoice* m_cSurfaceProp;
  277. // Are we highlighting bones?
  278. mxCheckBox* m_cBoneHighlight;
  279. // render bone names
  280. mxCheckBox* m_cBoneNames;
  281. // Are we highlighting hitboxes?
  282. mxCheckBox* m_cHitboxHighlight;
  283. // Should we show the default pose?
  284. mxCheckBox* m_cShowDefaultPose;
  285. // Should hitboxes be autogenerated?
  286. mxCheckBox* m_cAutoHitbox;
  287. // The control panel to which we're attached
  288. ControlPanel* m_pControlPanel;
  289. // Hitbox group
  290. mxLineEdit* m_eHitboxGroup;
  291. // Hitbox name
  292. mxLineEdit* m_eHitboxName;
  293. mxChoice* m_cHitboxEditMode;
  294. // Hitbox buttons
  295. mxButton* m_bUpdateHitbox;
  296. mxButton* m_bAddHitbox;
  297. mxButton* m_bDeleteHitbox;
  298. // The list of hitboxes per bone...
  299. typedef CUtlVector< int > BoneHitboxList_t;
  300. typedef CUtlVector< BoneHitboxList_t > BoneHitboxes_t;
  301. CUtlVector< BoneHitboxes_t > m_SetBoneHitBoxes;
  302. // Currently selected hitbox + bone
  303. int m_Bone;
  304. int m_Hitbox;
  305. int m_nHitboxSet;
  306. };
  307. //-----------------------------------------------------------------------------
  308. // constructor
  309. //-----------------------------------------------------------------------------
  310. CBoneControlWindow::CBoneControlWindow( ControlPanel* pParent ) : mxWindow( pParent, 0, 0, 0, 0 )
  311. {
  312. m_pControlPanel = pParent;
  313. m_nHitboxSet = 0;
  314. }
  315. //-----------------------------------------------------------------------------
  316. // Sets up all the controls in the window
  317. //-----------------------------------------------------------------------------
  318. void CBoneControlWindow::Init( )
  319. {
  320. int left, top;
  321. left = 5;
  322. top = 0;
  323. // Bone selection list
  324. new mxLabel (this, left + 3, top + 4, 30, 18, "Bone");
  325. m_cBone = new mxChoice (this, left, top + 20, 260, 22, IDC_BONE_BONELIST);
  326. m_cBone->add ("None");
  327. m_cBone->select (0);
  328. mxToolTip::add (m_cBone, "Select a bone to modify");
  329. // Show bone checkbox
  330. m_cBoneHighlight = new mxCheckBox (this, left, top + 45, 90, 20, "Highlight", IDC_BONE_HIGHLIGHT_BONE);
  331. mxToolTip::add (m_cBoneHighlight, "Toggle display of the bone being modified");
  332. //m_cBoneNames
  333. // Show bone names
  334. m_cBoneNames = new mxCheckBox (this, left + 90, top + 45, 140, 20, "Names", IDC_BONE_NAMES);
  335. m_cBoneNames->setChecked( g_viewerSettings.showBoneNames );
  336. mxToolTip::add (m_cBoneNames, "Toggle bone names");
  337. // Bone surface property selection
  338. new mxLabel (this, left + 3, top + 68, 100, 18, "Bone Surface Prop");
  339. m_cSurfaceProp = new mxChoice( this, left, top + 85, 140, 22, IDC_BONE_SURFACEPROP );
  340. mxToolTip::add (m_cSurfaceProp, "Select a surface property to apply to the bone");
  341. // FIXME: We can't read the surface props yet because the vphysics path isn't known!!!
  342. // This will only add 'default' to the list
  343. ReadPhysicsMaterials( m_cSurfaceProp );
  344. // This button will apply the surface prop to all children
  345. mxButton *btnApplyChild = new mxButton( this, left, top + 115, 140, 20, "Apply to Children", IDC_BONE_APPLY_TO_CHILDREN );
  346. mxToolTip::add (btnApplyChild, "Apply the surface property to all child bones");
  347. // Use autogenerated hitboxes
  348. m_cAutoHitbox = new mxCheckBox (this, left, top + 140, 140, 20, "Autogenerate Hitboxes", IDC_BONE_USE_AUTOGENERATED_HITBOXES);
  349. mxToolTip::add (m_cAutoHitbox, "When this is checked, studiomdl will automatically generate hitboxes");
  350. m_cShowDefaultPose = new mxCheckBox (this, left, top + 160, 140, 20, "Show Default Pose", IDC_BONE_SHOW_DEFAULT_POSE);
  351. mxToolTip::add (m_cShowDefaultPose, "Toggles display of the default physics pose");
  352. left = 160;
  353. new mxLabel( this, left + 3, top + 50, 80, 18, "Hitbox Set" );
  354. m_cHitboxSet = new mxChoice (this, left, top + 66, 100, 22, IDC_BONE_HITBOXSET);
  355. m_cHitboxSet->add ("unnamed");
  356. m_cHitboxSet->select (0);
  357. mxToolTip::add (m_cHitboxSet, "Change hitbox set");
  358. m_eHitboxSetName = new mxLineEdit(this, left, top + 96, 100, 18, "", IDC_BONE_HITBOXSETNAME_EDIT);
  359. mxToolTip::add (m_eHitboxSetName, "Type in a name and hit the set button");
  360. m_bHitboxSetUpdateName = new mxButton( this, left, top + 116, 100, 16, "Set Name", IDC_BONE_HITBOXSETNAME );
  361. mxToolTip::add (m_bHitboxSetUpdateName, "Press to set hitbox set name from above text field");
  362. m_bAddHitboxSet = new mxButton( this, left, top + 140, 100, 20, "Add set", IDC_BONE_HITBOXADDSET );
  363. mxToolTip::add (m_bAddHitboxSet, "Add a hitbox set");
  364. m_bDeleteHitboxSet= new mxButton( this, left, top + 162, 100, 20, "Delete set", IDC_BONE_HITBOXDELETESET );
  365. mxToolTip::add (m_bDeleteHitboxSet, "Remove a hitbox set");
  366. left += 120;
  367. // Hitbox selection list
  368. new mxLabel (this, left + 3, top + 4, 30, 18, "Hitbox");
  369. m_cHitbox = new mxChoice (this, left, top + 20, 100, 22, IDC_BONE_HITBOXLIST);
  370. m_cHitbox->add ("None");
  371. m_cHitbox->select (0);
  372. mxToolTip::add (m_cHitbox, "Select a hitbox to modify");
  373. // Show hitbox checkbox
  374. m_cHitboxHighlight = new mxCheckBox (this, left + 3, top + 45, 100, 20, "Highlight Hitbox", IDC_BONE_HIGHLIGHT_HITBOX);
  375. mxToolTip::add (m_cHitboxHighlight, "Toggle display of the hitbox being modified");
  376. // Hitbox group
  377. new mxLabel (this, left + 3, top + 80, 80, 18, "Hitbox Group");
  378. m_eHitboxGroup = new mxLineEdit(this, left + 80, top + 75, 50, 22, "", IDC_BONE_HITBOX_GROUP);
  379. mxToolTip::add (m_eHitboxGroup, "The group of the current hitbox");
  380. // Hitbox name
  381. new mxLabel (this, left + 133, top + 80, 80, 18, "Hitbox Name");
  382. m_eHitboxName = new mxLineEdit(this, left + 133+80, top + 75, 50, 22, "", IDC_BONE_HITBOX_NAME);
  383. m_eHitboxName->setEnabled(false);
  384. mxToolTip::add (m_eHitboxName, "The name of the current hitbox");
  385. new mxLabel (this, left + 3, top + 110, 80, 18, "Edit Hitbox:");
  386. m_cHitboxEditMode = new mxChoice( this, left + 80, top + 105, 200, 22, IDC_BONE_HITBOX_EDITMODE );
  387. m_cHitboxEditMode->add ("Rotate");
  388. m_cHitboxEditMode->add ("Translate BB Min");
  389. m_cHitboxEditMode->add ("Translate BB Max");
  390. m_cHitboxEditMode->select (0);
  391. // Update hitboxes here
  392. m_bUpdateHitbox = new mxButton( this, left, top + 163, 100, 20, "Update Hitbox", IDC_BONE_UPDATE_HITBOX );
  393. mxToolTip::add (m_bUpdateHitbox, "Apply hitbox group, origin, and size to the hitbox");
  394. // Load from a .hitbox file
  395. mxButton* btnLoadHitbox = new mxButton (this, left + 110, top + 163, 70, 20, "Load .HBX", IDC_BONE_LOAD_HITBOXES );
  396. mxToolTip::add (btnLoadHitbox, "Load hitboxes from a .hbx file");
  397. // Save as a .hitbox file
  398. mxButton* btnSaveHitbox = new mxButton (this, left + 190, top + 163, 70, 20, "Save .HBX", IDC_BONE_SAVE_HITBOXES );
  399. mxToolTip::add (btnSaveHitbox, "Save hitboxes to a .hbx file");
  400. left += 160;
  401. // Generate a QC file
  402. mxButton* btnGenerateQC = new mxButton (this, left, top + 10, 100, 20, "Generate QC", IDC_BONE_GENERATEQC );
  403. mxToolTip::add (btnGenerateQC, "Copy a .qc file snippet to the clipboard");
  404. // Add, remove hitboxes here
  405. m_bAddHitbox = new mxButton( this, left, top + 30, 100, 20, "Add Hitbox", IDC_BONE_ADD_HITBOX );
  406. m_bDeleteHitbox = new mxButton( this, left, top + 50, 100, 20, "Delete Hitbox", IDC_BONE_DELETE_HITBOX );
  407. mxToolTip::add (m_bAddHitbox, "Create a new hitbox attached to the current bone");
  408. mxToolTip::add (m_bDeleteHitbox, "Delete the currently selected hitbox");
  409. OnAutogenerateHitboxes( false );
  410. }
  411. //-----------------------------------------------------------------------------
  412. // Generates a list of all hitboxes per bone
  413. //-----------------------------------------------------------------------------
  414. void CBoneControlWindow::PopulateHitboxLists()
  415. {
  416. // Find the surface prop associated with this bone
  417. if (!g_pStudioModel)
  418. return;
  419. m_SetBoneHitBoxes.RemoveAll();
  420. for (int set = 0; set < g_pStudioModel->m_HitboxSets.Count(); set++ )
  421. {
  422. m_SetBoneHitBoxes.AddToTail();
  423. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ set ].m_Hitboxes;
  424. for ( unsigned short i = list.Head(); i != list.InvalidIndex(); i = list.Next(i) )
  425. {
  426. mstudiobbox_t* pHitbox = &list[i].m_BBox;
  427. m_SetBoneHitBoxes[ set ].EnsureCount( pHitbox->bone + 1 );
  428. m_SetBoneHitBoxes[ set ][ pHitbox->bone ].AddToTail( i );
  429. }
  430. }
  431. }
  432. //-----------------------------------------------------------------------------
  433. // This gets called when the model is loaded and unloaded
  434. //-----------------------------------------------------------------------------
  435. void CBoneControlWindow::OnLoadModel()
  436. {
  437. // Now that the vphysics path is known, we can load the surface props
  438. ReadPhysicsMaterials( m_cSurfaceProp );
  439. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  440. m_cAutoHitbox->setChecked( (pHdr->flags() & STUDIOHDR_FLAGS_AUTOGENERATED_HITBOX) != 0 );
  441. OnAutogenerateHitboxes( m_cAutoHitbox->isChecked() );
  442. // Determine all bones for this model
  443. PopulateBoneList( m_cBone );
  444. ComputeHitboxSetList();
  445. PopulateHitboxLists();
  446. OnBoneSelected( 0 );
  447. g_bDrawModelInfoValid = false;
  448. }
  449. void CBoneControlWindow::OnUnloadModel()
  450. {
  451. m_cBone->removeAll();
  452. m_cBone->add ("None");
  453. m_cBone->select (0);
  454. m_cAutoHitbox->setChecked( false );
  455. }
  456. //-----------------------------------------------------------------------------
  457. // Called when we're selected
  458. //-----------------------------------------------------------------------------
  459. void CBoneControlWindow::OnTabSelected()
  460. {
  461. // Make the selected bone and highlight state match
  462. OnBoneSelected( m_cBone->getSelectedIndex() );
  463. OnBoneHighlighted( m_cBoneHighlight->isChecked() );
  464. OnHitboxHighlighted( m_cHitboxHighlight->isChecked() );
  465. OnShowDefaultPose( m_cShowDefaultPose->isChecked() );
  466. }
  467. //-----------------------------------------------------------------------------
  468. // Purpose:
  469. //-----------------------------------------------------------------------------
  470. int CBoneControlWindow::GetHitboxSet( void )
  471. {
  472. return m_nHitboxSet;
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Purpose:
  476. //-----------------------------------------------------------------------------
  477. void CBoneControlWindow::ComputeHitboxSetList( void )
  478. {
  479. m_cHitboxSet->removeAll();
  480. for ( int i = 0 ; i < g_pStudioModel->m_HitboxSets.Count(); i++ )
  481. {
  482. const char *name = g_pStudioModel->m_HitboxSets[ i ].m_Name;
  483. m_cHitboxSet->add( name );
  484. }
  485. m_cHitboxSet->select( 0 );
  486. }
  487. //-----------------------------------------------------------------------------
  488. // Recomputes the hitbox list
  489. //-----------------------------------------------------------------------------
  490. void CBoneControlWindow::ComputeHitboxList( )
  491. {
  492. // Reset the hitbox list
  493. m_cHitbox->removeAll();
  494. int count = 0;
  495. if ( m_SetBoneHitBoxes.Count() > 0 )
  496. {
  497. if (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() > m_Bone)
  498. count = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count();
  499. if (count > 0)
  500. {
  501. for (int i = 0; i < count; ++i )
  502. {
  503. char buf[32];
  504. sprintf( buf, "%d", m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][i] );
  505. m_cHitbox->add( buf );
  506. }
  507. }
  508. else
  509. {
  510. m_cHitbox->add ("None");
  511. }
  512. }
  513. else
  514. {
  515. m_cHitbox->add ("None");
  516. }
  517. OnHitboxSelected(0);
  518. }
  519. //-----------------------------------------------------------------------------
  520. // Here's what we do when a new bone is selected
  521. //-----------------------------------------------------------------------------
  522. void CBoneControlWindow::OnBoneSelected( int boneIndex )
  523. {
  524. // Reset the surface prop
  525. if (!g_pStudioModel)
  526. return;
  527. if ( physprop && g_pStudioModel->m_SurfaceProps.Count() )
  528. {
  529. // Find the surface prop associated with this bone
  530. const char* pSurfaceProp = g_pStudioModel->m_SurfaceProps[boneIndex].String();
  531. int idx = FindSurfaceProp( pSurfaceProp );
  532. // Can't find it? Then apply the default one
  533. if (idx < 0)
  534. idx = FindSurfaceProp( "default" );
  535. if (idx < 0)
  536. idx = 0;
  537. m_cSurfaceProp->select(idx);
  538. }
  539. else
  540. {
  541. m_cSurfaceProp->select(0);
  542. }
  543. // Store off the bone
  544. m_Bone = boneIndex;
  545. if (m_cBoneHighlight->isChecked())
  546. g_viewerSettings.highlightBone = m_Bone;
  547. ComputeHitboxList();
  548. // select the render/highlight bone
  549. m_pControlPanel->redraw();
  550. }
  551. //-----------------------------------------------------------------------------
  552. // When the bone is highlighted or not
  553. //-----------------------------------------------------------------------------
  554. void CBoneControlWindow::OnShowDefaultPose( bool isChecked )
  555. {
  556. g_viewerSettings.showPhysicsPreview = isChecked;
  557. }
  558. //-----------------------------------------------------------------------------
  559. // When the bone is highlighted or not
  560. //-----------------------------------------------------------------------------
  561. void CBoneControlWindow::OnBoneHighlighted( bool isChecked )
  562. {
  563. g_viewerSettings.highlightBone = isChecked ? m_Bone : -1;
  564. }
  565. //-----------------------------------------------------------------------------
  566. // When the hitbox is highlighted or not
  567. //-----------------------------------------------------------------------------
  568. void CBoneControlWindow::OnHitboxHighlighted( bool isChecked )
  569. {
  570. g_viewerSettings.highlightHitbox = isChecked ? m_Hitbox : -1;
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Refreshes the hitbox size
  574. //-----------------------------------------------------------------------------
  575. void CBoneControlWindow::RefreshHitbox( )
  576. {
  577. if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Count() )
  578. {
  579. m_nHitboxSet = 0;
  580. }
  581. if ( m_Hitbox >= 0 && g_pStudioModel->m_HitboxSets.Count() > 0 )
  582. {
  583. // Set the hitbox size + origin + group
  584. mstudiobbox_t* pHitbox = &g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[ m_Hitbox ].m_BBox;
  585. m_eHitboxGroup->setLabel( "%i", pHitbox->group );
  586. const char *hitboxname = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[ m_Hitbox ].m_Name;
  587. m_eHitboxName->setLabel( hitboxname );
  588. }
  589. else
  590. {
  591. m_eHitboxGroup->setLabel( "" );
  592. m_eHitboxName->setLabel( "" );
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // When a hitbox is selected
  597. //-----------------------------------------------------------------------------
  598. void CBoneControlWindow::OnHitboxSelected( int hitbox )
  599. {
  600. if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Count() )
  601. {
  602. m_nHitboxSet = 0;
  603. }
  604. m_cHitbox->select(hitbox);
  605. if ( m_SetBoneHitBoxes.Count() == 0 ||
  606. (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() <= m_Bone) ||
  607. (m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() <= hitbox))
  608. {
  609. m_Hitbox = -1;
  610. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  611. // This'll cause no boxes to be drawn
  612. if (m_cHitboxHighlight->isChecked())
  613. g_viewerSettings.highlightHitbox = pHdr ? pHdr->numbones() + 1 : 1;
  614. }
  615. else
  616. {
  617. m_Hitbox = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][hitbox];
  618. if (m_cHitboxHighlight->isChecked())
  619. g_viewerSettings.highlightHitbox = m_Hitbox;
  620. }
  621. RefreshHitbox();
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Hitbox size/origin changed
  625. //-----------------------------------------------------------------------------
  626. void CBoneControlWindow::OnAutogenerateHitboxes( bool isChecked )
  627. {
  628. m_eHitboxGroup->setEnabled( !isChecked );
  629. m_eHitboxName->setEnabled( !isChecked );
  630. m_bUpdateHitbox->setEnabled( !isChecked );
  631. m_bAddHitbox->setEnabled( !isChecked );
  632. m_bDeleteHitbox->setEnabled( !isChecked );
  633. m_cHitboxSet->setEnabled( !isChecked );
  634. m_eHitboxSetName->setEnabled( !isChecked );
  635. m_bHitboxSetUpdateName->setEnabled( !isChecked );
  636. m_bAddHitboxSet->setEnabled( !isChecked );
  637. m_bDeleteHitboxSet->setEnabled( !isChecked );
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Hitbox size/origin changed
  641. //-----------------------------------------------------------------------------
  642. void CBoneControlWindow::OnHitboxChanged( )
  643. {
  644. if ( m_nHitboxSet < 0 || m_nHitboxSet >= g_pStudioModel->m_HitboxSets.Count() )
  645. {
  646. m_nHitboxSet = 0;
  647. }
  648. if ( m_Hitbox < 0 || g_pStudioModel->m_HitboxSets.Count() <= 0 )
  649. {
  650. // Blat out the hitbox size + origin + group
  651. RefreshHitbox();
  652. return;
  653. }
  654. mstudiobbox_t* pHitbox;
  655. const char *pGroup;
  656. pHitbox = &g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[m_Hitbox].m_BBox;
  657. pGroup = m_eHitboxGroup->getLabel();
  658. if (pGroup)
  659. {
  660. pHitbox->group = atol( pGroup );
  661. }
  662. // Store off the hitbox name
  663. g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[m_Hitbox].m_Name = m_eHitboxName->getLabel();
  664. RefreshHitbox();
  665. }
  666. //-----------------------------------------------------------------------------
  667. // Purpose: Hitbox set changed
  668. //-----------------------------------------------------------------------------
  669. void CBoneControlWindow::OnHitboxSetChanged( void )
  670. {
  671. m_Hitbox = 0;
  672. m_nHitboxSet = m_cHitboxSet->getSelectedIndex();
  673. PopulateHitboxLists();
  674. // Repopulate other controls
  675. ComputeHitboxList();
  676. RefreshHitbox();
  677. //OnHitboxGroupChanged( ); // Refresh hitbox will update the group label from the hitbox's group. No need to turn that back into a group #
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Hitbox size/origin changed
  681. //-----------------------------------------------------------------------------
  682. void CBoneControlWindow::OnHitboxGroupChanged( )
  683. {
  684. if ( m_Hitbox >= 0 && g_pStudioModel->m_HitboxSets.Count() > 0 )
  685. {
  686. const char *pGroup = m_eHitboxGroup->getLabel();
  687. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes;
  688. if ( pGroup && list.IsInList( m_Hitbox ) )
  689. {
  690. mstudiobbox_t* pHitbox = &list[m_Hitbox].m_BBox;
  691. pHitbox->group = atol( pGroup );
  692. }
  693. }
  694. }
  695. //-----------------------------------------------------------------------------
  696. // Add, remove hitboxes
  697. //-----------------------------------------------------------------------------
  698. void CBoneControlWindow::OnAddHitbox( )
  699. {
  700. if (!g_pStudioModel)
  701. return;
  702. // Remove the 'none' entry
  703. if (m_SetBoneHitBoxes[ m_nHitboxSet ].Count() > 0 &&
  704. m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() == 0)
  705. {
  706. m_cHitbox->removeAll();
  707. }
  708. int i = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes.AddToTail();
  709. HitboxInfo_t &hitbox = g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes[i];
  710. hitbox.m_BBox.bone = m_Bone;
  711. hitbox.m_BBox.group = 0;
  712. hitbox.m_BBox.bbmin.Init( -8, -8, -8 );
  713. hitbox.m_BBox.bbmax.Init( 8, 8, 8 );
  714. hitbox.m_BBox.szhitboxnameindex = 0;
  715. m_SetBoneHitBoxes[ m_nHitboxSet ].EnsureCount( m_Bone + 1 );
  716. m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].AddToTail(i);
  717. char buf[32];
  718. sprintf(buf, "%d", i );
  719. m_cHitbox->add ( buf );
  720. OnHitboxSelected(m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count() - 1);
  721. }
  722. void CBoneControlWindow::OnDeleteHitbox( )
  723. {
  724. if ( !g_pStudioModel || ( m_Hitbox < 0 ) )
  725. return;
  726. g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Hitboxes.Remove(m_Hitbox);
  727. for (int i = m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Count(); --i >= 0; )
  728. {
  729. if (m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone][i] == m_Hitbox)
  730. {
  731. m_SetBoneHitBoxes[ m_nHitboxSet ][m_Bone].Remove(i);
  732. break;
  733. }
  734. }
  735. // Recompute the list of hitboxes
  736. ComputeHitboxList();
  737. }
  738. //-----------------------------------------------------------------------------
  739. // Sets the surface property
  740. //-----------------------------------------------------------------------------
  741. void CBoneControlWindow::OnSurfaceProp( int propIndex )
  742. {
  743. if (g_pStudioModel->IsModelLoaded())
  744. {
  745. // Store off the new surface prop symbol
  746. CUtlSymbol prop( physprop->GetPropName( propIndex ) );
  747. g_pStudioModel->m_SurfaceProps[m_Bone] = prop;
  748. }
  749. }
  750. //-----------------------------------------------------------------------------
  751. // Duplictes the surface property to all children
  752. //-----------------------------------------------------------------------------
  753. void CBoneControlWindow::OnSurfacePropApplyToChildren_R( int bone, CUtlSymbol prop )
  754. {
  755. g_pStudioModel->m_SurfaceProps[bone] = prop;
  756. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  757. for ( int i = 0; i < pHdr->numbones(); i++ )
  758. {
  759. const mstudiobone_t* pBone = pHdr->pBone(i);
  760. if (pBone->parent == bone)
  761. {
  762. OnSurfacePropApplyToChildren_R( i, prop );
  763. }
  764. }
  765. }
  766. void CBoneControlWindow::OnSurfacePropApplyToChildren( )
  767. {
  768. if (!g_pStudioModel)
  769. return;
  770. CUtlSymbol prop = g_pStudioModel->m_SurfaceProps[m_Bone];
  771. OnSurfacePropApplyToChildren_R( m_Bone, prop );
  772. }
  773. //-----------------------------------------------------------------------------
  774. // Writes out qc-style text to a utlbuffer
  775. //-----------------------------------------------------------------------------
  776. bool CBoneControlWindow::SerializeQC( CUtlBuffer& buf )
  777. {
  778. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  779. if (!hdr)
  780. return false;
  781. buf.Printf("// .qc block generated by HLMV begins.\n\n");
  782. // Print out the surface props
  783. buf.Printf( "$surfaceprop \"%s\"\n", g_pStudioModel->m_SurfaceProps[0].String() );
  784. Assert( g_pStudioModel->m_SurfaceProps.Count() == hdr->numbones() );
  785. int i;
  786. for ( i = 1; i < g_pStudioModel->m_SurfaceProps.Count(); ++i)
  787. {
  788. const mstudiobone_t* pBone = hdr->pBone(i);
  789. // Don't bother printing out the name if it's got the same
  790. // surface prop as the parent does
  791. if (pBone->parent >= 0)
  792. {
  793. if (!stricmp( g_pStudioModel->m_SurfaceProps[i].String(),
  794. g_pStudioModel->m_SurfaceProps[pBone->parent].String() ))
  795. continue;
  796. }
  797. buf.Printf( "$jointsurfaceprop \"%s\"\t \"%s\"\n", pBone->pszName(),
  798. g_pStudioModel->m_SurfaceProps[i].String() );
  799. }
  800. if (!m_cAutoHitbox->isChecked())
  801. {
  802. buf.Printf("\n");
  803. float flInvScale = 1.0f;// / 1.07f;
  804. for ( i = 0 ; i < g_pStudioModel->m_HitboxSets.Count(); i++ )
  805. {
  806. buf.Printf( "\n$hboxset \"%s\"\n\n", g_pStudioModel->m_HitboxSets[ i ].m_Name.String() );
  807. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ i ].m_Hitboxes;
  808. for ( unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) )
  809. {
  810. mstudiobbox_t &hitbox = list[j].m_BBox;
  811. const mstudiobone_t* pBone = hdr->pBone( hitbox.bone );
  812. buf.Printf( "$hbox %d \"%s\"\t %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f",
  813. hitbox.group, pBone->pszName(),
  814. hitbox.bbmin.x * flInvScale, hitbox.bbmin.y * flInvScale, hitbox.bbmin.z * flInvScale,
  815. hitbox.bbmax.x * flInvScale, hitbox.bbmax.y * flInvScale, hitbox.bbmax.z * flInvScale,
  816. hitbox.angOffsetOrientation.x, hitbox.angOffsetOrientation.y, hitbox.angOffsetOrientation.z,
  817. hitbox.flCapsuleRadius );
  818. if ( !list[j].m_Name.IsEmpty() )
  819. {
  820. buf.Printf( " \"%s\"", list[j].m_Name.String() );
  821. }
  822. buf.Printf( "\n" );
  823. }
  824. }
  825. }
  826. buf.Printf("\n// .qc block generated by HLMV ends.\n\n");
  827. return true;
  828. }
  829. //-----------------------------------------------------------------------------
  830. // Generates the QC file and copies it to the clipboard
  831. //-----------------------------------------------------------------------------
  832. void CBoneControlWindow::OnGenerateQC( )
  833. {
  834. CUtlBuffer outbuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  835. SerializeQC( outbuf );
  836. if ( outbuf.TellPut() )
  837. {
  838. // Null-terminate the string so CopyString works...
  839. outbuf.PutChar('\0');
  840. Sys_CopyStringToClipboard( (const char*)outbuf.Base() );
  841. }
  842. }
  843. //-----------------------------------------------------------------------------
  844. // Generates a hitbox file's dmelements
  845. //-----------------------------------------------------------------------------
  846. static CDmElement *GenerateHitboxFileElements( )
  847. {
  848. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  849. Assert( g_pStudioModel->m_SurfaceProps.Count() == pHdr->numbones() );
  850. CDmeHitboxSetList *pRoot = CreateElement< CDmeHitboxSetList >( "hitboxSetList", DMFILEID_INVALID );
  851. int nSetCount = g_pStudioModel->m_HitboxSets.Count();
  852. for ( int i = 0; i < nSetCount; ++i )
  853. {
  854. CDmeHitboxSet *pHitboxSet = CreateElement< CDmeHitboxSet >( g_pStudioModel->m_HitboxSets[ i ].m_Name, DMFILEID_INVALID );
  855. pRoot->m_HitboxSetList.AddToTail( pHitboxSet );
  856. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ i ].m_Hitboxes;
  857. for ( unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) )
  858. {
  859. const mstudiobbox_t &srcHitbox = list[ j ].m_BBox;
  860. const char *pHitboxName = list[ j ].m_Name;
  861. const mstudiobone_t* pBone = pHdr->pBone( srcHitbox.bone );
  862. CDmeHitbox *pHitbox = CreateElement< CDmeHitbox >( pHitboxName, DMFILEID_INVALID );
  863. pHitboxSet->m_HitboxList.AddToTail( pHitbox );
  864. pHitbox->m_vMinBounds = srcHitbox.bbmin;
  865. pHitbox->m_vMaxBounds = srcHitbox.bbmax;
  866. pHitbox->m_sBoneName = pBone->pszName();
  867. pHitbox->m_nGroupId = srcHitbox.group;
  868. pHitbox->m_sSurfaceProperty = g_pStudioModel->m_SurfaceProps[ srcHitbox.bone ].String();
  869. }
  870. }
  871. return pRoot;
  872. }
  873. //-----------------------------------------------------------------------------
  874. // Saves hitboxes to a .hb file
  875. //-----------------------------------------------------------------------------
  876. void CBoneControlWindow::OnSaveHitboxes( )
  877. {
  878. const char *pFileName = mxGetSaveFileName( this, 0, "*.hbx" );
  879. if ( !pFileName )
  880. return;
  881. char pActualFileName[MAX_PATH];
  882. Q_strncpy( pActualFileName, pFileName, sizeof(pActualFileName) );
  883. Q_DefaultExtension( pActualFileName, ".hbx", sizeof(pActualFileName) );
  884. CP4AutoEditAddFile autop4( pActualFileName );
  885. CDmElement *pRoot = GenerateHitboxFileElements();
  886. bool bOk = g_pDataModel->SaveToFile( pActualFileName, NULL, NULL, "hitbox", pRoot );
  887. DestroyElement( pRoot, TD_ALL );
  888. if ( !bOk )
  889. {
  890. Warning( "Error serializing hitbox file \"%s\"!\n", pActualFileName );
  891. return;
  892. }
  893. }
  894. //-----------------------------------------------------------------------------
  895. // Loads hitboxes from dmelements
  896. //-----------------------------------------------------------------------------
  897. static void LoadHitboxesFromFile( CDmElement *pRoot )
  898. {
  899. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  900. Assert( g_pStudioModel->m_SurfaceProps.Count() == pHdr->numbones() );
  901. CDmrElementArray< CDmeHitboxSet > hitboxSetList( pRoot, "hitboxsets", false );
  902. if ( !hitboxSetList.IsValid() )
  903. {
  904. Warning( "Hitbox file contains no hitbox sets!\n" );
  905. return;
  906. }
  907. g_pStudioModel->m_HitboxSets.RemoveAll();
  908. int nHitboxSetCount = hitboxSetList.Count();
  909. for ( int i = 0; i < nHitboxSetCount; ++i )
  910. {
  911. CDmeHitboxSet *pSrcHitboxSet = hitboxSetList[i];
  912. // Add a new hitboxset
  913. HitboxSet_t *pHitboxSet = &g_pStudioModel->m_HitboxSets[ g_pStudioModel->m_HitboxSets.AddToTail() ];
  914. pHitboxSet->m_Name = pSrcHitboxSet->GetName();
  915. int nCount = pSrcHitboxSet->m_HitboxList.Count();
  916. for ( int j = 0; j < nCount; ++j )
  917. {
  918. CDmeHitbox *pSrcHitbox = pSrcHitboxSet->m_HitboxList[j];
  919. HitboxInfo_t *pHitbox = &pHitboxSet->m_Hitboxes[ pHitboxSet->m_Hitboxes.AddToTail() ];
  920. pHitbox->m_Name = pSrcHitbox->GetName();
  921. pHitbox->m_BBox.szhitboxnameindex = 0;
  922. pHitbox->m_BBox.group = pSrcHitbox->m_nGroupId;
  923. pHitbox->m_BBox.bbmin = pSrcHitbox->m_vMinBounds;
  924. pHitbox->m_BBox.bbmax = pSrcHitbox->m_vMaxBounds;
  925. bool bFoundBone = false;
  926. for ( int k = 0; k < pHdr->numbones(); ++k )
  927. {
  928. bFoundBone = !Q_stricmp( pHdr->pBone(k)->pszName(), pSrcHitbox->m_sBoneName );
  929. if ( bFoundBone )
  930. {
  931. pHitbox->m_BBox.bone = k;
  932. break;
  933. }
  934. }
  935. if ( !bFoundBone )
  936. {
  937. Warning( "HB file contained a reference to an unknown bone \"%s\"!\n", pSrcHitbox->m_sBoneName.Get() );
  938. }
  939. if ( bFoundBone && !pSrcHitbox->m_sSurfaceProperty.IsEmpty() )
  940. {
  941. // Store off the new surface prop symbol
  942. CUtlSymbol prop( pSrcHitbox->m_sSurfaceProperty );
  943. g_pStudioModel->m_SurfaceProps[ pHitbox->m_BBox.bone ] = prop;
  944. }
  945. }
  946. }
  947. }
  948. void CBoneControlWindow::OnLoadHitboxes( )
  949. {
  950. const char *pFileName = mxGetOpenFileName( this, 0, "*.hbx" );
  951. if ( !pFileName )
  952. return;
  953. char pActualFileName[MAX_PATH];
  954. Q_strncpy( pActualFileName, pFileName, sizeof(pActualFileName) );
  955. Q_DefaultExtension( pActualFileName, ".hbx", sizeof(pActualFileName) );
  956. CDmElement *pRoot;
  957. DmFileId_t fileid = g_pDataModel->RestoreFromFile( pActualFileName, NULL, NULL, &pRoot, CR_FORCE_COPY );
  958. if ( fileid == DMFILEID_INVALID )
  959. {
  960. Warning( "Unable to read hitbox file \"%s\"\n", pActualFileName );
  961. return;
  962. }
  963. LoadHitboxesFromFile( pRoot );
  964. g_pDataModel->RemoveFileId( fileid );
  965. }
  966. //-----------------------------------------------------------------------------
  967. // Purpose:
  968. //-----------------------------------------------------------------------------
  969. void CBoneControlWindow::OnHitboxAddSet( void )
  970. {
  971. char sz[ 32 ];
  972. sprintf( sz, "set%02i", g_pStudioModel->m_HitboxSets.Count() + 1 );
  973. int newsetnumber = g_pStudioModel->m_HitboxSets.AddToTail();
  974. g_pStudioModel->m_HitboxSets[ newsetnumber ].m_Name = sz;
  975. ComputeHitboxSetList();
  976. m_cHitboxSet->select( newsetnumber );
  977. OnHitboxSetChanged();
  978. }
  979. //-----------------------------------------------------------------------------
  980. // Purpose:
  981. //-----------------------------------------------------------------------------
  982. void CBoneControlWindow::OnHitboxDeleteSet( void )
  983. {
  984. // Can't remove last element
  985. if ( m_nHitboxSet == 0 )
  986. {
  987. return;
  988. }
  989. g_pStudioModel->m_HitboxSets.Remove( m_nHitboxSet );
  990. ComputeHitboxSetList();
  991. m_cHitboxSet->select( 0 );
  992. OnHitboxSetChanged();
  993. }
  994. //-----------------------------------------------------------------------------
  995. // Purpose:
  996. //-----------------------------------------------------------------------------
  997. void CBoneControlWindow::OnHitboxSetChangeName( void )
  998. {
  999. if ( g_pStudioModel->m_HitboxSets.Count() <= 0 )
  1000. return;
  1001. char newname[ 512 ];
  1002. strcpy( newname, m_eHitboxSetName->getLabel() );
  1003. if ( !newname[ 0 ] )
  1004. return;
  1005. g_pStudioModel->m_HitboxSets[ m_nHitboxSet ].m_Name = newname;
  1006. int oldsel = m_nHitboxSet;
  1007. ComputeHitboxSetList();
  1008. m_cHitboxSet->select( oldsel );
  1009. OnHitboxSetChanged();
  1010. }
  1011. //-----------------------------------------------------------------------------
  1012. // Responds to events on controls in the window
  1013. //-----------------------------------------------------------------------------
  1014. int CBoneControlWindow::handleEvent (mxEvent *event)
  1015. {
  1016. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1017. if ( event->event == mxEvent::KeyDown )
  1018. {
  1019. // FIXME: calling this forces the edit box to lose position
  1020. // OnHitboxChanged( );
  1021. return 1;
  1022. }
  1023. switch( event->action )
  1024. {
  1025. case IDC_BONE_BONELIST:
  1026. if (g_pStudioModel->IsModelLoaded())
  1027. {
  1028. OnHitboxGroupChanged( );
  1029. OnBoneSelected( m_cBone->getSelectedIndex() );
  1030. }
  1031. break;
  1032. case IDC_BONE_NAMES:
  1033. g_viewerSettings.showBoneNames = ((mxCheckBox *) event->widget)->isChecked();
  1034. break;
  1035. case IDC_BONE_HIGHLIGHT_BONE:
  1036. OnBoneHighlighted( ((mxCheckBox *) event->widget)->isChecked() );
  1037. break;
  1038. case IDC_BONE_HIGHLIGHT_HITBOX:
  1039. OnHitboxHighlighted( ((mxCheckBox *) event->widget)->isChecked() );
  1040. break;
  1041. case IDC_BONE_SHOW_DEFAULT_POSE:
  1042. OnShowDefaultPose( ((mxCheckBox *) event->widget)->isChecked() );
  1043. break;
  1044. case IDC_BONE_HITBOXLIST:
  1045. OnHitboxGroupChanged( );
  1046. OnHitboxSelected( m_cHitbox->getSelectedIndex() );
  1047. break;
  1048. case IDC_BONE_HITBOXSET:
  1049. OnHitboxSetChanged();
  1050. break;
  1051. case IDC_BONE_HITBOXADDSET:
  1052. OnHitboxAddSet();
  1053. break;
  1054. case IDC_BONE_HITBOXDELETESET:
  1055. OnHitboxDeleteSet();
  1056. break;
  1057. case IDC_BONE_HITBOXSETNAME:
  1058. OnHitboxSetChangeName();
  1059. break;
  1060. case IDC_BONE_UPDATE_HITBOX:
  1061. OnHitboxChanged( );
  1062. break;
  1063. case IDC_BONE_HITBOX_EDITMODE:
  1064. g_viewerSettings.hitboxEditMode = (HitboxEditMode)m_cHitboxEditMode->getSelectedIndex();
  1065. break;
  1066. case IDC_BONE_ADD_HITBOX:
  1067. OnHitboxGroupChanged( );
  1068. OnAddHitbox( );
  1069. break;
  1070. case IDC_BONE_DELETE_HITBOX:
  1071. OnDeleteHitbox( );
  1072. break;
  1073. case IDC_BONE_USE_AUTOGENERATED_HITBOXES:
  1074. if (g_pStudioModel->IsModelLoaded())
  1075. OnAutogenerateHitboxes( m_cAutoHitbox->isChecked() );
  1076. break;
  1077. case IDC_BONE_SURFACEPROP:
  1078. OnSurfaceProp( m_cSurfaceProp->getSelectedIndex() );
  1079. break;
  1080. case IDC_BONE_APPLY_TO_CHILDREN:
  1081. if (g_pStudioModel->IsModelLoaded())
  1082. OnSurfacePropApplyToChildren( );
  1083. break;
  1084. case IDC_BONE_GENERATEQC:
  1085. if (g_pStudioModel->IsModelLoaded())
  1086. {
  1087. OnHitboxGroupChanged( );
  1088. OnGenerateQC( );
  1089. }
  1090. break;
  1091. case IDC_BONE_SAVE_HITBOXES:
  1092. if ( g_pStudioModel->IsModelLoaded() && !m_cAutoHitbox->isChecked() )
  1093. {
  1094. OnHitboxGroupChanged( );
  1095. OnSaveHitboxes( );
  1096. }
  1097. break;
  1098. case IDC_BONE_LOAD_HITBOXES:
  1099. if ( g_pStudioModel->IsModelLoaded() )
  1100. {
  1101. OnLoadHitboxes( );
  1102. OnHitboxGroupChanged( );
  1103. }
  1104. break;
  1105. default:
  1106. return 0;
  1107. }
  1108. return 1;
  1109. }
  1110. //-----------------------------------------------------------------------------
  1111. // Singleton instance
  1112. //-----------------------------------------------------------------------------
  1113. ControlPanel *g_ControlPanel = 0;
  1114. #define TAB_RENDER 0
  1115. #define TAB_SEQUENCE 1
  1116. #define TAB_BODY 2
  1117. #define TAB_FLEX 3
  1118. #define TAB_PHYSICS 4
  1119. #define TAB_BONE 5
  1120. #define TAB_ATTACHMENT 6
  1121. #define TAB_IK 7
  1122. #define TAB_EVENT 8
  1123. ControlPanel::ControlPanel( mxWindow *parent )
  1124. : mxWindow( parent, 0, 0, 0, 0, "Control Panel", mxWindow::Normal )
  1125. {
  1126. InitViewerSettings ( "hlmv" );
  1127. // frame slider
  1128. new mxLabel( this, 5, 220, 50, 18, "Frame" );
  1129. slForceFrame = new mxSlider( this, 55, 220, 450, 18, IDC_FORCEFRAME );
  1130. slForceFrame->setRange( 0, 1.0 );
  1131. slForceFrame->setValue( 0.0 );
  1132. slForceFrame->setSteps( 1, 1 );
  1133. mxToolTip::add( slForceFrame, "Force To Frame" );
  1134. lForcedFrame = new mxLabel( this, 505, 220, 30, 18, "0" );
  1135. // create tabcontrol with subdialog windows
  1136. tab = new mxTab( this, 0, 20, 0, 0, IDC_TAB );
  1137. #ifdef WIN32
  1138. SetWindowLong( ( HWND )tab->getHandle(), GWL_EXSTYLE, WS_EX_CLIENTEDGE );
  1139. #endif
  1140. SetupRenderWindow( tab );
  1141. SetupSequenceWindow( tab );
  1142. SetupBodyWindow( tab );
  1143. SetupFlexWindow( tab );
  1144. SetupPhysicsWindow( tab );
  1145. SetupSoftbodyWindow( tab );
  1146. SetupBoneControlWindow( tab );
  1147. SetupAttachmentsWindow( tab );
  1148. SetupIKRuleWindow( tab );
  1149. SetupEventWindow( tab );
  1150. SetupMatVarWindow( tab );
  1151. SetupSubmodelWindow( tab );
  1152. SetupCompileWindow( tab );
  1153. g_ControlPanel = this;
  1154. memset( iSelectionToSequence, 0, sizeof(iSelectionToSequence ) );
  1155. memset( iSequenceToSelection, 0, sizeof(iSequenceToSelection ) );
  1156. memset( m_iSavedSequences, 0, sizeof(m_iSavedSequences) );
  1157. memset( m_flSavedWeights, 0, sizeof(m_flSavedWeights) );
  1158. }
  1159. void ControlPanel::UpdateSubmodelSelection( void )
  1160. {
  1161. int iSelectedSubmodel = cSubmodelList->getSelectedIndex();
  1162. bool bSubmodelButtonsEnabled = (iSelectedSubmodel != -1);
  1163. bSubmodelRemoveSelected->setEnabled( bSubmodelButtonsEnabled );
  1164. cSubmodelAttachTo->setEnabled( bSubmodelButtonsEnabled );
  1165. cSubmodelLocalAttachOrigin->setEnabled( bSubmodelButtonsEnabled );
  1166. if ( bSubmodelButtonsEnabled )
  1167. {
  1168. cSubmodelAttachTo->removeAll();
  1169. cSubmodelAttachTo->add( "_none_" );
  1170. cSubmodelAttachTo->select(0);
  1171. CStudioHdr *pHdr = g_pStudioModel->GetStudioHdr();
  1172. if ( pHdr )
  1173. {
  1174. for ( int n = 0; n < pHdr->numbones(); n++ )
  1175. {
  1176. const mstudiobone_t *pBone = pHdr->pBone(n);
  1177. if ( pBone )
  1178. {
  1179. cSubmodelAttachTo->add( pBone->pszName() );
  1180. if ( Q_stricmp(g_MergeModelBonePairs[iSelectedSubmodel].szTargetBone, pBone->pszName()) == 0 )
  1181. {
  1182. cSubmodelAttachTo->select(n+1);
  1183. }
  1184. }
  1185. }
  1186. for ( int n = 0; n < pHdr->GetNumAttachments(); n++ )
  1187. {
  1188. mstudioattachment_t &pModelAttachment = (mstudioattachment_t &)pHdr->pAttachment( n );
  1189. cSubmodelAttachTo->add( pModelAttachment.pszName() );
  1190. if ( Q_stricmp(g_MergeModelBonePairs[iSelectedSubmodel].szTargetBone, pModelAttachment.pszName()) == 0 )
  1191. {
  1192. cSubmodelAttachTo->select(pHdr->numbones()+n+1);
  1193. }
  1194. }
  1195. }
  1196. cSubmodelLocalAttachOrigin->removeAll();
  1197. cSubmodelLocalAttachOrigin->add( "_none_" );
  1198. cSubmodelLocalAttachOrigin->select(0);
  1199. CStudioHdr *pHdrSub = g_pStudioExtraModel[iSelectedSubmodel]->GetStudioHdr();
  1200. if ( pHdrSub )
  1201. {
  1202. for ( int n = 0; n < pHdrSub->numbones(); n++ )
  1203. {
  1204. const mstudiobone_t *pBone = pHdrSub->pBone(n);
  1205. if ( pBone )
  1206. {
  1207. cSubmodelLocalAttachOrigin->add( pBone->pszName() );
  1208. if ( Q_stricmp(g_MergeModelBonePairs[iSelectedSubmodel].szLocalBone, pBone->pszName()) == 0 )
  1209. {
  1210. cSubmodelLocalAttachOrigin->select(n+1);
  1211. }
  1212. }
  1213. }
  1214. for ( int n = 0; n < pHdrSub->GetNumAttachments(); n++ )
  1215. {
  1216. mstudioattachment_t &pModelAttachment = (mstudioattachment_t &)pHdrSub->pAttachment( n );
  1217. cSubmodelLocalAttachOrigin->add( pModelAttachment.pszName() );
  1218. if ( Q_stricmp(g_MergeModelBonePairs[iSelectedSubmodel].szLocalBone, pModelAttachment.pszName()) == 0 )
  1219. {
  1220. cSubmodelLocalAttachOrigin->select(pHdrSub->numbones()+n+1);
  1221. }
  1222. }
  1223. }
  1224. }
  1225. else
  1226. {
  1227. cSubmodelAttachTo->removeAll();
  1228. cSubmodelLocalAttachOrigin->removeAll();
  1229. }
  1230. }
  1231. void ControlPanel::UpdateSubmodelWindow( void )
  1232. {
  1233. cSubmodelList->removeAll();
  1234. for ( int i = 0; i < HLMV_MAX_MERGED_MODELS; i++ )
  1235. {
  1236. if ( g_viewerSettings.mergeModelFile[i][0] != 0 )
  1237. {
  1238. cSubmodelList->add( g_viewerSettings.mergeModelFile[i] );
  1239. }
  1240. }
  1241. UpdateSubmodelSelection();
  1242. }
  1243. void ControlPanel::SetupSubmodelWindow( mxTab* pTab )
  1244. {
  1245. mxWindow *wSubmodels = new mxWindow (this, 0, 0, 0, 0);
  1246. tab->add (wSubmodels, "Submodels");
  1247. bSubmodelAdd = new mxButton( wSubmodels, 2, 10, 90, 70, "Add Submodel", IDC_SUBMODEL_LOADMERGEDMODEL );
  1248. bSubmodelAddSteam = new mxButton( wSubmodels, 2, 90, 90, 20, "Add [Steam]", IDC_SUBMODEL_LOADMERGEDMODEL_STEAM );
  1249. bSubmodelRemoveAll = new mxButton( wSubmodels, 2, 120, 90, 50, "Remove All", IDC_SUBMODEL_UNLOADALLMERGEDMODELS );
  1250. //new mxLabel( wSubmodels, 100, 2, 100, 18, "Loaded Submodels:" );
  1251. cSubmodelList = new mxListBox( wSubmodels, 100, 10, 450, 175, IDC_SUBMODEL_UPDATE_SELECTION );
  1252. mxToolTip::add (cSubmodelList, "Select submodels to add/remove/change");
  1253. bSubmodelRemoveSelected = new mxButton( wSubmodels, 555, 10, 120, 20, "Remove Selected", IDC_SUBMODEL_UNLOADMERGEDMODEL );
  1254. bSubmodelRemoveSelected->setEnabled(false);
  1255. new mxLabel( wSubmodels, 555, 45, 160, 18, "Force attach to:" );
  1256. cSubmodelAttachTo = new mxChoice( wSubmodels, 555, 60, 200, 20, IDC_SUBMODEL_UPDATE_BONESELECTION );
  1257. cSubmodelAttachTo->setEnabled(false);
  1258. new mxLabel( wSubmodels, 555, 80, 160, 18, "From local attach origin:" );
  1259. cSubmodelLocalAttachOrigin = new mxChoice( wSubmodels, 555, 95, 200, 20, IDC_SUBMODEL_UPDATE_BONESELECTION );
  1260. cSubmodelLocalAttachOrigin->setEnabled(false);
  1261. }
  1262. void ControlPanel::SetupMatVarWindow( mxTab* pTab )
  1263. {
  1264. mxWindow *wMatVars = new mxWindow (this, 0, 0, 0, 0);
  1265. tab->add (wMatVars, "Materials");
  1266. new mxLabel( wMatVars, 2, 2, 100, 18, "Materials:" );
  1267. cMaterialList = new mxListBox( wMatVars, 0, 20, 200, 170, IDC_MATERIALVARMATS );
  1268. cMaterialList->add ("None");
  1269. cMaterialList->select (1);
  1270. mxToolTip::add (cMaterialList, "Materials (VMT files) this model has loaded");
  1271. new mxLabel( wMatVars, 202, 2, 100, 18, "Material Parameters:" );
  1272. cMaterialParamList = new mxListBox( wMatVars, 200, 20, 200, 170, IDC_MATERIALVARPARAMS );
  1273. cMaterialParamList->add ("None");
  1274. cMaterialParamList->select (1);
  1275. mxToolTip::add (cMaterialParamList, "Material parameters of this material");
  1276. new mxLabel (wMatVars, 405, 2, 100, 18, "Modify Parameter:");
  1277. leMaterialParamText = new mxLineEdit2(wMatVars, 405, 25, 510, 24, "", IDC_MATVAREDIT);
  1278. leMaterialParamText->setVisible(false);
  1279. lblMatrixRotation = new mxLabel (wMatVars, 405, 55, 70, 18, "Rotation:");
  1280. slMaterialParamMatrixSliderRotation = new mxSlider(wMatVars, 465, 55, 450, 20, IDC_MATVARSLIDERMATRIX);
  1281. slMaterialParamMatrixSliderRotation->setRange( -180.0, 180.0 );
  1282. slMaterialParamMatrixSliderRotation->setSteps( 1, 1 );
  1283. slMaterialParamMatrixSliderRotation->setValue( 0.0 );
  1284. lblMatrixScaleX = new mxLabel (wMatVars, 405, 75, 70, 18, "Scale X:");
  1285. slMaterialParamMatrixSliderScaleX = new mxSlider(wMatVars, 465, 75, 450, 20, IDC_MATVARSLIDERMATRIX);
  1286. slMaterialParamMatrixSliderScaleX->setRange( -5.0, 5.0 );
  1287. slMaterialParamMatrixSliderScaleX->setSteps( 1, 1 );
  1288. slMaterialParamMatrixSliderScaleX->setValue( 1.0 );
  1289. lblMatrixScaleY = new mxLabel (wMatVars, 405, 95, 70, 18, "Scale Y:");
  1290. slMaterialParamMatrixSliderScaleY = new mxSlider(wMatVars, 465, 95, 450, 20, IDC_MATVARSLIDERMATRIX);
  1291. slMaterialParamMatrixSliderScaleY->setRange( -5.0, 5.0 );
  1292. slMaterialParamMatrixSliderScaleY->setSteps( 1, 1 );
  1293. slMaterialParamMatrixSliderScaleY->setValue( 1.0 );
  1294. lblMatrixTranslateX = new mxLabel (wMatVars, 405, 115, 70, 18, "Translate X:");
  1295. slMaterialParamMatrixSliderTranslateX = new mxSlider(wMatVars, 465, 115, 450, 20, IDC_MATVARSLIDERMATRIX);
  1296. slMaterialParamMatrixSliderTranslateX->setRange( -2.0, 2.0 );
  1297. slMaterialParamMatrixSliderTranslateX->setSteps( 1, 1 );
  1298. slMaterialParamMatrixSliderTranslateX->setValue( 0.0 );
  1299. lblMatrixTranslateY = new mxLabel (wMatVars, 405, 135, 70, 18, "Translate Y:");
  1300. slMaterialParamMatrixSliderTranslateY = new mxSlider(wMatVars, 465, 135, 450, 20, IDC_MATVARSLIDERMATRIX);
  1301. slMaterialParamMatrixSliderTranslateY->setRange( -2.0, 2.0 );
  1302. slMaterialParamMatrixSliderTranslateY->setSteps( 1, 1 );
  1303. slMaterialParamMatrixSliderTranslateY->setValue( 0.0 );
  1304. slMaterialParamMatrixSliderRotation->setVisible(false);
  1305. slMaterialParamMatrixSliderScaleX->setVisible(false);
  1306. slMaterialParamMatrixSliderScaleY->setVisible(false);
  1307. slMaterialParamMatrixSliderTranslateX->setVisible(false);
  1308. slMaterialParamMatrixSliderTranslateY->setVisible(false);
  1309. lblMatrixRotation->setVisible(false);
  1310. lblMatrixScaleX->setVisible(false);
  1311. lblMatrixScaleY->setVisible(false);
  1312. lblMatrixTranslateX->setVisible(false);
  1313. lblMatrixTranslateY->setVisible(false);
  1314. bMaterialParamColor = new mxButton( wMatVars, 405, 55, 100, 30, "Color picker", IDC_MATVARCOLORPICKER );
  1315. bMaterialParamColor->setVisible(false);
  1316. slMaterialParamFloat = new mxSlider(wMatVars, 405, 55, 510, 20, IDC_MATVARSLIDERFLOAT);
  1317. slMaterialParamFloat->setRange( -1.0, 1.0 );
  1318. slMaterialParamFloat->setValue( 0.0 );
  1319. slMaterialParamFloat->setVisible(false);
  1320. cbMaterialParamMultiEdit = new mxCheckBox (wMatVars, 505, 0, 150, 20, "Affect all loaded materials", NULL);
  1321. #ifdef MATERIAL_SCRIPT_SAVE_FEATURE
  1322. bMaterialParamSave = new mxButton( wMatVars, 405, 159, 100, 20, "Run Script", IDC_MATVARSAVE );
  1323. leMaterialParamSavePath = new mxLineEdit2( wMatVars, 515, 159, 150, 20, "saved_material" );
  1324. cbMaterialParamSaveRun = new mxCheckBox( wMatVars, 680, 159, 50, 20, "Run:", NULL );
  1325. cbMaterialParamSaveRun->setChecked( true );
  1326. leMaterialParamSaveRun = new mxLineEdit2( wMatVars, 725, 159, 190, 20, "material_ops.py" );
  1327. #endif
  1328. bMaterialParamLoad = new mxButton( wMatVars, 405, 159, 100, 20, "Replace VMT", IDC_MATVARLOAD );
  1329. mxToolTip::add (bMaterialParamLoad, "Temporarily replace this material with a custom set of VMT parameters.");
  1330. bMaterialParamLoad->setVisible(false);
  1331. bMaterialParamCopyToClipboard = new mxButton( wMatVars, 510, 159, 100, 20, "Copy to clipboard", IDC_MATVARCOPYTOCLIPBOARD );
  1332. mxToolTip::add (bMaterialParamCopyToClipboard, "");
  1333. bMaterialParamCopyToClipboard->setVisible(false);
  1334. }
  1335. void ControlPanel::SetupCompileWindow( mxTab* pTab )
  1336. {
  1337. mxWindow *wCompile = new mxWindow (this, 0, 0, 0, 0);
  1338. tab->add (wCompile, "Compile");
  1339. new mxLabel( wCompile, 2, 2, 200, 15, "Recent QC scripts:" );
  1340. cCompileRecentQCpaths = new mxListBox( wCompile, 2, 18, 300, 155, IDC_COMPILE_UPDATE_QCPATHSELECTION );
  1341. cCompileRecentQCpaths->setEnabled(true);
  1342. bCompileQCRemoveFromList = new mxButton( wCompile, 2, 168, 160, 18, "Remove selected from list", IDC_COMPILE_REMOVEFROMLIST );
  1343. bCompileQCRemoveFromList->setEnabled(false);
  1344. bCompileQCWhenSelected = new mxButton( wCompile, 170, 168, 130, 18, "One-click compile [OFF]", IDC_COMPILE_SELECTEDTOGGLE );
  1345. bCompileQCWhenSelected->setEnabled(true);
  1346. mxToolTip::add (bCompileQCWhenSelected, "When enabled, selecting a QC in the list will start a recompile automatically.");
  1347. bCompileSelectedToggle = false;
  1348. int nButtonsLeft = 310;
  1349. int nButtonsTop = 22;
  1350. lblFullQCPath = new mxLabel( wCompile, nButtonsLeft, 2, 500, 18, "No QC script selected. To add a QC file, drag and drop it onto the viewport." );
  1351. bCompileQCCompile = new mxButton( wCompile, nButtonsLeft, nButtonsTop, 120, 24, "Recompile", IDC_COMPILE_CALLSTUDIOMDL );
  1352. bCompileQCCompile->setEnabled(false);
  1353. int nButtonsRight = 690;
  1354. bCompileQCLoadModel = new mxButton( wCompile, nButtonsRight, nButtonsTop, 100, 24, "Load in HLMV", IDC_COMPILE_LOADMODELFILE );
  1355. bCompileQCLoadModel->setEnabled(false);
  1356. bCompileQCShowCompileOutput = new mxButton( wCompile, nButtonsRight + 110, nButtonsTop, 100, 24, "Open full log file", IDC_COMPILE_OPENLOGFILE );
  1357. bCompileQCShowCompileOutput->setEnabled(false);
  1358. bCompileQCBrowseToQC = new mxButton( wCompile, nButtonsRight + 220, nButtonsTop, 100, 24, "Explore to QC", IDC_COMPILE_EXPLORETOQC );
  1359. bCompileQCBrowseToQC->setEnabled(false);
  1360. cCompileQCOutput = new mxListBox(wCompile, nButtonsLeft, 56, 700, 130);
  1361. lblCompileWarningOrError = new mxLabel( wCompile, nButtonsLeft, 168, 1000, 18, "" );
  1362. nCompileLastUpdateTick = GetTickCount();
  1363. }
  1364. void ControlPanel::UpdateQCPathPanel( bool bUpdateList /* = true */, int nForceSelection /* = -1 */ )
  1365. {
  1366. int nSelection = ( nForceSelection >= 0 ) ? nForceSelection : cCompileRecentQCpaths->getSelectedIndex();
  1367. if ( bUpdateList )
  1368. {
  1369. cCompileRecentQCpaths->removeAll();
  1370. FOR_EACH_VEC( g_QCPathRecords, i )
  1371. {
  1372. if ( i >= MAX_NUM_QCPATH_RECORDS )
  1373. break;
  1374. const char* szStatus = "";
  1375. if ( g_QCPathRecords[i].status == QCSTATUS_COMPILING )
  1376. {
  1377. szStatus = " --> compiling...";
  1378. }
  1379. else if (g_QCPathRecords[i].status == QCSTATUS_ERROR)
  1380. {
  1381. szStatus = "[ ERROR! ]";
  1382. }
  1383. else if (g_QCPathRecords[i].status == QCSTATUS_COMPLETE_WITH_WARNING)
  1384. {
  1385. szStatus = "[ warning ]";
  1386. }
  1387. else if (g_QCPathRecords[i].status == QCSTATUS_COMPLETE)
  1388. {
  1389. szStatus = "[ COMPLETE ]";
  1390. }
  1391. char szStatusAndName[256];
  1392. V_sprintf_safe( szStatusAndName, "%s %s", szStatus, g_QCPathRecords[i].szPrettyPath );
  1393. cCompileRecentQCpaths->add( szStatusAndName );
  1394. }
  1395. cCompileRecentQCpaths->select(nSelection);
  1396. }
  1397. bCompileQCRemoveFromList->setEnabled(false);
  1398. bCompileQCCompile->setEnabled(false);
  1399. bCompileQCShowCompileOutput->setEnabled(false);
  1400. bCompileQCBrowseToQC->setEnabled(false);
  1401. bCompileQCLoadModel->setEnabled(false);
  1402. if ( nSelection >= 0 && g_QCPathRecords.Count() > nSelection )
  1403. {
  1404. bCompileQCBrowseToQC->setEnabled(true);
  1405. lblFullQCPath->setLabel( g_QCPathRecords[nSelection].szAbsPath );
  1406. bCompileQCRemoveFromList->setEnabled(true);
  1407. lblCompileWarningOrError->setLabel( g_QCPathRecords[nSelection].szMostRecentWarningOrError );
  1408. if ( g_QCPathRecords[nSelection].status != QCSTATUS_COMPILING )
  1409. {
  1410. bCompileQCCompile->setEnabled(true);
  1411. if ( strlen(g_QCPathRecords[nSelection].szModelPath) > 0 )
  1412. {
  1413. bCompileQCLoadModel->setEnabled(true);
  1414. }
  1415. }
  1416. if ( g_QCPathRecords[nSelection].status != QCSTATUS_NOLOGFILE )
  1417. {
  1418. bCompileQCShowCompileOutput->setEnabled(true);
  1419. cCompileQCOutput->removeAll();
  1420. FILE *file = fopen( g_QCPathRecords[nSelection].szLogFilePath, "rt" );
  1421. if ( file )
  1422. {
  1423. char line[1024];
  1424. while ( fgets( line, 1024, file ) )
  1425. {
  1426. cCompileQCOutput->add( line );
  1427. }
  1428. }
  1429. if ( file )
  1430. fclose( file );
  1431. }
  1432. }
  1433. SaveCompileQCPathSettings();
  1434. }
  1435. void ControlPanel::UpdateBoneWeightInspect( void )
  1436. {
  1437. if ( g_viewerSettings.renderMode == RM_BONEWEIGHTS )
  1438. {
  1439. if (!g_pStudioModel)
  1440. return;
  1441. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  1442. if (hdr)
  1443. {
  1444. int nNumBones = hdr->numbones();
  1445. const mstudiobone_t *pbones = hdr->pBone( 0 );
  1446. char szWeightResult[255];
  1447. V_sprintf_safe( szWeightResult, "weights: " );
  1448. for ( int i=0; i<3; i++ )
  1449. {
  1450. int nIndex = g_BoneWeightInspectResults[i].index;
  1451. float flWeight = g_BoneWeightInspectResults[i].flweight;
  1452. if ( nIndex < nNumBones && flWeight > 0 )
  1453. {
  1454. V_sprintf_safe( szWeightResult, "%s %f [%s]", szWeightResult, flWeight, pbones[nIndex].pszName() );
  1455. }
  1456. }
  1457. lblBoneWeightInspectValues->setLabel( szWeightResult );
  1458. }
  1459. }
  1460. }
  1461. void ControlPanel::CompileTimerUpdate( void )
  1462. {
  1463. //update status of visible qcs
  1464. if ( (GetTickCount() - nCompileLastUpdateTick) < 1000 )
  1465. return;
  1466. nCompileLastUpdateTick = GetTickCount();
  1467. bool bNeedToRefreshList = false;
  1468. int nTopIndex = cCompileRecentQCpaths->getTopIndex();
  1469. for ( int i=0; i<11; i++ )
  1470. {
  1471. int nRecordIndex = nTopIndex + i;
  1472. if ( nRecordIndex < g_QCPathRecords.Count() )
  1473. {
  1474. if ( g_QCPathRecords[nRecordIndex].status == QCSTATUS_UNKNOWN || g_QCPathRecords[nRecordIndex].status == QCSTATUS_COMPILING )
  1475. {
  1476. // need to parse the log file for changes
  1477. FILE *file = fopen( g_QCPathRecords[nRecordIndex].szLogFilePath, "rt" );
  1478. if ( file )
  1479. {
  1480. bool bFoundWarning = false;
  1481. bool bFoundError = false;
  1482. char line[1024];
  1483. while ( fgets( line, 1024, file ) )
  1484. {
  1485. if ( !bFoundError && !bFoundWarning && V_stristr( line, "WARNING" ) )
  1486. {
  1487. V_strcpy_safe( g_QCPathRecords[nRecordIndex].szMostRecentWarningOrError, line );
  1488. bFoundWarning = true;
  1489. }
  1490. if ( !bFoundError && V_stristr( line, "ERROR" ) )
  1491. {
  1492. V_strcpy_safe( g_QCPathRecords[nRecordIndex].szMostRecentWarningOrError, line );
  1493. bFoundError = true;
  1494. }
  1495. if ( V_stristr( line, "OUTPUT MODEL: " ) )
  1496. {
  1497. char szTrimmedPath[1024];
  1498. V_StrRight( line, strlen(line) - strlen("OUTPUT MODEL: "), szTrimmedPath, sizeof(szTrimmedPath) );
  1499. V_FixSlashes( szTrimmedPath );
  1500. V_strcpy_safe( g_QCPathRecords[nRecordIndex].szModelPath, szTrimmedPath );
  1501. }
  1502. if ( V_stristr( line, "RESULT: SUCCESS" ) )
  1503. {
  1504. if ( !bFoundWarning )
  1505. V_strcpy_safe( g_QCPathRecords[nRecordIndex].szMostRecentWarningOrError, "Most recent compile finished successfully." );
  1506. g_QCPathRecords[nRecordIndex].status = bFoundWarning ? QCSTATUS_COMPLETE_WITH_WARNING : QCSTATUS_COMPLETE;
  1507. bNeedToRefreshList = true;
  1508. char szCurrent[256];
  1509. char szFinished[256];
  1510. V_FileBase( g_pStudioModel->GetFileName(), szCurrent, sizeof(szCurrent) );
  1511. V_FileBase( g_QCPathRecords[nRecordIndex].szModelPath, szFinished, sizeof(szFinished) );
  1512. if ( !V_strcmp( szCurrent, szFinished ) )
  1513. {
  1514. g_MDLViewer->Refresh();
  1515. }
  1516. break;
  1517. }
  1518. else if ( V_stristr( line, "RESULT: ERROR" ) )
  1519. {
  1520. g_QCPathRecords[nRecordIndex].status = QCSTATUS_ERROR;
  1521. bNeedToRefreshList = true;
  1522. break;
  1523. }
  1524. }
  1525. }
  1526. else
  1527. {
  1528. // there's no log file. don't retry unless recompiled
  1529. g_QCPathRecords[nRecordIndex].status = QCSTATUS_NOLOGFILE;
  1530. }
  1531. if ( file )
  1532. fclose( file );
  1533. }
  1534. }
  1535. }
  1536. if ( bNeedToRefreshList )
  1537. {
  1538. UpdateQCPathPanel();
  1539. }
  1540. }
  1541. void ControlPanel::CompileSelectedIndex( void )
  1542. {
  1543. int nSelection = cCompileRecentQCpaths->getSelectedIndex();
  1544. if ( nSelection >= 0 && g_QCPathRecords.Count() > nSelection && g_QCPathRecords[nSelection].status != QCSTATUS_COMPILING )
  1545. {
  1546. DeleteFile( TEXT(g_QCPathRecords[nSelection].szLogFilePath) );
  1547. bCompileQCCompile->setEnabled(false);
  1548. g_QCPathRecords[nSelection].status = QCSTATUS_COMPILING;
  1549. // unghhhh here we go
  1550. SECURITY_ATTRIBUTES sa;
  1551. sa.nLength = sizeof(sa);
  1552. sa.lpSecurityDescriptor = NULL;
  1553. sa.bInheritHandle = TRUE;
  1554. HANDLE h = CreateFile( TEXT(g_QCPathRecords[nSelection].szLogFilePath),
  1555. FILE_GENERIC_WRITE,
  1556. FILE_SHARE_WRITE | FILE_SHARE_READ,
  1557. &sa,
  1558. CREATE_NEW,
  1559. FILE_ATTRIBUTE_NORMAL,
  1560. NULL );
  1561. PROCESS_INFORMATION pi;
  1562. STARTUPINFO si;
  1563. BOOL ret = FALSE;
  1564. DWORD flags = CREATE_NO_WINDOW;
  1565. ZeroMemory( &pi, sizeof(PROCESS_INFORMATION) );
  1566. ZeroMemory( &si, sizeof(STARTUPINFO) );
  1567. si.cb = sizeof(STARTUPINFO);
  1568. si.dwFlags |= STARTF_USESTDHANDLES;
  1569. si.hStdInput = NULL;
  1570. si.hStdError = h;
  1571. si.hStdOutput = h;
  1572. char cmd[2048];
  1573. V_snprintf( cmd, sizeof(cmd), "studiomdl.exe -parsecompletion %s", g_QCPathRecords[nSelection].szAbsPath );
  1574. ret = CreateProcess( NULL, TEXT(cmd), NULL, NULL, TRUE, flags, NULL, TEXT(g_QCPathRecords[nSelection].szCWDPath), &si, &pi);
  1575. if ( ret )
  1576. {
  1577. CloseHandle(pi.hProcess);
  1578. CloseHandle(pi.hThread);
  1579. }
  1580. if ( h )
  1581. {
  1582. CloseHandle( h );
  1583. }
  1584. qcpathrecord_t temp = g_QCPathRecords[nSelection];
  1585. g_QCPathRecords.Remove(nSelection);
  1586. g_QCPathRecords.AddToHead(temp);
  1587. UpdateQCPathPanel( true, 0 );
  1588. }
  1589. }
  1590. void ControlPanel::AddQCRecordPath( const char* szPath, bool bCompileWhenLoaded /* = false */ )
  1591. {
  1592. if ( !V_stristr( szPath, ".qc" ) )
  1593. return;
  1594. FOR_EACH_VEC_BACK( g_QCPathRecords, i )
  1595. {
  1596. if ( g_QCPathRecords[i].DoesAbsPathMatch(szPath) )
  1597. {
  1598. g_QCPathRecords.Remove(i);
  1599. }
  1600. }
  1601. g_QCPathRecords[ g_QCPathRecords.AddToHead() ].InitFromAbsPath( szPath );
  1602. UpdateQCPathPanel( true, bCompileWhenLoaded ? 0 : -1 );
  1603. if ( bCompileWhenLoaded )
  1604. {
  1605. CompileSelectedIndex();
  1606. }
  1607. }
  1608. //-----------------------------------------------------------------------------
  1609. // Sets up the window dealing with render control
  1610. //-----------------------------------------------------------------------------
  1611. void ControlPanel::SetupRenderWindow( mxTab* pTab )
  1612. {
  1613. wRender = new mxWindow (this, 0, 0, 0, 0);
  1614. tab->add (wRender, "Render");
  1615. cRenderMode = new mxChoice (wRender, 5, 2, 100, 22, IDC_RENDERMODE);
  1616. cRenderMode->add ("Wireframe");
  1617. // cRenderMode->add ("Flatshaded");
  1618. cRenderMode->add ("Smoothshaded");
  1619. cRenderMode->add ("Textured");
  1620. cRenderMode->add ("BoneWeights");
  1621. cRenderMode->add ("BadVertexData");
  1622. cRenderMode->add ("UV Chart");
  1623. cRenderMode->add ("Co-LocatedVerts");
  1624. cRenderMode->select (2);
  1625. mxToolTip::add (cRenderMode, "Select Render Mode");
  1626. new mxLabel (wRender, 450, 103, 200, 18, "Inspect bone weights:");
  1627. cbBoneWeightInspectIndex = new mxChoice( wRender, 450, 120, 80, 20, IDC_BONEWEIGHTINDEX );
  1628. lblBoneWeightInspectValues = new mxLabel( wRender, 530, 120, 600, 20, "" );
  1629. for ( int i=0; i<32766; i++ )
  1630. {
  1631. char szNumber[16];
  1632. itoa( i, szNumber, 10 );
  1633. cbBoneWeightInspectIndex->add( szNumber );
  1634. }
  1635. cbGround = new mxCheckBox (wRender, 125, 5, 150, 20, "Ground (Ctrl-G)", IDC_GROUND);
  1636. cbGround->setEnabled( true );
  1637. cbMovement = new mxCheckBox (wRender, 125, 25, 150, 20, "Movement (Ctrl-M)", IDC_MOVEMENT);
  1638. cbMovement->setEnabled( true );
  1639. cbBackground = new mxCheckBox (wRender, 125, 45, 150, 20, "Background (Ctrl-B)", IDC_BACKGROUND);
  1640. cbBackground->setEnabled( true );
  1641. cbHitBoxes = new mxCheckBox (wRender, 125, 65, 150, 20, "Hit Boxes (Ctrl-H)", IDC_HITBOXES);
  1642. cbSequenceBoxes = new mxCheckBox (wRender, 125, 85, 150, 20, "Seq. Boxes", IDC_SEQUENCEBOXES);
  1643. cbShadow = new mxCheckBox (wRender, 125, 105, 150, 20, "Shadow (Ctrl-S)", IDC_SHADOW);
  1644. cbSoftwareSkin = new mxCheckBox (wRender, 125, 125, 150, 20, "Software Skin", IDC_SOFTWARESKIN);
  1645. cbSoftwareSkin->setEnabled( true );
  1646. cbOverbright2 = new mxCheckBox (wRender, 125, 145, 150, 20, "Enable Overbrightening", IDC_OVERBRIGHT2);
  1647. cbOverbright2->setEnabled( true );
  1648. cbOverbright2->setChecked( true );
  1649. setOverbright( true );
  1650. cbAttachments = new mxCheckBox (wRender, 5, 45, 120, 20, "Attachments (Ctrl-A)", IDC_ATTACHMENTS);
  1651. cbAttachments->setEnabled( true );
  1652. cbBones = new mxCheckBox (wRender, 5, 65, 120, 20, "Bones (Ctrl-O)", IDC_BONES);
  1653. cbNormals = new mxCheckBox (wRender, 5, 85, 120, 20, "Normals (Ctrl-N)", IDC_NORMALS);
  1654. cbNormals->setEnabled( true );
  1655. cbNormals->setChecked( false );
  1656. cbTangentFrame = new mxCheckBox( wRender, 5, 105, 120, 20, "Tangents (Ctrl-T)", IDC_TANGENTFRAME );
  1657. cbTangentFrame->setEnabled( true );
  1658. cbTangentFrame->setChecked( false );
  1659. cbOverlayWireframe = new mxCheckBox (wRender, 5, 125, 120, 20, "Wireframe (Ctrl-W)", IDC_OVERLAY_WIREFRAME);
  1660. cbOverlayWireframe->setEnabled( true );
  1661. cbOverlayWireframe->setChecked( false );
  1662. // cbParallaxMap = new mxCheckBox (wRender, 5, 125, 100, 20, "Parallax Mapping", IDC_PARALLAXMAP);
  1663. // cbParallaxMap->setEnabled( true );
  1664. // cbParallaxMap->setChecked( true );
  1665. cbSpecular = new mxCheckBox( wRender, 5, 145, 120, 20, "Specular", IDC_SPECULAR );
  1666. cbSpecular->setEnabled( true );
  1667. cbSpecular->setChecked( true );
  1668. cbNormalMap = new mxCheckBox( wRender, 5, 25, 100, 20, "Normal Mapping", IDC_NORMALMAP );
  1669. cbNormalMap->setEnabled( true );
  1670. cbNormalMap->setChecked( false );
  1671. cbDisplacementMap = new mxCheckBox( wRender, 275, 45, 150, 20, "Displacement (Ctrl-D)", IDC_DISPLACEMENTMAP );
  1672. cbDisplacementMap->setEnabled( true );
  1673. cbDisplacementMap->setChecked( true );
  1674. cbRunIK = new mxCheckBox (wRender, 275, 65, 150, 20, "Enable IK", IDC_RUNIK);
  1675. cbEnableHead = new mxCheckBox (wRender, 275, 85, 150, 20, "Head Turn", IDC_HEADTURN);
  1676. cbIllumPosition = new mxCheckBox (wRender, 275, 105, 150, 20, "Illum. Position", IDC_ILLUMPOSITION);
  1677. cbPlaySounds = new mxCheckBox (wRender, 275, 125, 150, 20, "Play Sounds", IDC_PLAYSOUNDS);
  1678. cbShowOriginAxis = new mxCheckBox (wRender, 275, 145, 150, 20, "Show Origin Axis", IDC_SHOWORIGINAXIS);
  1679. new mxLabel (wRender, 275, 170, 45, 18, "Axis Len:");
  1680. leOriginAxisLength = new mxSlider(wRender, 320, 165, 105, 22, IDC_ORIGINAXISLENGTH);
  1681. leOriginAxisLength->setRange( 1, 100 );
  1682. leOriginAxisLength->setValue( 10 );
  1683. new mxCheckBox (wRender, 275, 5, 150, 20, "Physics Model", IDC_PHYSICSMODEL);
  1684. cHighlightBone = new mxChoice (wRender, 275, 25, 150, 22, IDC_PHYSICSHIGHLIGHT);
  1685. cHighlightBone->add ("None");
  1686. cHighlightBone->select (0);
  1687. mxToolTip::add (cHighlightBone, "Select Physics Bone to highlight");
  1688. new mxLabel (wRender, 450, 29, 60, 18, "HitBox Set:");
  1689. cDrawHitBoxSet = new mxChoice (wRender, 510, 25, 90, 22, IDC_DRAWHITBOXSET);
  1690. cDrawHitBoxSet->add ("All");
  1691. cDrawHitBoxSet->select (0);
  1692. cDrawHitBoxSet->setEnabled( false );
  1693. new mxLabel (wRender, 450, 48, 60, 18, "HitBox:");
  1694. cDrawHitBoxNumber = new mxChoice (wRender, 510, 48, 90, 22, IDC_DRAWHITBOXNUMBER);
  1695. cDrawHitBoxNumber->setEnabled( false );
  1696. new mxLabel (wRender, 5, 170, 30, 18, "FOV:");
  1697. leFOV = new mxLineEdit(wRender, 35, 165, 30, 22, "65", IDC_RENDER_FOV);
  1698. cIncludedModels = new mxChoice( wRender, 450, 68, 250, 20, IDC_INCLUDEDMODELS );
  1699. cIncludedModels->add( "Included Models" );
  1700. cIncludedModels->add( "---------------" );
  1701. cIncludedModels->setEnabled( false );
  1702. }
  1703. //-----------------------------------------------------------------------------
  1704. // Updates control sizes for the window dealing with sequence control
  1705. //-----------------------------------------------------------------------------
  1706. void ControlPanel::updateSequenceSizes( int tabWidth )
  1707. {
  1708. int extraWidth = (tabWidth - 640);
  1709. int extraPoseParamWidth = 0;
  1710. if ( extraWidth > 200 )
  1711. {
  1712. extraPoseParamWidth = extraWidth - 200;
  1713. extraWidth = 200;
  1714. }
  1715. if ( extraWidth < 0 )
  1716. {
  1717. extraWidth = 0;
  1718. }
  1719. extraPoseParamWidth = clamp( extraPoseParamWidth, 0, 200 );
  1720. for ( int i = 0; i < MAX_SEQUENCES; i++ )
  1721. {
  1722. cSequence[i]->setBounds( 5, 5 + i * 22, 200 + extraWidth, 22 + 500 ); // mxChoice adds 500 internally for the dropdown in constructor, not in setBounds
  1723. slSequence[i]->setBounds( 208 + extraWidth, 5 + i * 22, 80, 18 );
  1724. rbFrameSelection[i]->setBounds( 300 + extraWidth, 5 + i * 22, 35, 22 );
  1725. leSequenceFilter[i]->setBounds( 520 + extraWidth + 96 + extraPoseParamWidth + 90, 5 + i * 22, 100, 18 );
  1726. }
  1727. laFilters->setBounds( 520 + extraWidth + 96 + extraPoseParamWidth + 5, 5, 80, 18 );
  1728. laGroundSpeed->setBounds( 208 + extraWidth, 5, 80, 18 );
  1729. for ( int i = 0; i < NUM_POSEPARAMETERS; i++ )
  1730. {
  1731. int x, y;
  1732. x = 334;
  1733. y = 2 + (i % 8) * 17;
  1734. cPoseParameter[i]->setBounds( 520 + extraWidth, y, 96 + extraPoseParamWidth, 22 + 500 ); // mxChoice adds 500 internally for the dropdown in constructor, not in setBounds
  1735. slPoseParameter[i]->setBounds( x + extraWidth, y, 140, 16 );
  1736. lePoseParameter[i]->setBounds( x + 146 + extraWidth, y, 40, 16 );
  1737. }
  1738. }
  1739. //-----------------------------------------------------------------------------
  1740. // Sets up the window dealing with sequence control
  1741. //-----------------------------------------------------------------------------
  1742. void ControlPanel::SetupSequenceWindow( mxTab* pTab )
  1743. {
  1744. mxWindow *wSequence = new mxWindow (this, 0, 0, 0, 0);
  1745. tab->add (wSequence, "Sequence");
  1746. for ( int i = 0; i < MAX_SEQUENCES; i++ )
  1747. {
  1748. cSequence[i] = new mxChoice (wSequence, 5, 5 + i * 22, 200, 22, IDC_SEQUENCE0+i);
  1749. mxToolTip::add (cSequence[i], "Select Sequence");
  1750. slSequence[i] = new mxSlider (wSequence, 208, 5 + i * 22, 80, 18, IDC_SEQUENCESCALE0+i);
  1751. slSequence[i]->setRange (0, 1.0, 100);
  1752. slSequence[i]->setValue (0.0);
  1753. rbFrameSelection[i] = new mxRadioButton (wSequence, 300, 5 + i * 22, 35, 22, "", IDC_FRAMESELECTION0+i, i == 0);
  1754. leSequenceFilter[i] = new mxLineEdit( wSequence, 0, 0, 0, 0, "", IDC_SEQUENCEFILTER0+i);
  1755. }
  1756. laFilters = new mxLabel( wSequence, 0, 0, 0, 0, "Sequence Filters" );
  1757. slSequence[0]->setVisible( false );
  1758. laGroundSpeed = new mxLabel( wSequence, 208, 5, 80, 18, "" );
  1759. for ( int i = 0; i < NUM_POSEPARAMETERS; i++ )
  1760. {
  1761. int x, y;
  1762. x = 334;
  1763. y = 2 + (i % 8) * 17;
  1764. cPoseParameter[i] = new mxChoice (wSequence, 520, y, 96, 22, IDC_POSEPARAMETER+i);
  1765. cPoseParameter[i]->setVisible( false );
  1766. slPoseParameter[i] = new mxSlider (wSequence, x, y, 140, 16, IDC_POSEPARAMETER_SCALE+i);
  1767. slPoseParameter[i]->setRange (0.0, 1.0, 1000);
  1768. mxToolTip::add (slPoseParameter[i], "Parameter");
  1769. slPoseParameter[i]->setVisible( false );
  1770. lePoseParameter[i] = new mxLineEdit ( wSequence, x + 146, y, 40, 16, "X", IDC_POSEPARAMETER_VALUE+i );
  1771. lePoseParameter[i]->setVisible( false );
  1772. }
  1773. slSpeedScale = new mxSlider (wSequence, 5, 115, 200, 18, IDC_SPEEDSCALE);
  1774. slSpeedScale->setRange (0, 1.0, 100);
  1775. slSpeedScale->setValue (1.0);
  1776. mxToolTip::add (slSpeedScale, "Speed Scale");
  1777. laFPS = new mxLabel (wSequence, 208, 115, 128, 22, "" );
  1778. new mxCheckBox (wSequence, 5, 142, 150, 20, "Blend Sequence Changes", IDC_BLENDSEQUENCECHANGES);
  1779. new mxButton( wSequence, 155, 142, 80, 20, "Blend Now", IDC_BLENDNOW );
  1780. laBlendAmount = new mxLabel( wSequence, 240, 142, 60, 20, "" );
  1781. slBlendTime = new mxSlider( wSequence, 308, 142, 200, 18, IDC_BLENDTIME );
  1782. slBlendTime->setRange( 0, 1.0, 100 );
  1783. slBlendTime->setValue( DEFAULT_BLEND_TIME );
  1784. laBlendTime = new mxLabel( wSequence, 540, 142, 80, 22, "" );
  1785. new mxLabel (wSequence, 5, 170, 90, 18, "Activity modifiers:");
  1786. cActivityModifiers = new mxChoice (wSequence, 105, 166, 350, 22, IDC_ACTIVITY_MODIFIERS);
  1787. new mxCheckBox (wSequence, 460, 166, 350, 22, "Animate weapons", IDC_ANIMATEWEAPONS);
  1788. }
  1789. //-----------------------------------------------------------------------------
  1790. // Sets up the window dealing with body control
  1791. //-----------------------------------------------------------------------------
  1792. void ControlPanel::SetupBodyWindow( mxTab* pTab )
  1793. {
  1794. mxWindow *wBody = new mxWindow (this, 0, 0, 0, 0);
  1795. pTab->add (wBody, "Model");
  1796. cBodypart = new mxChoice (wBody, 5, 5, 100, 22, IDC_BODYPART);
  1797. mxToolTip::add (cBodypart, "Choose a bodypart");
  1798. cSubmodel = new mxChoice (wBody, 110, 5, 100, 22, IDC_SUBMODEL);
  1799. mxToolTip::add (cSubmodel, "Choose a submodel of current bodypart");
  1800. cBodyGroupPreset = new mxChoice (wBody, 110, 55, 100, 22, IDC_BODYGROUPPRESET);
  1801. mxToolTip::add (cBodyGroupPreset, "Choose a bodygroup preset");
  1802. cController = new mxChoice (wBody, 5, 30, 100, 22, IDC_CONTROLLER);
  1803. mxToolTip::add (cController, "Choose a bone controller");
  1804. slController = new mxSlider (wBody, 105, 32, 100, 18, IDC_CONTROLLERVALUE);
  1805. slController->setRange (0, 255);
  1806. mxToolTip::add (slController, "Change current bone controller value");
  1807. lModelInfo1 = new mxLabel (wBody, 220, 5, 120, 80, "No Model.");
  1808. lModelInfo2 = new mxLabel (wBody, 340, 5, 120, 130, "");
  1809. cSkin = new mxChoice (wBody, 5, 55, 100, 22, IDC_SKINS);
  1810. mxToolTip::add (cSkin, "Choose a skin family");
  1811. new mxLabel (wBody, 5, 170, 90, 18, "Materials used:");
  1812. cMaterials = new mxChoice (wBody, 105, 166, 350, 22, IDC_MATERIALS);
  1813. mxToolTip::add (cMaterials, "Select material for UV Chart view");
  1814. lModelInfo3 = new mxLabel (wBody, 220, 100, 120, 22, "");
  1815. lModelInfo4 = new mxLabel (wBody, 220, 118, 120, 22, "");
  1816. setTransparent( false );
  1817. cbAutoLOD = new mxCheckBox (wBody, 5, 80, 100, 20, "Auto LOD", IDC_AUTOLOD);
  1818. cbAutoLOD->setEnabled( true );
  1819. cLODChoice = new mxChoice( wBody, 5, 101, 100, 22, IDC_LODCHOICE);
  1820. mxToolTip::add (cLODChoice, "Select model LOD to render");
  1821. new mxLabel (wBody, 5, 126, 60, 18, "LOD Switch:");
  1822. leLODSwitch = new mxLineEdit(wBody, 70, 126, 35, 22, "", IDC_LODSWITCH);
  1823. new mxLabel (wBody, 5, 151, 60, 18, "LOD Metric:" );
  1824. lLODMetric = new mxLabel( wBody, 70, 151, 35, 22, "" );
  1825. new mxLabel( wBody, 505, 5, 100, 18, "VMTs Loaded:" );
  1826. cMessageList = new mxListBox( wBody, 500, 25, 540, 160, IDC_MESSAGES );
  1827. cMessageList->add ("None");
  1828. cMessageList->select (1);
  1829. mxToolTip::add (cMessageList, "Materials (VMT files) this model has loaded");
  1830. m_bExploreToMaterial = new mxButton( wBody, 500, 172, 100, 20, "Explore to material", IDC_EXPLORE_TO_VMT );
  1831. new mxLabel( wBody, 785, 5, 100, 18, "Shader:" );
  1832. cShaderUsed = new mxListBox( wBody, 830, 3, 210, 28, IDC_SHADERS );
  1833. cShaderUsed->add ("Select material to show shader");
  1834. cShaderUsed->select (0);
  1835. mxToolTip::add (cShaderUsed, "Shader Used");
  1836. m_bRandomizeWeaponModuleSlots = new mxButton( wBody, 390, 140, 100, 20, "Roll bodygroups", IDC_ROLL_BODYGROUPS );
  1837. mxToolTip::add (m_bRandomizeWeaponModuleSlots, "Randomize model bodygroup selections");
  1838. }
  1839. //-----------------------------------------------------------------------------
  1840. // Sets up the window dealing with flexes
  1841. //-----------------------------------------------------------------------------
  1842. #define FLEX_DROPDOWN_WIDTH 90
  1843. #define FLEX_SLIDER_WIDTH 100
  1844. #define FLEX_ROWS_OF_SLIDERS 8
  1845. void ControlPanel::SetupFlexWindow( mxTab* pTab )
  1846. {
  1847. mxWindow *wFlex = new mxWindow (this, 0, 0, 0, 0);
  1848. pTab->add (wFlex, "Flex");
  1849. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  1850. {
  1851. int w = (i / FLEX_ROWS_OF_SLIDERS) * (FLEX_SLIDER_WIDTH + FLEX_DROPDOWN_WIDTH + 4) + 5;
  1852. int h = (i % FLEX_ROWS_OF_SLIDERS) * 20 + 5;
  1853. cFlex[i] = new mxChoice (wFlex, w, h, FLEX_DROPDOWN_WIDTH, 22, IDC_FLEX + i);
  1854. mxToolTip::add (cFlex[i], "Select Flex");
  1855. slFlexScale[i] = new mxSlider (wFlex, w + FLEX_DROPDOWN_WIDTH, h, FLEX_SLIDER_WIDTH, 18, IDC_FLEXSCALE + i);
  1856. slFlexScale[i]->setRange (0, 1.0);
  1857. slFlexScale[i]->setValue (0);
  1858. mxToolTip::add (slFlexScale[i], "Flex Scale");
  1859. }
  1860. {
  1861. int h = FLEX_ROWS_OF_SLIDERS * 20 + 5;
  1862. new mxButton( wFlex, 5, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Reset", IDC_FLEXDEFAULTS );
  1863. int w = ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
  1864. new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Random", IDC_FLEXRANDOM );
  1865. w += ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
  1866. new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "Zero", IDC_FLEXZERO );
  1867. w += ( FLEX_DROPDOWN_WIDTH + 4 ) + 5;
  1868. new mxButton( wFlex, w, h + 1, FLEX_DROPDOWN_WIDTH - 2, 18, "One", IDC_FLEXONE );
  1869. }
  1870. }
  1871. //-----------------------------------------------------------------------------
  1872. // Sets up the window dealing with physics
  1873. //-----------------------------------------------------------------------------
  1874. void ControlPanel::SetupPhysicsWindow( mxTab* pTab )
  1875. {
  1876. // Physics Window
  1877. mxWindow *wPhysics = new mxWindow (this, 0, 0, 0, 0);
  1878. pTab->add (wPhysics, "Physics");
  1879. new mxLabel (wPhysics, 5, 33, 30, 18, "Mass");
  1880. leMass = new mxLineEdit(wPhysics, 35, 30, 70, 22, "", IDC_PHYS_MASS);
  1881. cPhysicsBone = new mxChoice (wPhysics, 5, 5, 345, 22, IDC_PHYS_BONE);
  1882. cPhysicsBone->add ("None");
  1883. cPhysicsBone->select (0);
  1884. new mxCheckBox (wPhysics, 5, 55, 100, 20, "Highlight", IDC_PHYSICSMODEL);
  1885. int x = 5;
  1886. int y = 80;
  1887. rbConstraintAxis[0] = new mxRadioButton (wPhysics, x, y, 35, 22, "X", IDC_PHYS_CON_AXIS_X, true);
  1888. rbConstraintAxis[1] = new mxRadioButton (wPhysics, x+35, y, 35, 22, "Y", IDC_PHYS_CON_AXIS_Y);
  1889. rbConstraintAxis[2] = new mxRadioButton (wPhysics, x+70, y, 35, 22, "Z", IDC_PHYS_CON_AXIS_Z);
  1890. setPhysicsAxis( 0 );
  1891. y += 25;
  1892. new mxLabel (wPhysics, x, y, 45, 18, "Friction");
  1893. slPhysicsFriction = new mxSlider (wPhysics, x+50, y, 180, 18, IDC_PHYS_CON_FRICTION);
  1894. slPhysicsFriction->setRange (0, 1000.0, 1000);
  1895. slPhysicsFriction->setValue (0);
  1896. slPhysicsFriction->setSteps( 1, 1 );
  1897. lPhysicsFriction = new mxLabel (wPhysics, x+230, y, 30, 18, "0");
  1898. x = 135;
  1899. y = 30;
  1900. new mxLabel (wPhysics, 115, y, 30, 18, "Min");
  1901. slPhysicsConMin = new mxSlider (wPhysics, x, y, 180, 18, IDC_PHYS_CON_MIN);
  1902. slPhysicsConMin->setRange (-180, 180.0, 360);
  1903. slPhysicsConMin->setValue (-90);
  1904. slPhysicsConMin->setSteps( 1, 1 );
  1905. lPhysicsConMin = new mxLabel (wPhysics, x+180, y, 30, 18, "-90");
  1906. y += 25;
  1907. new mxLabel (wPhysics, 115, y, 30, 18, "Max");
  1908. slPhysicsConMax = new mxSlider (wPhysics, x, y, 180, 18, IDC_PHYS_CON_MAX);
  1909. slPhysicsConMax->setRange (-180.0, 180.0, 360);
  1910. slPhysicsConMax->setValue (90.0);
  1911. slPhysicsConMax->setSteps( 1, 1 );
  1912. lPhysicsConMax = new mxLabel (wPhysics, x+180, y, 30, 18, "90");
  1913. y += 25;
  1914. new mxLabel (wPhysics, 115, y, 30, 18, "Test");
  1915. slPhysicsConTest = new mxSlider (wPhysics, x, y, 55, 18, IDC_PHYS_CON_TEST);
  1916. slPhysicsConTest->setRange (0, 1.0, 100);
  1917. slPhysicsConTest->setValue (0);
  1918. cbLinked = new mxCheckBox (wPhysics, 200, y, 50, 20, "Link", IDC_PHYS_CON_LINK_LIMITS);
  1919. mxToolTip::add (cbLinked, "Link mins/maxs to be symmetric");
  1920. new mxButton (wPhysics, 250, y, 80, 22, "Generate QC", IDC_PHYS_QCFILE);
  1921. x += 220;
  1922. y = 5;
  1923. new mxLabel (wPhysics, x, y, 55, 18, "Mass Bias");
  1924. new mxLabel (wPhysics, x, y+25, 55, 18, "Inertia");
  1925. new mxLabel (wPhysics, x, y+50, 55, 18, "Damping");
  1926. new mxLabel (wPhysics, x, y+75, 55, 18, "Rot Damp");
  1927. new mxLabel (wPhysics, x, y+100+3, 55, 18, "Material");
  1928. x += 55;
  1929. slPhysicsParamMassBias = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_MASSBIAS );
  1930. slPhysicsParamMassBias->setRange (0, 10.0, 100);
  1931. slPhysicsParamMassBias->setValue (1.0);
  1932. slPhysicsParamMassBias->setSteps( 1, 1 );
  1933. lPhysicsParamMassBias = new mxLabel (wPhysics, x+80, y, 30, 18, "1.0");
  1934. y += 25;
  1935. slPhysicsParamInertia = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_INERTIA );
  1936. slPhysicsParamInertia->setRange (0, 10.0, 100);
  1937. slPhysicsParamInertia->setValue (1.0);
  1938. slPhysicsParamInertia->setSteps( 1, 1 );
  1939. lPhysicsParamInertia = new mxLabel (wPhysics, x+80, y, 30, 18, "1.0");
  1940. y += 25;
  1941. slPhysicsParamDamping = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_DAMPING );
  1942. slPhysicsParamDamping->setRange (0, 1.0, 100);
  1943. slPhysicsParamDamping->setValue (0.01);
  1944. slPhysicsParamDamping->setSteps( 1, 1 );
  1945. lPhysicsParamDamping = new mxLabel (wPhysics, x+80, y, 30, 18, "0.5");
  1946. y += 25;
  1947. slPhysicsParamRotDamping = new mxSlider (wPhysics, x, y, 76, 18, IDC_PHYS_P_ROT_DAMPING );
  1948. slPhysicsParamRotDamping->setRange (0, 10.0, 200);
  1949. slPhysicsParamRotDamping->setValue (0.2);
  1950. slPhysicsParamRotDamping->setSteps( 1, 1 );
  1951. lPhysicsParamRotDamping = new mxLabel (wPhysics, x+80, y, 30, 18, "0.2");
  1952. y += 25;
  1953. lPhysicsMaterial = new mxLabel( wPhysics, x, y+3, 110, 18, "default" );
  1954. }
  1955. void ControlPanel::SetupSoftbodyWindow( mxTab* pTab )
  1956. {
  1957. mxWindow *wSoftbody = new mxWindow( this, 0, 0, 0, 0 );
  1958. pTab->add( wSoftbody, "Cloth" );
  1959. leSoftbodyIterations = new mxLabel( wSoftbody, 5, 33, 90, 18, "Iterations" );
  1960. slSoftbodyIterations = new mxSlider( wSoftbody, 100, 33, 100, 18, IDC_SOFT_ITERATIONS );
  1961. slSoftbodyIterations->setRange( 1, 101, 100 );
  1962. slSoftbodyIterations->setValue( 1.0f );
  1963. slSoftbodyIterations->setSteps( 1, 5 );
  1964. new mxLabel( wSoftbody, 210, 33, 60, 18, "Wind Yaw" );
  1965. slSoftbodyWindYaw = new mxSlider( wSoftbody, 285, 33, 105, 18, IDC_SOFT_WIND_YAW );
  1966. slSoftbodyWindYaw->setRange( 0, 360, 360 );
  1967. slSoftbodyWindYaw->setValue( 0 );
  1968. slSoftbodyWindYaw->setSteps( 1, 5 );
  1969. new mxLabel( wSoftbody, 405, 33, 80, 18, "Wind Strength" );
  1970. slSoftbodyWindStrength = new mxSlider( wSoftbody, 480, 33, 100, 18, IDC_SOFT_WIND_STRENGTH );
  1971. slSoftbodyWindStrength->setRange( 0, 1, 100 );
  1972. slSoftbodyWindStrength->setValue( 0 );
  1973. slSoftbodyWindStrength->setSteps( 1, 5 );
  1974. cSoftbodyCtrl = new mxChoice( wSoftbody, 5, 5, 345, 22, IDC_SOFT_BONE );
  1975. cSoftbodyCtrl->add( "None" );
  1976. cSoftbodyCtrl->select( 0 );
  1977. cbSoftbodySimulate = new mxCheckBox( wSoftbody, 5, 55, 80, 20, "Simulate", IDC_SOFT_SIMULATE );
  1978. new mxLabel( wSoftbody, 100, 55, 70, 18, "2D Stretch" );
  1979. slSoftbodySurfaceStretch = new mxSlider( wSoftbody, 170, 55, 100, 20, IDC_SOFT_SURFACE_STRETCH);
  1980. slSoftbodySurfaceStretch->setRange( 0, 3, 300 );
  1981. slSoftbodySurfaceStretch->setValue( 0 );
  1982. slSoftbodySurfaceStretch->setSteps( 1, 10 );
  1983. new mxLabel( wSoftbody, 270, 55, 70, 18, "1D Stretch" );
  1984. slSoftbodyThreadStretch = new mxSlider( wSoftbody, 340, 55, 100, 20, IDC_SOFT_THREAD_STRETCH );
  1985. slSoftbodyThreadStretch->setRange( 0, 3, 300 );
  1986. slSoftbodyThreadStretch->setValue( 0 );
  1987. slSoftbodyThreadStretch->setSteps( 1, 10 );
  1988. cbSoftbodyPolygons = new mxCheckBox( wSoftbody, 5, 80, 80, 20, "Polygons", IDC_SOFT_SHOW_POLYGONS );
  1989. cbSoftbodyEdges = new mxCheckBox( wSoftbody, 100, 80, 80, 20, "Edges", IDC_SOFT_SHOW_EDGES );
  1990. cbSoftbodyBases = new mxCheckBox( wSoftbody, 200, 80, 80, 20, "Bases", IDC_SOFT_SHOW_BASES );
  1991. cbSoftbodyWind = new mxCheckBox( wSoftbody, 300, 80, 80, 20, "Wind", IDC_SOFT_SHOW_WIND );
  1992. cbSoftbodyIndices = new mxCheckBox( wSoftbody, 400, 80, 80, 20, "Indices", IDC_SOFT_SHOW_INDICES );
  1993. int x = 5;
  1994. int y = 105;
  1995. rbSoftbodyAxis[ 0 ] = new mxRadioButton( wSoftbody, x, y, 35, 22, "X", IDC_SOFT_CON_AXIS_X, true );
  1996. rbSoftbodyAxis[ 1 ] = new mxRadioButton( wSoftbody, x + 35, y, 35, 22, "Y", IDC_SOFT_CON_AXIS_Y );
  1997. rbSoftbodyAxis[ 2 ] = new mxRadioButton( wSoftbody, x + 70, y, 35, 22, "Z", IDC_SOFT_CON_AXIS_Z );
  1998. setSoftbodyAxis( 0 );
  1999. y += 25;
  2000. }
  2001. //-----------------------------------------------------------------------------
  2002. // Sets up the window dealing with ik rules
  2003. //-----------------------------------------------------------------------------
  2004. void ControlPanel::SetupIKRuleWindow( mxTab *pTab )
  2005. {
  2006. mxWindow *wIKRule = new mxWindow( this, 0, 0, 0, 0 );
  2007. pTab->add( wIKRule, "IKRule" );
  2008. new mxLabel( wIKRule, 5, 5, 80, 20, "Chain:" );
  2009. cIKChain = new mxChoice( wIKRule, 90, 5, 50, 20, IDC_IKRULE_CHAIN );
  2010. cIKChain->add( "lfoot" );
  2011. cIKChain->add( "rfoot" );
  2012. cIKChain->add( "lhand" );
  2013. cIKChain->add( "rhand" );
  2014. cIKChain->select( 0 );
  2015. mxToolTip::add( cIKChain, "Select IK Chain" );
  2016. new mxLabel( wIKRule, 145, 5, 80, 20, "Type:" );
  2017. cIKType = new mxChoice( wIKRule, 230, 5, 80, 20, IDC_IKRULE_CHOICE );
  2018. cIKType->add( "footstep" );
  2019. cIKType->add( "touch" );
  2020. cIKType->add( "release" );
  2021. cIKType->add( "attachment" );
  2022. cIKType->add( "unlatch" );
  2023. cIKType->select( 0 );
  2024. mxToolTip::add( cIKType, "Select IK Type" );
  2025. lIKTouch = new mxLabel( wIKRule, 315, 5, 80, 20, "Bone:" );
  2026. cIKTouch = new mxChoice( wIKRule, 400, 5, 200, 20, IDC_IKRULE_TOUCH );
  2027. PopulateBoneList( cIKTouch );
  2028. mxToolTip::add( cIKTouch, "Select Touched Bone" );
  2029. lIKAttachment = new mxLabel( wIKRule, 315, 5, 80, 20, "Attachment:" );
  2030. leIKAttachment = new mxLineEdit( wIKRule, 400, 5, 80, 20, "", IDC_IKRULE_ATTACHMENT );
  2031. cbIKRangeToggle = new mxCheckBox( wIKRule, 5, 30, 80, 20, "Range", IDC_IKRULE_RANGE_TOGGLE );
  2032. mxToolTip::add( cbIKRangeToggle, "Toggle range option" );
  2033. new mxButton( wIKRule, 90, 30, 30, 20, "start", IDC_IKRULE_RANGE_START_NOW );
  2034. leIKRangeStart = new mxLineEdit2( wIKRule, 120, 30, 35, 20, "..", IDC_IKRULE_RANGE_START );
  2035. new mxButton( wIKRule, 160, 30, 30, 20, "peak", IDC_IKRULE_RANGE_PEAK_NOW );
  2036. leIKRangePeak = new mxLineEdit2( wIKRule, 190, 30, 35, 20, "..", IDC_IKRULE_RANGE_PEAK );
  2037. new mxButton( wIKRule, 230, 30, 30, 20, "tail", IDC_IKRULE_RANGE_TAIL_NOW );
  2038. leIKRangeTail = new mxLineEdit2( wIKRule, 260, 30, 35, 20, "..", IDC_IKRULE_RANGE_TAIL );
  2039. new mxButton( wIKRule, 300, 30, 30, 20, "end", IDC_IKRULE_RANGE_END_NOW );
  2040. leIKRangeEnd = new mxLineEdit2( wIKRule, 330, 30, 35, 20, "..", IDC_IKRULE_RANGE_END );
  2041. cbIKContactToggle = new mxCheckBox( wIKRule, 5, 55, 80, 20, "Contact", IDC_IKRULE_CONTACT_TOGGLE );
  2042. mxToolTip::add( cbIKContactToggle, "Toggle contact option" );
  2043. new mxButton( wIKRule, 90, 55, 30, 20, "frame", IDC_IKRULE_CONTACT_FRAME_NOW );
  2044. leIKContactFrame = new mxLineEdit2( wIKRule, 120, 55, 35, 20, "", IDC_IKRULE_CONTACT_FRAME );
  2045. new mxLabel( wIKRule, 5, 80, 80, 20, "Transform using:" );
  2046. cIKUsing = new mxChoice( wIKRule, 90, 80, 80, 20, IDC_IKRULE_USING );
  2047. cIKUsing->add( "neither" );
  2048. cIKUsing->add( "source" );
  2049. cIKUsing->add( "sequence" );
  2050. cIKUsing->select( 0 );
  2051. mxToolTip::add( cIKUsing, "Choose Transform To Use" );
  2052. new mxLabel( wIKRule, 5, 105, 80, 20, "QC String:" );
  2053. leIKQCString = new mxLineEdit2( wIKRule, 90, 105, 500, 20, "", IDC_IKRULE_QC_STRING );
  2054. UpdateIKRuleWindow();
  2055. }
  2056. //-----------------------------------------------------------------------------
  2057. // Sets up the window dealing with events
  2058. //-----------------------------------------------------------------------------
  2059. void ControlPanel::SetupEventWindow( mxTab *pTab )
  2060. {
  2061. mxWindow *wEvents = new mxWindow( this, 0, 0, 0, 0 );
  2062. pTab->add( wEvents, "Events" );
  2063. new mxLabel( wEvents, 5, 5, 80, 20, "Sound:" );
  2064. mxButton *bSoundFrameNow = new mxButton( wEvents, 90, 5, 30, 20, "frame", IDC_EVENT_SOUND_FRAME_NOW );
  2065. mxToolTip::add( bSoundFrameNow, "Set sound start at the current frame" );
  2066. leEventSoundFrame = new mxLineEdit2( wEvents, 120, 5, 35, 20, "0", IDC_EVENT_SOUND_FRAME );
  2067. lbEventSoundName = new mxListBox( wEvents, 160, 5, 300, 170, IDC_EVENT_SOUND_NAME );
  2068. PopulateSoundNameList( lbEventSoundName );
  2069. mxToolTip::add( lbEventSoundName, "Select Sound Name" );
  2070. new mxLabel( wEvents, 5, 170, 80, 20, "QC String:" );
  2071. leEventQCString = new mxLineEdit2( wEvents, 90, 170, 450, 20, "", IDC_EVENT_QC_STRING );
  2072. BuildEventQCString();
  2073. lEventSequence = new mxLabel( wEvents, 460, 5, 300, 20, "" );
  2074. lbEventHistory = new mxListBox( wEvents, 460, 25, 300, 150 );
  2075. m_lastEventCycle = 0.0f;
  2076. }
  2077. //-----------------------------------------------------------------------------
  2078. // Sets up the window dealing with bone control
  2079. //-----------------------------------------------------------------------------
  2080. void ControlPanel::SetupBoneControlWindow( mxTab* pTab )
  2081. {
  2082. m_pBoneWindow = new CBoneControlWindow(this);
  2083. pTab->add (m_pBoneWindow, "Bones");
  2084. m_pBoneWindow->Init();
  2085. }
  2086. void ControlPanel::SetupAttachmentsWindow( mxTab *pTab )
  2087. {
  2088. m_pAttachmentsWindow = new CAttachmentsWindow(this);
  2089. pTab->add( m_pAttachmentsWindow, "Attachments" );
  2090. m_pAttachmentsWindow->Init();
  2091. }
  2092. int ControlPanel::GetCurrentHitboxSet( void )
  2093. {
  2094. return m_pBoneWindow ? m_pBoneWindow->GetHitboxSet() : 0;
  2095. }
  2096. ControlPanel::~ControlPanel()
  2097. {
  2098. g_ControlPanel = NULL;
  2099. }
  2100. void ControlPanel::OnDelete()
  2101. {
  2102. // for some reason, the destructor only gets called from mx when breakpoints are set,
  2103. // so to be safe, clear the pointer (possibly twice)
  2104. g_ControlPanel = NULL;
  2105. }
  2106. void ControlPanel::BuildEventQCString()
  2107. {
  2108. if ( g_ControlPanel == NULL )
  2109. return;
  2110. char qcstr[ 256 ];
  2111. Q_strcpy( qcstr, "{ event AE_CL_PLAYSOUND " );
  2112. Q_strcat( qcstr, leEventSoundFrame->getLabel(), sizeof(qcstr) );
  2113. Q_strcat( qcstr, " \"", sizeof(qcstr) );
  2114. int i = lbEventSoundName->getSelectedIndex();
  2115. Q_strcat( qcstr, lbEventSoundName->getItemText( i ), sizeof(qcstr) );
  2116. Q_strcat( qcstr, "\" }", sizeof(qcstr) );
  2117. leEventQCString->setText( qcstr );
  2118. }
  2119. void ControlPanel::BuildIKRuleQCString()
  2120. {
  2121. if ( g_ControlPanel == NULL )
  2122. return;
  2123. char qcstr[ 256 ];
  2124. Q_strcpy( qcstr, "ikrule " );
  2125. Q_strcat( qcstr, cIKChain->getLabel(), sizeof(qcstr) );
  2126. Q_strcat( qcstr, " ", sizeof(qcstr) );
  2127. const char *pType = cIKType->getLabel();
  2128. Q_strcat( qcstr, pType, sizeof(qcstr) );
  2129. if ( Q_strcmp( pType, "touch" ) == 0 )
  2130. {
  2131. Q_strcat( qcstr, " \"", sizeof(qcstr) );
  2132. if ( cIKTouch->getSelectedIndex() > 0 )
  2133. {
  2134. Q_strcat( qcstr, cIKTouch->getLabel(), sizeof(qcstr) );
  2135. }
  2136. Q_strcat( qcstr, "\"", sizeof(qcstr) );
  2137. }
  2138. else if ( Q_strcmp( pType, "attachment" ) == 0 )
  2139. {
  2140. Q_strcat( qcstr, " \"", sizeof(qcstr) );
  2141. Q_strcat( qcstr, leIKAttachment->getLabel(), sizeof(qcstr) );
  2142. Q_strcat( qcstr, "\"", sizeof(qcstr) );
  2143. }
  2144. if ( cbIKRangeToggle->isChecked() )
  2145. {
  2146. Q_strcat( qcstr, " range ", sizeof(qcstr) );
  2147. char str[ 20 ];
  2148. leIKRangeStart->getText( str, sizeof( str ) );
  2149. Q_strcat( qcstr, str, sizeof(qcstr) );
  2150. Q_strcat( qcstr, " ", sizeof(qcstr) );
  2151. leIKRangePeak->getText( str, sizeof( str ) );
  2152. Q_strcat( qcstr, str, sizeof(qcstr) );
  2153. Q_strcat( qcstr, " ", sizeof(qcstr) );
  2154. leIKRangeTail->getText( str, sizeof( str ) );
  2155. Q_strcat( qcstr, str, sizeof(qcstr) );
  2156. Q_strcat( qcstr, " ", sizeof(qcstr) );
  2157. leIKRangeEnd->getText( str, sizeof( str ) );
  2158. Q_strcat( qcstr, str, sizeof(qcstr) );
  2159. }
  2160. if ( cbIKContactToggle->isChecked() )
  2161. {
  2162. Q_strcat( qcstr, " contact ", sizeof(qcstr) );
  2163. char str[ 20 ];
  2164. leIKContactFrame->getText( str, sizeof( str ) );
  2165. Q_strcat( qcstr, str, sizeof(qcstr) );
  2166. }
  2167. int nUsing = cIKUsing->getSelectedIndex();
  2168. if ( nUsing > 0 )
  2169. {
  2170. if ( nUsing == 1 ) // source
  2171. {
  2172. Q_strcat( qcstr, " usesource", sizeof(qcstr) );
  2173. }
  2174. else if ( nUsing == 2 ) // sequence
  2175. {
  2176. Q_strcat( qcstr, " usesequence", sizeof(qcstr) );
  2177. }
  2178. }
  2179. leIKQCString->setText( qcstr );
  2180. }
  2181. void ControlPanel::UpdateIKRuleWindow()
  2182. {
  2183. const char *pIKType = cIKType->getLabel();
  2184. bool bIsTouch = Q_strcmp( pIKType, "touch" ) == 0;
  2185. bool bIsAttachment = Q_strcmp( pIKType, "attachment" ) == 0;
  2186. lIKTouch->setVisible( bIsTouch );
  2187. cIKTouch->setVisible( bIsTouch );
  2188. lIKAttachment->setVisible( bIsAttachment );
  2189. leIKAttachment->setVisible( bIsAttachment );
  2190. BuildIKRuleQCString();
  2191. }
  2192. int
  2193. ControlPanel::handleEvent (mxEvent *event)
  2194. {
  2195. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  2196. if ( !g_ControlPanel )
  2197. return 1;
  2198. if ( event->event == mxEvent::Size )
  2199. {
  2200. tab->setBounds( 0, 0, event->width, max( 0, event->height - 20 ) );
  2201. updateSequenceSizes( event->width );
  2202. return 1;
  2203. }
  2204. if ( event->event == mxEvent::KeyDown )
  2205. {
  2206. if ( tab->getSelectedIndex() == 4 )
  2207. {
  2208. handlePhysicsKey( event );
  2209. }
  2210. if (event->action >= IDC_POSEPARAMETER_VALUE && event->action < IDC_POSEPARAMETER_VALUE + NUM_POSEPARAMETERS)
  2211. {
  2212. int index = event->action - IDC_POSEPARAMETER_VALUE;
  2213. int poseparam = cPoseParameter[index]->getSelectedIndex();
  2214. float value = atof( lePoseParameter[index]->getLabel() );
  2215. setBlend( poseparam, value );
  2216. slPoseParameter[index]->setValue( g_pStudioModel->GetPoseParameter( poseparam ) );
  2217. return 1;
  2218. }
  2219. switch (event->key)
  2220. {
  2221. case 27:
  2222. if (!getParent ()) // fullscreen mode ?
  2223. mx::quit ();
  2224. break;
  2225. case '1':
  2226. case '2':
  2227. case '3':
  2228. case '4':
  2229. // don't do quick keys when in edit mode
  2230. if ( tab->getSelectedIndex() < TAB_PHYSICS )
  2231. {
  2232. g_viewerSettings.renderMode = event->key - '1';
  2233. }
  2234. break;
  2235. case '-':
  2236. g_viewerSettings.speedScale -= 0.1f;
  2237. if (g_viewerSettings.speedScale < 0.0f)
  2238. g_viewerSettings.speedScale = 0.0f;
  2239. break;
  2240. case '+':
  2241. g_viewerSettings.speedScale += 0.1f;
  2242. if (g_viewerSettings.speedScale > 5.0f)
  2243. g_viewerSettings.speedScale = 5.0f;
  2244. break;
  2245. default:
  2246. return 0;
  2247. }
  2248. return 1;
  2249. }
  2250. switch (event->action)
  2251. {
  2252. case IDC_TAB:
  2253. {
  2254. int tabIndex = tab->getSelectedIndex();
  2255. // g_viewerSettings.highlightBone = -1;
  2256. g_viewerSettings.highlightHitbox = -1;
  2257. g_viewerSettings.showTexture = (tabIndex == TAB_FLEX) ? true : false;
  2258. g_viewerSettings.showPhysicsPreview = (tabIndex == TAB_PHYSICS) ? true : false;
  2259. setHighlightBone(cHighlightBone->getSelectedIndex());
  2260. if (tabIndex == TAB_PHYSICS)
  2261. {
  2262. setupPhysicsBone(cPhysicsBone->getSelectedIndex());
  2263. }
  2264. if (tabIndex == TAB_BONE)
  2265. {
  2266. m_pBoneWindow->OnTabSelected();
  2267. }
  2268. if ( tabIndex == TAB_ATTACHMENT )
  2269. {
  2270. m_pAttachmentsWindow->OnTabSelected();
  2271. }
  2272. else
  2273. {
  2274. m_pAttachmentsWindow->OnTabUnselected();
  2275. }
  2276. }
  2277. break;
  2278. case IDC_RENDERMODE:
  2279. {
  2280. int index = cRenderMode->getSelectedIndex();
  2281. if (index >= 0)
  2282. {
  2283. setRenderMode (index);
  2284. }
  2285. }
  2286. break;
  2287. case IDC_PHYSICSHIGHLIGHT:
  2288. {
  2289. int index = cHighlightBone->getSelectedIndex();
  2290. setHighlightBone(index);
  2291. }
  2292. break;
  2293. case IDC_RENDER_FOV:
  2294. {
  2295. mxLineEdit *pLineEdit = ((mxLineEdit *) event->widget);
  2296. const char *pText = pLineEdit->getLabel();
  2297. float val = atof( pText );
  2298. g_viewerSettings.fov = val;
  2299. break;
  2300. }
  2301. case IDC_ORIGINAXISLENGTH:
  2302. {
  2303. g_viewerSettings.originAxisLength = reinterpret_cast< mxSlider * >( event->widget )->getValue();
  2304. break;
  2305. }
  2306. case IDC_MATERIALVARMATS:
  2307. {
  2308. //when a material is selected, populate the material param list with all the parameters of this material
  2309. cMaterialParamList->removeAll();
  2310. //hide slider controls
  2311. slMaterialParamMatrixSliderRotation->setVisible(false);
  2312. slMaterialParamMatrixSliderScaleX->setVisible(false);
  2313. slMaterialParamMatrixSliderScaleY->setVisible(false);
  2314. slMaterialParamMatrixSliderTranslateX->setVisible(false);
  2315. slMaterialParamMatrixSliderTranslateY->setVisible(false);
  2316. lblMatrixRotation->setVisible(false);
  2317. lblMatrixScaleX->setVisible(false);
  2318. lblMatrixScaleY->setVisible(false);
  2319. lblMatrixTranslateX->setVisible(false);
  2320. lblMatrixTranslateY->setVisible(false);
  2321. slMaterialParamFloat->setVisible(false);
  2322. leMaterialParamText->setVisible(false);
  2323. bMaterialParamColor->setVisible(false);
  2324. bMaterialParamLoad->setVisible(false);
  2325. bMaterialParamCopyToClipboard->setVisible(false);
  2326. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2327. if ( pStudioR )
  2328. {
  2329. IMaterial *pMaterials[128];
  2330. g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  2331. IMaterial *pSelectedMaterial = pMaterials[ cMaterialList->getSelectedIndex() ];
  2332. if ( g_OnlyEditMaterialsThatWantToBeEdited )
  2333. {
  2334. bool bLocalHideOthersInHLMV = false;
  2335. pSelectedMaterial->FindVar("$hlmvallowedit", &bLocalHideOthersInHLMV, false);
  2336. if ( !bLocalHideOthersInHLMV )
  2337. break;
  2338. }
  2339. if ( !pSelectedMaterial->IsErrorMaterial() )
  2340. {
  2341. bMaterialParamLoad->setVisible( true );
  2342. bMaterialParamCopyToClipboard->setVisible(true);
  2343. int nShaderParams = pSelectedMaterial->ShaderParamCount();
  2344. IMaterialVar **pMatVars = pSelectedMaterial->GetShaderParams();
  2345. for (int n=0; n<nShaderParams; n++ )
  2346. {
  2347. IMaterialVar *pThisVar = pMatVars[n];
  2348. if (pThisVar->IsDefined() )
  2349. {
  2350. cMaterialParamList->add( pThisVar->GetName() );
  2351. }
  2352. }
  2353. }
  2354. }
  2355. break;
  2356. }
  2357. case IDC_MATERIALVARPARAMS:
  2358. {
  2359. // when a material parameter is selected, populate the lineedit control with the string value of that parameter
  2360. leMaterialParamText->clear();
  2361. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2362. if ( pStudioR )
  2363. {
  2364. IMaterial *pMaterials[128];
  2365. //int nMaterials =
  2366. g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  2367. bool bHideInHLMV = false;
  2368. if ( g_OnlyEditMaterialsThatWantToBeEdited )
  2369. {
  2370. bool bLocalHideOthersInHLMV = false;
  2371. pMaterials[cMaterialList->getSelectedIndex()]->FindVar("$hlmvallowedit", &bLocalHideOthersInHLMV, false);
  2372. if ( !bLocalHideOthersInHLMV )
  2373. bHideInHLMV = true;
  2374. }
  2375. leMaterialParamText->setVisible(!bHideInHLMV);
  2376. bMaterialParamColor->setVisible(!bHideInHLMV);
  2377. #ifdef MATERIAL_SCRIPT_SAVE_FEATURE
  2378. bMaterialParamSave->setVisible(!bHideInHLMV);
  2379. leMaterialParamSavePath->setVisible(!bHideInHLMV);
  2380. cbMaterialParamSaveRun->setVisible(!bHideInHLMV);
  2381. leMaterialParamSaveRun->setVisible(!bHideInHLMV);
  2382. #endif
  2383. bMaterialParamLoad->setVisible(!bHideInHLMV);
  2384. if ( !pMaterials[ cMaterialList->getSelectedIndex() ]->IsErrorMaterial() )
  2385. {
  2386. bool bFoundParam = false;
  2387. IMaterialVar *pThisVar = pMaterials[cMaterialList->getSelectedIndex()]->FindVar( cMaterialParamList->getItemText(cMaterialParamList->getSelectedIndex()), &bFoundParam, false );
  2388. if (bFoundParam)
  2389. {
  2390. //hide type-specific controls
  2391. bMaterialParamColor->setVisible(false);
  2392. slMaterialParamMatrixSliderRotation->setVisible(false);
  2393. slMaterialParamMatrixSliderScaleX->setVisible(false);
  2394. slMaterialParamMatrixSliderScaleY->setVisible(false);
  2395. slMaterialParamMatrixSliderTranslateX->setVisible(false);
  2396. slMaterialParamMatrixSliderTranslateY->setVisible(false);
  2397. lblMatrixRotation->setVisible(false);
  2398. lblMatrixScaleX->setVisible(false);
  2399. lblMatrixScaleY->setVisible(false);
  2400. lblMatrixTranslateX->setVisible(false);
  2401. lblMatrixTranslateY->setVisible(false);
  2402. slMaterialParamFloat->setVisible(false);
  2403. switch ( pThisVar->GetType() )
  2404. {
  2405. case MATERIAL_VAR_TYPE_FLOAT:
  2406. {
  2407. slMaterialParamFloat->setVisible(true);
  2408. if ( pThisVar->GetFloatValue() > slMaterialParamFloat->getMaxValue() || pThisVar->GetFloatValue() < slMaterialParamFloat->getMinValue() )
  2409. {
  2410. slMaterialParamFloat->setRange( -pThisVar->GetFloatValue() * 2.0, pThisVar->GetFloatValue() * 2.0 );
  2411. }
  2412. else
  2413. {
  2414. slMaterialParamFloat->setRange( -1.0, 1.0 );
  2415. }
  2416. slMaterialParamFloat->setValue( pThisVar->GetFloatValue() );
  2417. leMaterialParamText->setText( pThisVar->GetStringValue() );
  2418. }
  2419. break;
  2420. case MATERIAL_VAR_TYPE_VECTOR:
  2421. {
  2422. bMaterialParamColor->setVisible(true);
  2423. leMaterialParamText->setText( pThisVar->GetStringValue() );
  2424. }
  2425. break;
  2426. case MATERIAL_VAR_TYPE_MATRIX:
  2427. {
  2428. slMaterialParamMatrixSliderRotation->setVisible(true);
  2429. slMaterialParamMatrixSliderScaleX->setVisible(true);
  2430. slMaterialParamMatrixSliderScaleY->setVisible(true);
  2431. slMaterialParamMatrixSliderTranslateX->setVisible(true);
  2432. slMaterialParamMatrixSliderTranslateY->setVisible(true);
  2433. lblMatrixRotation->setVisible(true);
  2434. lblMatrixScaleX->setVisible(true);
  2435. lblMatrixScaleY->setVisible(true);
  2436. lblMatrixTranslateX->setVisible(true);
  2437. lblMatrixTranslateY->setVisible(true);
  2438. VMatrix mat = pThisVar->GetMatrixValue();
  2439. Vector tempScale = mat.GetScale();
  2440. Vector tempTrans = mat.GetTranslation();
  2441. QAngle tempAngle;
  2442. MatrixToAngles( mat, tempAngle );
  2443. slMaterialParamMatrixSliderScaleX->setValue( tempScale.x );
  2444. slMaterialParamMatrixSliderScaleY->setValue( tempScale.y );
  2445. slMaterialParamMatrixSliderTranslateX->setValue( tempTrans.x );
  2446. slMaterialParamMatrixSliderTranslateY->setValue( tempTrans.y );
  2447. slMaterialParamMatrixSliderRotation->setValue( tempAngle.y );
  2448. char temp[255];
  2449. V_snprintf( temp, sizeof(temp), " scale %f %f translate %f %f rotate %f", tempScale.x, tempScale.y, tempTrans.x, tempTrans.y, tempAngle.y );
  2450. leMaterialParamText->setText( temp );
  2451. }
  2452. break;
  2453. default:
  2454. {
  2455. leMaterialParamText->setText( pThisVar->GetStringValue() );
  2456. }
  2457. break;
  2458. }
  2459. }
  2460. }
  2461. }
  2462. break;
  2463. }
  2464. case IDC_MATVAREDIT:
  2465. {
  2466. char str[ 255 ];
  2467. leMaterialParamText->getText( str, sizeof( str ) );
  2468. if ( V_strcmp( str, "" ) )
  2469. {
  2470. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2471. if ( pStudioR )
  2472. {
  2473. IMaterial *pMaterials[128];
  2474. g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  2475. if ( !pMaterials[ cMaterialList->getSelectedIndex() ]->IsErrorMaterial() )
  2476. {
  2477. bool bFoundParam = false;
  2478. IMaterialVar *pThisVar = pMaterials[cMaterialList->getSelectedIndex()]->FindVar( cMaterialParamList->getItemText(cMaterialParamList->getSelectedIndex()), &bFoundParam, false );
  2479. if (bFoundParam)
  2480. {
  2481. pThisVar->SetValueAutodetectType( str );
  2482. pMaterials[cMaterialList->getSelectedIndex()]->RefreshPreservingMaterialVars();
  2483. }
  2484. //if affect all loaded materials is checked, loop through other materials and attempt the same change
  2485. if ( cbMaterialParamMultiEdit->isChecked() )
  2486. {
  2487. for ( int i=0; i<cMaterialList->getItemCount(); i++ )
  2488. {
  2489. if ( i == cMaterialList->getSelectedIndex() )
  2490. continue;
  2491. if ( g_OnlyEditMaterialsThatWantToBeEdited )
  2492. {
  2493. bool bLocalHideOthersInHLMV = false;
  2494. pMaterials[i]->FindVar("$hlmvallowedit", &bLocalHideOthersInHLMV, false);
  2495. if ( !bLocalHideOthersInHLMV )
  2496. continue;
  2497. }
  2498. IMaterialVar *pThisVar = pMaterials[i]->FindVar( cMaterialParamList->getItemText(cMaterialParamList->getSelectedIndex()), &bFoundParam, false );
  2499. if (bFoundParam)
  2500. {
  2501. pThisVar->SetValueAutodetectType( str );
  2502. pMaterials[i]->RefreshPreservingMaterialVars();
  2503. }
  2504. }
  2505. }
  2506. }
  2507. }
  2508. }
  2509. break;
  2510. }
  2511. case IDC_MATVARCOLORPICKER:
  2512. {
  2513. char str[255];
  2514. char str2[255];
  2515. leMaterialParamText->getText(str,sizeof(str));
  2516. V_StrSubst( str, "[ ", "", str2, sizeof(str2) );
  2517. V_StrSubst( str2, " ]", "", str, sizeof(str) );
  2518. CUtlVector< char * > vectorComponents;
  2519. V_SplitString(str, " ", vectorComponents );
  2520. int r = atoi(vectorComponents[0]);
  2521. int g = atoi(vectorComponents[1]);
  2522. int b = atoi(vectorComponents[2]);
  2523. if (mxChooseColor (this, &r, &g, &b))
  2524. {
  2525. char result[255];
  2526. V_snprintf(result, sizeof(result), "[ %i %i %i ]", r, g, b );
  2527. leMaterialParamText->setText(result);
  2528. }
  2529. break;
  2530. }
  2531. case IDC_MATVARCOPYTOCLIPBOARD:
  2532. {
  2533. int nMatSelection = cMaterialList->getSelectedIndex();
  2534. if ( nMatSelection < 0 || !strcmp( cMaterialList->getItemText(nMatSelection), "None" ) )
  2535. {
  2536. mxMessageBox (this, "No material selected.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2537. break;
  2538. }
  2539. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2540. if ( !pStudioR )
  2541. {
  2542. mxMessageBox (this, "No loaded model.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2543. break;
  2544. }
  2545. IMaterial *pMaterials[128];
  2546. g_pStudioRender->GetMaterialList(pStudioR, ARRAYSIZE(pMaterials), &pMaterials[0]);
  2547. IMaterial *pSelectedMaterial = pMaterials[nMatSelection];
  2548. if (pSelectedMaterial->IsErrorMaterial())
  2549. {
  2550. mxMessageBox(this, "Selected material is ErrorMaterial.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2551. break;
  2552. }
  2553. // write material property KVs to clipboard
  2554. CTextBuffer out;
  2555. out.WriteText( pSelectedMaterial->GetShaderName() );
  2556. out.WriteText( "\r\n{\r\n" );
  2557. IMaterialVar **pMatVars = pSelectedMaterial->GetShaderParams();
  2558. for ( int n = 0; n < pSelectedMaterial->ShaderParamCount(); n++ )
  2559. {
  2560. IMaterialVar *pThisVar = pMatVars[n];
  2561. if ( pThisVar->IsDefined() )
  2562. {
  2563. char tmp[512];
  2564. sprintf( tmp, "\t\"%s\" \"%s\"\r\n", pThisVar->GetName(), pThisVar->GetStringValue() );
  2565. out.WriteText( tmp );
  2566. }
  2567. }
  2568. out.WriteText( "\r\n}\r\n" );
  2569. if ( out.GetSize() )
  2570. {
  2571. char *pOutput = new char[out.GetSize()];
  2572. memcpy( pOutput, out.GetData(), out.GetSize() );
  2573. Sys_CopyStringToClipboard( pOutput );
  2574. mxMessageBox (this, "Material properties copied to clipboard.", g_appTitle, MX_MB_OK | MX_MB_INFORMATION);
  2575. }
  2576. break;
  2577. }
  2578. case IDC_MATVARLOAD:
  2579. {
  2580. int nMatSelection = cMaterialList->getSelectedIndex();
  2581. if ( nMatSelection < 0 || !strcmp( cMaterialList->getItemText(nMatSelection), "None" ) )
  2582. {
  2583. mxMessageBox (this, "Can't replace VMT parameters: No material selected.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2584. break;
  2585. }
  2586. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2587. if ( !pStudioR )
  2588. {
  2589. mxMessageBox (this, "Can't replace VMT parameters: No loaded model.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2590. break;
  2591. }
  2592. IMaterial *pMaterials[128];
  2593. g_pStudioRender->GetMaterialList(pStudioR, ARRAYSIZE(pMaterials), &pMaterials[0]);
  2594. IMaterial *pSelectedMaterial = pMaterials[nMatSelection];
  2595. if (pSelectedMaterial->IsErrorMaterial())
  2596. {
  2597. mxMessageBox(this, "Can't replace VMT parameters: Selected material is ErrorMaterial.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2598. break;
  2599. }
  2600. const char *pFilePath = mxGetOpenFileName (this, 0, "*.vmt");
  2601. if (pFilePath)
  2602. {
  2603. KeyValues *kvLoadedFromFile = new KeyValues( pSelectedMaterial->GetShaderName() );
  2604. if ( kvLoadedFromFile->LoadFromFile( g_pFullFileSystem, pFilePath ) )
  2605. {
  2606. cMaterialList->deselect(nMatSelection);
  2607. cMaterialParamList->removeAll();
  2608. //hide slider controls
  2609. slMaterialParamMatrixSliderRotation->setVisible(false);
  2610. slMaterialParamMatrixSliderScaleX->setVisible(false);
  2611. slMaterialParamMatrixSliderScaleY->setVisible(false);
  2612. slMaterialParamMatrixSliderTranslateX->setVisible(false);
  2613. slMaterialParamMatrixSliderTranslateY->setVisible(false);
  2614. lblMatrixRotation->setVisible(false);
  2615. lblMatrixScaleX->setVisible(false);
  2616. lblMatrixScaleY->setVisible(false);
  2617. lblMatrixTranslateX->setVisible(false);
  2618. lblMatrixTranslateY->setVisible(false);
  2619. slMaterialParamFloat->setVisible(false);
  2620. leMaterialParamText->setVisible(false);
  2621. bMaterialParamColor->setVisible(false);
  2622. bMaterialParamLoad->setVisible(false);
  2623. KeyValues *kv = new KeyValues(pSelectedMaterial->GetShaderName());
  2624. IMaterialVar **pMatVars = pSelectedMaterial->GetShaderParams();
  2625. for (int n = 0; n < pSelectedMaterial->ShaderParamCount(); n++)
  2626. {
  2627. IMaterialVar *pThisVar = pMatVars[n];
  2628. if (pThisVar->IsDefined())
  2629. kv->SetString(pThisVar->GetName(), pThisVar->GetStringValue());
  2630. }
  2631. kv->MergeFrom( kvLoadedFromFile, KeyValues::MERGE_KV_UPDATE );
  2632. pSelectedMaterial->SetShaderAndParams( kv );
  2633. pSelectedMaterial->Refresh();
  2634. if (cbMaterialParamMultiEdit->isChecked())
  2635. {
  2636. for (int i = 0; i < cMaterialList->getItemCount(); i++)
  2637. {
  2638. if (i == cMaterialList->getSelectedIndex())
  2639. continue;
  2640. if ( g_OnlyEditMaterialsThatWantToBeEdited )
  2641. {
  2642. bool bLocalHideOthersInHLMV = false;
  2643. pMaterials[i]->FindVar("$hlmvallowedit", &bLocalHideOthersInHLMV, false);
  2644. if ( !bLocalHideOthersInHLMV )
  2645. continue;
  2646. }
  2647. pSelectedMaterial = pMaterials[i];
  2648. KeyValues *kv = new KeyValues(pSelectedMaterial->GetShaderName());
  2649. IMaterialVar **pMatVars = pSelectedMaterial->GetShaderParams();
  2650. for (int n = 0; n < pSelectedMaterial->ShaderParamCount(); n++)
  2651. {
  2652. IMaterialVar *pThisVar = pMatVars[n];
  2653. if (pThisVar->IsDefined())
  2654. kv->SetString(pThisVar->GetName(), pThisVar->GetStringValue());
  2655. }
  2656. kv->MergeFrom(kvLoadedFromFile, KeyValues::MERGE_KV_UPDATE);
  2657. pSelectedMaterial->SetShaderAndParams(kv);
  2658. pSelectedMaterial->Refresh();
  2659. if ( kv )
  2660. delete kv;
  2661. }
  2662. }
  2663. if ( kv )
  2664. delete kv;
  2665. if ( kvLoadedFromFile )
  2666. delete kvLoadedFromFile;
  2667. }
  2668. else
  2669. {
  2670. mxMessageBox(this, "Failed to load vmt file.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2671. break;
  2672. }
  2673. }
  2674. }
  2675. #ifdef MATERIAL_SCRIPT_SAVE_FEATURE
  2676. case IDC_MATVARSAVE:
  2677. {
  2678. int nMatSelection = cMaterialList->getSelectedIndex();
  2679. if ( nMatSelection < 0 || !strcmp( cMaterialList->getItemText(nMatSelection), "None" ) )
  2680. {
  2681. mxMessageBox (this, "Error saving VMT keyvalues: No material selected.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2682. break;
  2683. }
  2684. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2685. if ( !pStudioR )
  2686. {
  2687. mxMessageBox (this, "Error saving VMT keyvalues: No loaded model.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2688. break;
  2689. }
  2690. IMaterial *pMaterials[128];
  2691. g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  2692. IMaterial *pSelectedMaterial = pMaterials[nMatSelection];
  2693. if ( pSelectedMaterial->IsErrorMaterial() )
  2694. {
  2695. mxMessageBox (this, "Error saving VMT keyvalues: Material is ErrorMaterial.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2696. break;
  2697. }
  2698. KeyValues *kv = new KeyValues( pSelectedMaterial->GetShaderName() );
  2699. IMaterialVar **pMatVars = pSelectedMaterial->GetShaderParams();
  2700. for (int n=0; n<pSelectedMaterial->ShaderParamCount(); n++ )
  2701. {
  2702. IMaterialVar *pThisVar = pMatVars[n];
  2703. if (pThisVar->IsDefined() )
  2704. kv->SetString( pThisVar->GetName(), pThisVar->GetStringValue() );
  2705. }
  2706. char szVmtPath[255];
  2707. leMaterialParamSavePath->getText( szVmtPath, sizeof(szVmtPath) );
  2708. strcat( szVmtPath, ".vmt" );
  2709. if ( !strcmp( szVmtPath, ".vmt" ) )
  2710. {
  2711. mxMessageBox (this, "Error saving VMT keyvalues: no output filename.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2712. break;
  2713. }
  2714. if ( !kv->SaveToFile( g_pFullFileSystem, szVmtPath, "MOD" ) )
  2715. {
  2716. mxMessageBox (this, "Error saving VMT keyvalues.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  2717. break;
  2718. }
  2719. if ( cbMaterialParamSaveRun->isChecked() )
  2720. {
  2721. char szExecuteStr[512];
  2722. leMaterialParamSaveRun->getText( szExecuteStr, sizeof(szExecuteStr) );
  2723. if ( szExecuteStr[0] != '\0' )
  2724. {
  2725. char fullpath[ 512 ];
  2726. g_pFullFileSystem->RelativePathToFullPath( szExecuteStr, "GAME", fullpath, sizeof( fullpath ) );
  2727. system( fullpath );
  2728. }
  2729. }
  2730. break;
  2731. }
  2732. #endif
  2733. case IDC_MATVARSLIDERMATRIX:
  2734. {
  2735. char temp[255];
  2736. V_snprintf( temp, sizeof(temp), " scale %f %f translate %f %f rotate %f",
  2737. slMaterialParamMatrixSliderScaleX->getValue(), slMaterialParamMatrixSliderScaleY->getValue(),
  2738. slMaterialParamMatrixSliderTranslateX->getValue(), slMaterialParamMatrixSliderTranslateY->getValue(),
  2739. slMaterialParamMatrixSliderRotation->getValue() );
  2740. leMaterialParamText->setText(temp);
  2741. break;
  2742. }
  2743. case IDC_MATVARSLIDERFLOAT:
  2744. {
  2745. char temp[255];
  2746. V_snprintf( temp, sizeof(temp), "%f", slMaterialParamFloat->getValue() );
  2747. leMaterialParamText->setText(temp);
  2748. break;
  2749. }
  2750. case IDC_LODCHOICE:
  2751. {
  2752. int index = cLODChoice->getSelectedIndex();
  2753. if( index >= 0 )
  2754. {
  2755. setLOD( index, false, false );
  2756. }
  2757. break;
  2758. }
  2759. case IDC_LODSWITCH:
  2760. {
  2761. mxLineEdit *pLineEdit = ((mxLineEdit *) event->widget);
  2762. const char *pText = pLineEdit->getLabel();
  2763. float val = atof( pText );
  2764. g_pStudioModel->SetLODSwitchValue( g_viewerSettings.lod, val );
  2765. break;
  2766. }
  2767. case IDC_BONEWEIGHTINDEX:
  2768. {
  2769. g_BoneWeightInspectVert = cbBoneWeightInspectIndex->getSelectedIndex();
  2770. break;
  2771. }
  2772. case IDC_AUTOLOD:
  2773. setAutoLOD (((mxCheckBox *) event->widget)->isChecked());
  2774. break;
  2775. case IDC_SOFTWARESKIN:
  2776. setSoftwareSkin(((mxCheckBox *) event->widget)->isChecked());
  2777. break;
  2778. case IDC_OVERBRIGHT2:
  2779. setOverbright(((mxCheckBox *) event->widget)->isChecked());
  2780. break;
  2781. case IDC_GROUND:
  2782. setShowGround (((mxCheckBox *) event->widget)->isChecked());
  2783. break;
  2784. case IDC_MOVEMENT:
  2785. setShowMovement (((mxCheckBox *) event->widget)->isChecked());
  2786. break;
  2787. case IDC_BACKGROUND:
  2788. setShowBackground (((mxCheckBox *) event->widget)->isChecked());
  2789. break;
  2790. case IDC_HITBOXES:
  2791. if ( g_pStudioModel->GetStudioHdr() == NULL )
  2792. ((mxCheckBox *) event->widget)->setChecked( false );
  2793. g_viewerSettings.showHitBoxes = ((mxCheckBox *) event->widget)->isChecked();
  2794. cDrawHitBoxSet->select( 0 );
  2795. cDrawHitBoxNumber->select( 0 );
  2796. g_viewerSettings.showHitBoxSet = -1;
  2797. g_viewerSettings.showHitBoxNumber = -1;
  2798. cDrawHitBoxSet->setEnabled( g_viewerSettings.showHitBoxes );
  2799. cDrawHitBoxNumber->setEnabled( g_viewerSettings.showHitBoxes && g_viewerSettings.showHitBoxSet != -1 );
  2800. break;
  2801. case IDC_SEQUENCEBOXES:
  2802. g_viewerSettings.showSequenceBoxes = ((mxCheckBox *) event->widget)->isChecked();
  2803. break;
  2804. case IDC_SHADOW:
  2805. g_viewerSettings.showShadow = ((mxCheckBox *) event->widget)->isChecked();
  2806. break;
  2807. case IDC_ILLUMPOSITION:
  2808. g_viewerSettings.showIllumPosition = ((mxCheckBox *) event->widget)->isChecked();
  2809. break;
  2810. case IDC_RUNIK:
  2811. g_viewerSettings.enableIK = ((mxCheckBox *) event->widget)->isChecked();
  2812. g_viewerSettings.enableTargetIK = ((mxCheckBox *) event->widget)->isChecked();
  2813. break;
  2814. case IDC_HEADTURN:
  2815. g_pStudioModel->SetSolveHeadTurn( ((mxCheckBox *) event->widget)->isChecked() ? 1 : 0 );
  2816. break;
  2817. case IDC_PHYSICSMODEL:
  2818. g_viewerSettings.showPhysicsModel = ((mxCheckBox *) event->widget)->isChecked();
  2819. break;
  2820. case IDC_BONES:
  2821. g_viewerSettings.showBones = ((mxCheckBox *) event->widget)->isChecked();
  2822. break;
  2823. case IDC_PLAYSOUNDS:
  2824. g_viewerSettings.playSounds = ((mxCheckBox *) event->widget)->isChecked();
  2825. break;
  2826. case IDC_NORMALMAP:
  2827. g_viewerSettings.enableNormalMapping = ((mxCheckBox *) event->widget)->isChecked();
  2828. break;
  2829. case IDC_DISPLACEMENTMAP:
  2830. g_viewerSettings.enableDisplacementMapping = ((mxCheckBox *) event->widget)->isChecked();
  2831. break;
  2832. // case IDC_PARALLAXMAP:
  2833. // g_viewerSettings.enableParallaxMapping = ((mxCheckBox *) event->widget)->isChecked();
  2834. // break;
  2835. case IDC_SPECULAR:
  2836. g_viewerSettings.enableSpecular = ((mxCheckBox *) event->widget)->isChecked();
  2837. break;
  2838. case IDC_NORMALS:
  2839. g_viewerSettings.showNormals = ((mxCheckBox *) event->widget)->isChecked();
  2840. break;
  2841. case IDC_TANGENTFRAME:
  2842. g_viewerSettings.showTangentFrame = ((mxCheckBox *) event->widget)->isChecked();
  2843. break;
  2844. case IDC_OVERLAY_WIREFRAME:
  2845. g_viewerSettings.overlayWireframe = ((mxCheckBox *) event->widget)->isChecked();
  2846. break;
  2847. case IDC_ATTACHMENTS:
  2848. g_viewerSettings.showAttachments = ((mxCheckBox *) event->widget)->isChecked();
  2849. break;
  2850. case IDC_SHOWORIGINAXIS:
  2851. setShowOriginAxis (((mxCheckBox *) event->widget)->isChecked());
  2852. break;
  2853. case IDC_MESSAGES:
  2854. {
  2855. int index = cMessageList->getSelectedIndex();
  2856. if (index >= 0)
  2857. {
  2858. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  2859. if ( pStudioR )
  2860. {
  2861. IMaterial *pMaterials[128];
  2862. g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  2863. cShaderUsed->removeAll();
  2864. if ( pMaterials[index]->IsErrorMaterial() )
  2865. {
  2866. cShaderUsed->add( "*** ERROR *** Can't load VMT");
  2867. }
  2868. else
  2869. {
  2870. cShaderUsed->add( pMaterials[index]->GetShaderName() );
  2871. }
  2872. }
  2873. }
  2874. }
  2875. break;
  2876. case IDC_INCLUDEDMODELS:
  2877. // Do nothing
  2878. break;
  2879. case IDC_SEQUENCE0:
  2880. case IDC_SEQUENCE1:
  2881. case IDC_SEQUENCE2:
  2882. case IDC_SEQUENCE3:
  2883. case IDC_SEQUENCE4:
  2884. {
  2885. int i = event->action - IDC_SEQUENCE0;
  2886. int index = ((mxChoice *) event->widget)->getSelectedIndex();
  2887. if (index >= 0)
  2888. {
  2889. index = GetSequenceForSelection( i, index );
  2890. if (i == 0)
  2891. {
  2892. setSequence (index);
  2893. showActivityModifiers( index );
  2894. }
  2895. else
  2896. {
  2897. setOverlaySequence( i, index, slSequence[i]->getValue() );
  2898. }
  2899. }
  2900. }
  2901. break;
  2902. case IDC_SEQUENCESCALE0:
  2903. case IDC_SEQUENCESCALE1:
  2904. case IDC_SEQUENCESCALE2:
  2905. case IDC_SEQUENCESCALE3:
  2906. case IDC_SEQUENCESCALE4:
  2907. {
  2908. int i = event->action - IDC_SEQUENCESCALE0;
  2909. int index = cSequence[i]->getSelectedIndex();
  2910. if (index >= 0)
  2911. {
  2912. index = GetSequenceForSelection( i, index );
  2913. if (i == 0)
  2914. {
  2915. setSequence (index);
  2916. showActivityModifiers( index );
  2917. }
  2918. else
  2919. {
  2920. setOverlaySequence( i, index, (float)((mxSlider *) event->widget)->getValue() );
  2921. }
  2922. }
  2923. else
  2924. {
  2925. setOverlaySequence( i, 0, (float)((mxSlider *) event->widget)->getValue() );
  2926. }
  2927. }
  2928. break;
  2929. case IDC_SEQUENCEFILTER0:
  2930. case IDC_SEQUENCEFILTER1:
  2931. case IDC_SEQUENCEFILTER2:
  2932. case IDC_SEQUENCEFILTER3:
  2933. case IDC_SEQUENCEFILTER4:
  2934. {
  2935. int sequenceSlot = event->action - IDC_SEQUENCEFILTER0;
  2936. SaveSelectedSequences();
  2937. initSequenceChoices( sequenceSlot );
  2938. RestoreSelectedSequences();
  2939. }
  2940. break;
  2941. case IDC_FRAMESELECTION0:
  2942. case IDC_FRAMESELECTION1:
  2943. case IDC_FRAMESELECTION2:
  2944. case IDC_FRAMESELECTION3:
  2945. case IDC_FRAMESELECTION4:
  2946. {
  2947. updateFrameSelection();
  2948. }
  2949. break;
  2950. case IDC_BLENDTIME:
  2951. {
  2952. char sz[ 256 ];
  2953. sprintf( sz, "%.2f s", (float)((mxSlider *) event->widget)->getValue() );
  2954. g_pStudioModel->SetBlendTime( ((mxSlider *) event->widget)->getValue() );
  2955. laBlendTime->setLabel( sz );
  2956. }
  2957. break;
  2958. case IDC_BLENDSEQUENCECHANGES:
  2959. g_viewerSettings.blendSequenceChanges = ((mxCheckBox *) event->widget)->isChecked();
  2960. break;
  2961. case IDC_ANIMATEWEAPONS:
  2962. g_viewerSettings.animateWeapons = ((mxCheckBox *) event->widget)->isChecked();
  2963. break;
  2964. case IDC_BLENDNOW:
  2965. startBlending();
  2966. break;
  2967. case IDC_SPEEDSCALE:
  2968. {
  2969. setSpeedScale( ((mxSlider *) event->widget)->getValue() );
  2970. }
  2971. break;
  2972. case IDC_FORCEFRAME:
  2973. {
  2974. setFrame( ((mxSlider *) event->widget)->getValue() );
  2975. // stop the animation
  2976. setSpeedScale( 0 );
  2977. if ( g_bHlmvMaster && g_HlmvIpcClient.Connect() )
  2978. {
  2979. CUtlBuffer cmd;
  2980. CUtlBuffer res;
  2981. cmd.Printf( "%s %f", "hlmvForceFrame", reinterpret_cast< mxSlider * >( event->widget )->getValue() );
  2982. g_HlmvIpcClient.ExecuteCommand( cmd, res );
  2983. g_HlmvIpcClient.Disconnect();
  2984. }
  2985. }
  2986. break;
  2987. case IDC_BODYPART:
  2988. {
  2989. int index = cBodypart->getSelectedIndex();
  2990. if (index >= 0)
  2991. {
  2992. //don't change bodygroup states just by selecting the group dropdown. The submodel dropdown does this
  2993. //g_pStudioModel->SetBodygroup (cBodypart->getSelectedIndex(), index);
  2994. setBodypart (index);
  2995. }
  2996. }
  2997. break;
  2998. case IDC_BODYGROUPPRESET:
  2999. {
  3000. int index = cBodyGroupPreset->getSelectedIndex();
  3001. if (index >= 0)
  3002. {
  3003. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3004. if (hdr)
  3005. {
  3006. g_pStudioModel->SetBodygroupPreset( cBodyGroupPreset->getItemText(index) );
  3007. }
  3008. }
  3009. }
  3010. break;
  3011. case IDC_ROLL_BODYGROUPS:
  3012. {
  3013. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3014. if (hdr)
  3015. {
  3016. mstudiobodyparts_t *pbodyparts = hdr->pBodypart(0);
  3017. for ( int i=0; i<hdr->numbodyparts(); i++ )
  3018. {
  3019. int randSelect = RandomInt(0, pbodyparts[i].nummodels - 1);
  3020. g_pStudioModel->SetBodygroup( i, randSelect );
  3021. if (cBodypart->getSelectedIndex() == i)
  3022. cSubmodel->select( randSelect );
  3023. }
  3024. }
  3025. }
  3026. break;
  3027. case IDC_EXPLORE_TO_VMT:
  3028. {
  3029. int index = cMessageList->getSelectedIndex();
  3030. if (index >= 0)
  3031. {
  3032. char szAbsPath[260];
  3033. V_sprintf_safe( szAbsPath, "%s\\%s\\materials\\%s.vmt", getenv("VGAME"), getenv("VMOD"), cMessageList->getItemText( index ) );
  3034. for (char *cp = szAbsPath; *cp; cp++)
  3035. {
  3036. if (*cp == '/')
  3037. *cp = '\\';
  3038. if (*cp == '\r' ||*cp == '\n')
  3039. *cp = '\0';
  3040. }
  3041. ShellExecute( 0, 0, _T(szAbsPath), 0, 0, SW_SHOW );
  3042. }
  3043. }
  3044. break;
  3045. case IDC_SUBMODEL:
  3046. {
  3047. int index = cSubmodel->getSelectedIndex();
  3048. if (index >= 0)
  3049. {
  3050. setSubmodel (index);
  3051. }
  3052. }
  3053. break;
  3054. case IDC_CONTROLLER:
  3055. {
  3056. int index = cController->getSelectedIndex();
  3057. if (index >= 0)
  3058. setBoneController (index);
  3059. }
  3060. break;
  3061. case IDC_CONTROLLERVALUE:
  3062. {
  3063. int index = cController->getSelectedIndex();
  3064. if (index >= 0)
  3065. {
  3066. float flValue = slController->getValue();
  3067. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3068. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
  3069. if (pbonecontroller->end < pbonecontroller->start)
  3070. {
  3071. flValue *= -1.0f;
  3072. }
  3073. setBoneControllerValue(index, flValue);
  3074. }
  3075. }
  3076. break;
  3077. case IDC_SKINS:
  3078. {
  3079. int index = cSkin->getSelectedIndex();
  3080. if (index >= 0)
  3081. {
  3082. g_pStudioModel->SetSkin (index);
  3083. g_viewerSettings.skin = index;
  3084. d_MatSysWindow->redraw();
  3085. }
  3086. }
  3087. break;
  3088. case IDC_MATERIALS:
  3089. {
  3090. int index = cMaterials->getSelectedIndex();
  3091. if (index >= 0)
  3092. {
  3093. g_viewerSettings.materialIndex = index;
  3094. }
  3095. }
  3096. break;
  3097. case IDC_IKRULE_CHAIN:
  3098. case IDC_IKRULE_CHOICE:
  3099. case IDC_IKRULE_RANGE_TOGGLE:
  3100. case IDC_IKRULE_RANGE_START:
  3101. case IDC_IKRULE_RANGE_PEAK:
  3102. case IDC_IKRULE_RANGE_TAIL:
  3103. case IDC_IKRULE_RANGE_END:
  3104. case IDC_IKRULE_CONTACT_TOGGLE:
  3105. case IDC_IKRULE_CONTACT_FRAME:
  3106. case IDC_IKRULE_USING:
  3107. UpdateIKRuleWindow();
  3108. break;
  3109. case IDC_IKRULE_TOUCH:
  3110. case IDC_IKRULE_ATTACHMENT:
  3111. BuildIKRuleQCString();
  3112. break;
  3113. case IDC_IKRULE_RANGE_START_NOW:
  3114. SetFrameString( leIKRangeStart, getFrameSelection() );
  3115. break;
  3116. case IDC_IKRULE_RANGE_PEAK_NOW:
  3117. SetFrameString( leIKRangePeak, getFrameSelection() );
  3118. break;
  3119. case IDC_IKRULE_RANGE_TAIL_NOW:
  3120. SetFrameString( leIKRangeTail, getFrameSelection() );
  3121. break;
  3122. case IDC_IKRULE_RANGE_END_NOW:
  3123. SetFrameString( leIKRangeEnd, getFrameSelection() );
  3124. break;
  3125. case IDC_IKRULE_CONTACT_FRAME_NOW:
  3126. SetFrameString( leIKContactFrame, getFrameSelection() );
  3127. break;
  3128. case IDC_IKRULE_QC_STRING:
  3129. // ignore edits to the qc text box
  3130. break;
  3131. case IDC_EVENT_SOUND_FRAME:
  3132. case IDC_EVENT_SOUND_NAME:
  3133. BuildEventQCString();
  3134. break;
  3135. case IDC_EVENT_SOUND_FRAME_NOW:
  3136. SetFrameString( leEventSoundFrame, getFrameSelection() );
  3137. break;
  3138. case IDC_EVENT_QC_STRING:
  3139. // ignore edits to the qc text box
  3140. break;
  3141. case IDC_SUBMODEL_UPDATE_BONESELECTION:
  3142. {
  3143. int iSelectedSubmodel = cSubmodelList->getSelectedIndex();
  3144. if ( iSelectedSubmodel != -1 )
  3145. {
  3146. strcpy( g_MergeModelBonePairs[iSelectedSubmodel].szTargetBone, cSubmodelAttachTo->getLabel() );
  3147. strcpy( g_MergeModelBonePairs[iSelectedSubmodel].szLocalBone, cSubmodelLocalAttachOrigin->getLabel() );
  3148. }
  3149. }
  3150. break;
  3151. case IDC_SUBMODEL_UPDATE_SELECTION:
  3152. {
  3153. UpdateSubmodelSelection();
  3154. }
  3155. break;
  3156. case IDC_SUBMODEL_LOADMERGEDMODEL:
  3157. {
  3158. const char *ptr = mxGetOpenFileName (this, 0, "*.mdl");
  3159. if (ptr)
  3160. {
  3161. // find the first free slot
  3162. int iChosenSlot = 0;
  3163. for ( int i = 0; i < HLMV_MAX_MERGED_MODELS; i++ )
  3164. {
  3165. if ( g_viewerSettings.mergeModelFile[i][0] == 0 )
  3166. {
  3167. iChosenSlot = i;
  3168. break;
  3169. }
  3170. }
  3171. strcpy( g_viewerSettings.mergeModelFile[iChosenSlot], ptr );
  3172. g_MDLViewer->LoadModelFile( ptr, iChosenSlot );
  3173. }
  3174. }
  3175. break;
  3176. case IDC_SUBMODEL_LOADMERGEDMODEL_STEAM:
  3177. {
  3178. const char *pFilename = g_MDLViewer->SteamGetOpenFilename();
  3179. if ( pFilename )
  3180. {
  3181. // find the first free slot
  3182. int iChosenSlot = 0;
  3183. for ( int i = 0; i < HLMV_MAX_MERGED_MODELS; i++ )
  3184. {
  3185. if ( g_viewerSettings.mergeModelFile[i][0] == 0 )
  3186. {
  3187. iChosenSlot = i;
  3188. break;
  3189. }
  3190. }
  3191. strcpy( g_viewerSettings.mergeModelFile[iChosenSlot], pFilename );
  3192. g_MDLViewer->LoadModelFile( pFilename, iChosenSlot );
  3193. }
  3194. }
  3195. break;
  3196. case IDC_SUBMODEL_UNLOADMERGEDMODEL:
  3197. {
  3198. int i = cSubmodelList->getSelectedIndex();
  3199. // FIXME: move to d_cpl
  3200. if ( i != -1 && g_pStudioExtraModel[i])
  3201. {
  3202. strcpy( g_viewerSettings.mergeModelFile[i], "" );
  3203. g_pStudioExtraModel[i]->FreeModel( false );
  3204. delete g_pStudioExtraModel[i];
  3205. g_pStudioExtraModel[i] = NULL;
  3206. }
  3207. //need to push the missing index out of the merged model list
  3208. for ( int i = 0; i < HLMV_MAX_MERGED_MODELS - 1; i++ )
  3209. {
  3210. if ( g_pStudioExtraModel[i] == NULL && g_pStudioExtraModel[i+1] != NULL )
  3211. {
  3212. strcpy( g_viewerSettings.mergeModelFile[i], g_viewerSettings.mergeModelFile[i+1] );
  3213. strcpy( g_viewerSettings.mergeModelFile[i+1], "" );
  3214. g_pStudioExtraModel[i] = g_pStudioExtraModel[i+1];
  3215. g_pStudioExtraModel[i+1] = NULL;
  3216. strcpy( g_MergeModelBonePairs[i].szLocalBone, g_MergeModelBonePairs[i+1].szLocalBone );
  3217. strcpy( g_MergeModelBonePairs[i+1].szLocalBone, "" );
  3218. strcpy( g_MergeModelBonePairs[i].szTargetBone, g_MergeModelBonePairs[i+1].szTargetBone );
  3219. strcpy( g_MergeModelBonePairs[i+1].szTargetBone, "" );
  3220. }
  3221. }
  3222. UpdateSubmodelWindow();
  3223. }
  3224. break;
  3225. case IDC_SUBMODEL_UNLOADALLMERGEDMODELS:
  3226. {
  3227. for (int i=0; i<HLMV_MAX_MERGED_MODELS; i++)
  3228. {
  3229. // FIXME: move to d_cpl
  3230. if (g_pStudioExtraModel[i])
  3231. {
  3232. strcpy( g_viewerSettings.mergeModelFile[i], "" );
  3233. g_pStudioExtraModel[i]->FreeModel( false );
  3234. delete g_pStudioExtraModel[i];
  3235. g_pStudioExtraModel[i] = NULL;
  3236. }
  3237. }
  3238. UpdateSubmodelWindow();
  3239. }
  3240. break;
  3241. case IDC_COMPILE_UPDATE_QCPATHSELECTION:
  3242. {
  3243. if ( bCompileSelectedToggle )
  3244. {
  3245. CompileSelectedIndex();
  3246. }
  3247. else
  3248. {
  3249. UpdateQCPathPanel( false );
  3250. }
  3251. }
  3252. break;
  3253. case IDC_COMPILE_REMOVEFROMLIST:
  3254. {
  3255. int nSelection = cCompileRecentQCpaths->getSelectedIndex();
  3256. if ( nSelection >= 0 && g_QCPathRecords.Count() > nSelection )
  3257. {
  3258. DeleteFile( TEXT(g_QCPathRecords[nSelection].szLogFilePath) );
  3259. g_QCPathRecords.Remove( nSelection );
  3260. }
  3261. cCompileRecentQCpaths->select(-1);
  3262. UpdateQCPathPanel();
  3263. }
  3264. break;
  3265. case IDC_COMPILE_SELECTEDTOGGLE:
  3266. {
  3267. bCompileSelectedToggle = !bCompileSelectedToggle;
  3268. bCompileQCWhenSelected->setLabel( bCompileSelectedToggle ? "One-click compile [ON]" : "One-click compile [OFF]" );
  3269. }
  3270. break;
  3271. case IDC_COMPILE_OPENLOGFILE:
  3272. {
  3273. int nSelection = cCompileRecentQCpaths->getSelectedIndex();
  3274. if ( nSelection >= 0 && g_QCPathRecords.Count() > nSelection )
  3275. {
  3276. if ( strlen(g_QCPathRecords[nSelection].szLogFilePath) > 0 )
  3277. {
  3278. ShellExecute(0, 0, g_QCPathRecords[nSelection].szLogFilePath, 0, 0 , SW_SHOW );
  3279. }
  3280. }
  3281. }
  3282. break;
  3283. case IDC_COMPILE_EXPLORETOQC:
  3284. {
  3285. int nSelection = cCompileRecentQCpaths->getSelectedIndex();
  3286. if ( nSelection >= 0 && g_QCPathRecords.Count() > nSelection )
  3287. {
  3288. char cmd[1024];
  3289. V_sprintf_safe( cmd, "/select,\"%s\"", g_QCPathRecords[nSelection].szAbsPath );
  3290. ShellExecute(0, _T("open"), _T("explorer.exe"), cmd, 0, SW_NORMAL);
  3291. }
  3292. }
  3293. break;
  3294. case IDC_COMPILE_LOADMODELFILE:
  3295. {
  3296. int nSelection = cCompileRecentQCpaths->getSelectedIndex();
  3297. if ( nSelection >= 0 && g_QCPathRecords.Count() > nSelection )
  3298. {
  3299. if ( strlen(g_QCPathRecords[nSelection].szModelPath) > 0 )
  3300. {
  3301. char szAbsPath[260];
  3302. V_sprintf_safe( szAbsPath, "%s\\%s", getenv("VGAME"), g_QCPathRecords[nSelection].szModelPath );
  3303. for (char *cp = szAbsPath; *cp; cp++)
  3304. {
  3305. if (*cp == '/')
  3306. *cp = '\\';
  3307. if (*cp == '\r' ||*cp == '\n')
  3308. *cp = '\0';
  3309. }
  3310. g_MDLViewer->LoadModelFile( szAbsPath );
  3311. }
  3312. }
  3313. }
  3314. break;
  3315. case IDC_COMPILE_CALLSTUDIOMDL:
  3316. {
  3317. CompileSelectedIndex();
  3318. }
  3319. break;
  3320. default:
  3321. {
  3322. if ( event->action == IDC_FLEXDEFAULTS )
  3323. {
  3324. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3325. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  3326. {
  3327. g_pStudioModel->SetFlexController( i, 0 );
  3328. }
  3329. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  3330. {
  3331. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  3332. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  3333. }
  3334. }
  3335. else if ( event->action == IDC_FLEXRANDOM )
  3336. {
  3337. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3338. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  3339. {
  3340. float r = rand() / float( VALVE_RAND_MAX );
  3341. g_pStudioModel->SetFlexController( i, r );
  3342. }
  3343. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  3344. {
  3345. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  3346. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  3347. }
  3348. }
  3349. else if ( event->action == IDC_FLEXZERO )
  3350. {
  3351. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3352. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  3353. {
  3354. g_pStudioModel->SetFlexController( i, 0 );
  3355. }
  3356. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  3357. {
  3358. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  3359. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  3360. }
  3361. }
  3362. else if ( event->action == IDC_FLEXONE )
  3363. {
  3364. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3365. for (LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  3366. {
  3367. g_pStudioModel->SetFlexController( i, 1 );
  3368. }
  3369. for (int i = 0; i < NUM_FLEX_SLIDERS; i++)
  3370. {
  3371. LocalFlexController_t index = (LocalFlexController_t)cFlex[i]->getSelectedIndex();
  3372. slFlexScale[ i ]->setValue( g_pStudioModel->GetFlexControllerRaw( index ) );
  3373. }
  3374. }
  3375. else if (event->action >= IDC_FLEX && event->action < IDC_FLEX + NUM_FLEX_SLIDERS)
  3376. {
  3377. int flex = (event->action - IDC_FLEX);
  3378. LocalFlexController_t index = (LocalFlexController_t)cFlex[flex]->getSelectedIndex();
  3379. if (index >= 0)
  3380. {
  3381. slFlexScale[flex]->setValue(g_pStudioModel->GetFlexControllerRaw(index));
  3382. }
  3383. }
  3384. else if (event->action >= IDC_FLEXSCALE && event->action < IDC_FLEXSCALE + NUM_FLEX_SLIDERS)
  3385. {
  3386. int flex = (event->action - IDC_FLEXSCALE);
  3387. LocalFlexController_t index = (LocalFlexController_t)cFlex[flex]->getSelectedIndex();
  3388. g_pStudioModel->SetFlexControllerRaw( index, ((mxSlider *) event->widget)->getValue() );
  3389. }
  3390. else if ( event->action >= IDC_PHYS_FIRST && event->action <= IDC_PHYS_LAST )
  3391. {
  3392. return handlePhysicsEvent( event );
  3393. }
  3394. else if ( event->action >= IDC_SOFT_FIRST && event->action <= IDC_SOFT_LAST )
  3395. {
  3396. return handleSoftbodyEvent( event );
  3397. }
  3398. else if (event->action >= IDC_POSEPARAMETER && event->action < IDC_POSEPARAMETER + NUM_POSEPARAMETERS)
  3399. {
  3400. int index = event->action - IDC_POSEPARAMETER;
  3401. int poseparam = cPoseParameter[index]->getSelectedIndex();
  3402. float flMin, flMax;
  3403. if (g_pStudioModel->GetPoseParameterRange( poseparam, &flMin, &flMax ))
  3404. {
  3405. slPoseParameter[index]->setRange( flMin, flMax, 1000 );
  3406. slPoseParameter[index]->setValue( g_pStudioModel->GetPoseParameter( poseparam ) );
  3407. lePoseParameter[index]->setLabel( "%.1f", g_pStudioModel->GetPoseParameter( poseparam ) );
  3408. }
  3409. }
  3410. else if (event->action >= IDC_POSEPARAMETER_SCALE && event->action < IDC_POSEPARAMETER_SCALE + NUM_POSEPARAMETERS)
  3411. {
  3412. int index = event->action - IDC_POSEPARAMETER_SCALE;
  3413. int poseparam = cPoseParameter[index]->getSelectedIndex();
  3414. setBlend( poseparam, ((mxSlider *) event->widget)->getValue() );
  3415. lePoseParameter[index]->setLabel( "%.1f", ((mxSlider *) event->widget)->getValue() );
  3416. }
  3417. }
  3418. break;
  3419. }
  3420. return 1;
  3421. }
  3422. void
  3423. ControlPanel::dumpModelInfo()
  3424. {
  3425. #if 0
  3426. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3427. if (hdr)
  3428. {
  3429. DeleteFile ("midump.txt");
  3430. FILE *file = fopen ("midump.txt", "wt");
  3431. if (file)
  3432. {
  3433. byte *phdr = (byte *) hdr;
  3434. int i;
  3435. fprintf (file, "id: %c%c%c%c\n", phdr[0], phdr[1], phdr[2], phdr[3]);
  3436. fprintf (file, "version: %d\n", hdr->version);
  3437. fprintf (file, "name: \"%s\"\n", hdr->name);
  3438. fprintf (file, "length: %d\n\n", hdr->length);
  3439. fprintf (file, "eyeposition: %f %f %f\n", hdr->eyeposition[0], hdr->eyeposition[1], hdr->eyeposition[2]);
  3440. fprintf (file, "min: %f %f %f\n", hdr->min[0], hdr->min[1], hdr->min[2]);
  3441. fprintf (file, "max: %f %f %f\n", hdr->max[0], hdr->max[1], hdr->max[2]);
  3442. fprintf (file, "bbmin: %f %f %f\n", hdr->bbmin[0], hdr->bbmin[1], hdr->bbmin[2]);
  3443. fprintf (file, "bbmax: %f %f %f\n", hdr->bbmax[0], hdr->bbmax[1], hdr->bbmax[2]);
  3444. fprintf (file, "flags: %d\n\n", hdr->flags);
  3445. fprintf (file, "numbones: %d\n", hdr->numbones);
  3446. for (i = 0; i < hdr->numbones; i++)
  3447. {
  3448. const mstudiobone_t *pbones = (mstudiobone_t *) (phdr + hdr->boneindex);
  3449. fprintf (file, "\nbone %d.name: \"%s\"\n", i + 1, pbones[i].name);
  3450. fprintf (file, "bone %d.parent: %d\n", i + 1, pbones[i].parent);
  3451. fprintf (file, "bone %d.flags: %d\n", i + 1, pbones[i].flags);
  3452. 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]);
  3453. 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]);
  3454. 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]);
  3455. }
  3456. fprintf (file, "\nnumbonecontrollers: %d\n", hdr->numbonecontrollers);
  3457. for (i = 0; i < hdr->numbonecontrollers; i++)
  3458. {
  3459. mstudiobonecontroller_t *pbonecontrollers = (mstudiobonecontroller_t *) (phdr + hdr->bonecontrollerindex);
  3460. fprintf (file, "\nbonecontroller %d.bone: %d\n", i + 1, pbonecontrollers[i].bone);
  3461. fprintf (file, "bonecontroller %d.type: %d\n", i + 1, pbonecontrollers[i].type);
  3462. fprintf (file, "bonecontroller %d.start: %f\n", i + 1, pbonecontrollers[i].start);
  3463. fprintf (file, "bonecontroller %d.end: %f\n", i + 1, pbonecontrollers[i].end);
  3464. fprintf (file, "bonecontroller %d.rest: %d\n", i + 1, pbonecontrollers[i].rest);
  3465. fprintf (file, "bonecontroller %d.index: %d\n", i + 1, pbonecontrollers[i].index);
  3466. }
  3467. fprintf (file, "\nnumhitboxes: %d\n", hdr->numhitboxes);
  3468. for (i = 0; i < hdr->numhitboxes; i++)
  3469. {
  3470. mstudiobbox_t *pbboxes = (mstudiobbox_t *) (phdr + hdr->hitboxindex);
  3471. fprintf (file, "\nhitbox %d.bone: %d\n", i + 1, pbboxes[i].bone);
  3472. fprintf (file, "hitbox %d.group: %d\n", i + 1, pbboxes[i].group);
  3473. fprintf (file, "hitbox %d.bbmin: %f %f %f\n", i + 1, pbboxes[i].bbmin[0], pbboxes[i].bbmin[1], pbboxes[i].bbmin[2]);
  3474. fprintf (file, "hitbox %d.bbmax: %f %f %f\n", i + 1, pbboxes[i].bbmax[0], pbboxes[i].bbmax[1], pbboxes[i].bbmax[2]);
  3475. }
  3476. fprintf (file, "\nnumseq: %d\n", hdr->GetNumSeq());
  3477. for (i = 0; i < hdr->GetNumSeq(); i++)
  3478. {
  3479. mstudioseqdesc_t *pseqdescs = (mstudioseqdesc_t *) (phdr + hdr->seqindex);
  3480. fprintf (file, "\nseqdesc %d.label: \"%s\"\n", i + 1, pseqdescs[i].label);
  3481. fprintf (file, "seqdesc %d.fps: %f\n", i + 1, pseqdescs[i].fps);
  3482. fprintf (file, "seqdesc %d.flags: %d\n", i + 1, pseqdescs[i].flags);
  3483. fprintf (file, "<...>\n");
  3484. }
  3485. /*
  3486. fprintf (file, "\nnumseqgroups: %d\n", hdr->GetNumSeq()groups);
  3487. for (i = 0; i < hdr->GetNumSeq()groups; i++)
  3488. {
  3489. mstudioseqgroup_t *pseqgroups = (mstudioseqgroup_t *) (phdr + hdr->seqgroupindex);
  3490. fprintf (file, "\nseqgroup %d.label: \"%s\"\n", i + 1, pseqgroups[i].label);
  3491. fprintf (file, "\nseqgroup %d.namel: \"%s\"\n", i + 1, pseqgroups[i].name);
  3492. fprintf (file, "\nseqgroup %d.data: %d\n", i + 1, pseqgroups[i].data);
  3493. }
  3494. */
  3495. hdr = g_pStudioModel->getTextureHeader();
  3496. fprintf (file, "\nnumtextures: %d\n", hdr->numtextures);
  3497. fprintf (file, "textureindex: %d\n", hdr->textureindex);
  3498. fprintf (file, "texturedataindex: %d\n", hdr->texturedataindex);
  3499. for (i = 0; i < hdr->numtextures; i++)
  3500. {
  3501. mstudiotexture_t *ptextures = (mstudiotexture_t *) ((byte *) hdr + hdr->textureindex);
  3502. fprintf (file, "\ntexture %d.name: \"%s\"\n", i + 1, ptextures[i].name);
  3503. fprintf (file, "texture %d.flags: %d\n", i + 1, ptextures[i].flags);
  3504. fprintf (file, "texture %d.width: %d\n", i + 1, ptextures[i].width);
  3505. fprintf (file, "texture %d.height: %d\n", i + 1, ptextures[i].height);
  3506. fprintf (file, "texture %d.index: %d\n", i + 1, ptextures[i].index);
  3507. }
  3508. hdr = g_pStudioModel->GetStudioHdr();
  3509. fprintf (file, "\nnumskinref: %d\n", hdr->numskinref);
  3510. fprintf (file, "numskinfamilies: %d\n", hdr->numskinfamilies);
  3511. fprintf (file, "\nnumbodyparts: %d\n", hdr->numbodyparts);
  3512. for (i = 0; i < hdr->numbodyparts; i++)
  3513. {
  3514. mstudiobodyparts_t *pbodyparts = (mstudiobodyparts_t *) ((byte *) hdr + hdr->bodypartindex);
  3515. fprintf (file, "\nbodypart %d.name: \"%s\"\n", i + 1, pbodyparts[i].name);
  3516. fprintf (file, "bodypart %d.nummodels: %d\n", i + 1, pbodyparts[i].nummodels);
  3517. fprintf (file, "bodypart %d.base: %d\n", i + 1, pbodyparts[i].base);
  3518. fprintf (file, "bodypart %d.modelindex: %d\n", i + 1, pbodyparts[i].modelindex);
  3519. }
  3520. fprintf (file, "\nnumattachments: %d\n", hdr->numattachments);
  3521. for (i = 0; i < hdr->numattachments; i++)
  3522. {
  3523. mstudioattachment_t *pattachments = (mstudioattachment_t *) ((byte *) hdr + hdr->attachmentindex);
  3524. fprintf (file, "attachment %d.name: \"%s\"\n", i + 1, pattachments[i].name);
  3525. }
  3526. fclose (file);
  3527. ShellExecute ((HWND) getHandle(), "open", "midump.txt", 0, 0, SW_SHOW);
  3528. }
  3529. }
  3530. #endif
  3531. }
  3532. LoadModelResult_t ControlPanel::loadModel(const char *filename)
  3533. {
  3534. SaveViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
  3535. g_pStudioModel->FreeModel( false );
  3536. if (!g_pStudioModel->LoadModel( filename ))
  3537. {
  3538. return LoadModel_LoadFail;
  3539. }
  3540. if (!g_pStudioModel->PostLoadModel( filename ))
  3541. {
  3542. return LoadModel_PostLoadFail;
  3543. }
  3544. if (!g_pStudioModel->HasModel())
  3545. {
  3546. return LoadModel_NoModel;
  3547. }
  3548. OnLoadModel( );
  3549. return LoadModel_Success;
  3550. }
  3551. void ControlPanel::OnLoadModel( void )
  3552. {
  3553. int i;
  3554. m_bVMTInfoLoaded = false;
  3555. if (!g_pStudioModel->HasModel())
  3556. return;
  3557. initSequenceChoices();
  3558. initBodypartChoices();
  3559. initBoneControllers();
  3560. initSkinChoices();
  3561. initMaterialChoices();
  3562. initPhysicsBones();
  3563. initIncludedModels();
  3564. initLODs();
  3565. initFlexes();
  3566. setModelInfo();
  3567. const bool bNoModelSettings = LoadViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
  3568. if ( !bNoModelSettings )
  3569. {
  3570. InitViewerSettings( "hlmv" );
  3571. setSequence( 0 );
  3572. showActivityModifiers( 0 );
  3573. setSpeedScale( 1.0 );
  3574. }
  3575. resetControlPanel();
  3576. /*!!
  3577. for (i = 0; i < 32; i++)
  3578. g_viewerSettings.submodels[i] = 0;
  3579. for (i = 0; i < 8; i++)
  3580. g_viewerSettings.controllers[i] = 0;
  3581. */
  3582. setupPhysics();
  3583. m_pBoneWindow->OnLoadModel();
  3584. m_pAttachmentsWindow->OnLoadModel();
  3585. PopulateBoneList( cIKTouch, true );
  3586. mx_setcwd (mx_getpath (g_pStudioModel->GetFileName()));
  3587. for (i = 0; i < HLMV_MAX_MERGED_MODELS; i++)
  3588. {
  3589. if (g_pStudioExtraModel[i])
  3590. {
  3591. g_pStudioExtraModel[i]->FreeModel( false );
  3592. delete g_pStudioExtraModel[i];
  3593. g_pStudioExtraModel[i] = NULL;
  3594. }
  3595. if (strlen( g_viewerSettings.mergeModelFile[i] ) != 0)
  3596. {
  3597. loadModel( g_viewerSettings.mergeModelFile[i], i );
  3598. }
  3599. }
  3600. g_pWidgetControl = new WidgetControl();
  3601. // Center the model if we don't have last view position data in the registry
  3602. if ( !bNoModelSettings )
  3603. {
  3604. // Need to call this twice for some reason. Really - I don't have OCD!
  3605. centerView();
  3606. centerView();
  3607. }
  3608. // guess the category and set a reasonable default fov
  3609. if ( V_stristr( g_pStudioModel->GetFileName(), "\\player\\" ) )
  3610. {
  3611. setFOV( 90 );
  3612. }
  3613. else if ( V_stristr( g_pStudioModel->GetFileName(), "weapons\\v_" ) )
  3614. {
  3615. setFOV( 54 );
  3616. }
  3617. else if ( V_stristr( g_pStudioModel->GetFileName(), "weapons\\w_" ) )
  3618. {
  3619. setFOV( 90 );
  3620. }
  3621. }
  3622. LoadModelResult_t ControlPanel::loadModel(const char *filename, int slot )
  3623. {
  3624. if (slot == -1)
  3625. {
  3626. return loadModel( filename );
  3627. }
  3628. if (g_pStudioExtraModel[slot] == NULL)
  3629. {
  3630. g_pStudioExtraModel[slot] = new StudioModel;
  3631. }
  3632. else
  3633. {
  3634. g_pStudioExtraModel[slot]->FreeModel( false );
  3635. }
  3636. if (g_pStudioExtraModel[slot]->LoadModel( filename ))
  3637. {
  3638. if (g_pStudioExtraModel[slot]->PostLoadModel( filename ))
  3639. {
  3640. MapExtraFlexes( slot );
  3641. UpdateSubmodelWindow();
  3642. return LoadModel_Success;
  3643. }
  3644. else
  3645. {
  3646. return LoadModel_PostLoadFail;
  3647. }
  3648. }
  3649. return LoadModel_LoadFail;
  3650. }
  3651. void
  3652. ControlPanel::resetControlPanel( void )
  3653. {
  3654. setSequence( g_pStudioModel->GetSequence() );
  3655. showActivityModifiers( g_pStudioModel->GetSequence() );
  3656. setOverlaySequence( 1, g_pStudioModel->GetOverlaySequence( 0 ), g_pStudioModel->GetOverlaySequenceWeight( 0 ) );
  3657. setOverlaySequence( 2, g_pStudioModel->GetOverlaySequence( 1 ), g_pStudioModel->GetOverlaySequenceWeight( 1 ) );
  3658. setOverlaySequence( 3, g_pStudioModel->GetOverlaySequence( 2 ), g_pStudioModel->GetOverlaySequenceWeight( 2 ) );
  3659. setOverlaySequence( 4, g_pStudioModel->GetOverlaySequence( 3 ), g_pStudioModel->GetOverlaySequenceWeight( 3 ) );
  3660. setSpeedScale( g_viewerSettings.speedScale );
  3661. cbGround->setChecked( g_viewerSettings.showGround );
  3662. cbMovement->setChecked( g_viewerSettings.showMovement );
  3663. cbShadow->setChecked( g_viewerSettings.showShadow );
  3664. cbNormalMap->setChecked( g_viewerSettings.enableNormalMapping );
  3665. cbDisplacementMap->setChecked( g_viewerSettings.enableDisplacementMapping );
  3666. cbIllumPosition->setChecked( g_viewerSettings.showIllumPosition );
  3667. cbHitBoxes->setChecked( g_viewerSettings.showHitBoxes );
  3668. cbBones->setChecked( g_viewerSettings.showBones );
  3669. cbPlaySounds->setChecked( g_viewerSettings.playSounds );
  3670. cbShowOriginAxis->setChecked( g_viewerSettings.showOriginAxis );
  3671. cbSequenceBoxes->setChecked( g_viewerSettings.showSequenceBoxes );
  3672. cbRunIK->setChecked( g_viewerSettings.enableIK );
  3673. cbBackground->setChecked( g_viewerSettings.showBackground );
  3674. cbSoftwareSkin->setChecked( g_viewerSettings.softwareSkin );
  3675. cbOverbright2->setChecked( g_viewerSettings.overbright );
  3676. cbAttachments->setChecked( g_viewerSettings.showAttachments );
  3677. cbNormals->setChecked( g_viewerSettings.showNormals );
  3678. cbEnableHead->setChecked( g_pStudioModel->GetSolveHeadTurn() ? 1 : 0 );
  3679. cbShowOriginAxis->setChecked( g_viewerSettings.showOriginAxis );
  3680. setOriginAxisLength( g_viewerSettings.originAxisLength );
  3681. }
  3682. void
  3683. ControlPanel::setRenderMode (int mode)
  3684. {
  3685. g_viewerSettings.renderMode = mode;
  3686. d_MatSysWindow->redraw();
  3687. }
  3688. void
  3689. ControlPanel::setHighlightBone( int index )
  3690. {
  3691. if ( index >= 0 )
  3692. {
  3693. g_viewerSettings.highlightPhysicsBone = index;
  3694. }
  3695. }
  3696. void
  3697. ControlPanel::setLOD( int index, bool setLODchoice, bool force )
  3698. {
  3699. #if 1
  3700. if( !force && ( g_viewerSettings.lod == index ) )
  3701. {
  3702. return;
  3703. }
  3704. #endif
  3705. g_viewerSettings.lod = index;
  3706. if ( !g_pStudioModel->HasMesh() )
  3707. return;
  3708. float lodSwitch = g_pStudioModel->GetLODSwitchValue( index );
  3709. char tmp[128];
  3710. sprintf( tmp, "%0.0f", lodSwitch );
  3711. leLODSwitch->setLabel( tmp );
  3712. HWND wnd = ( HWND )leLODSwitch->getHandle();
  3713. if( setLODchoice )
  3714. {
  3715. cLODChoice->select( index );
  3716. }
  3717. setModelInfo();
  3718. InvalidateRect( wnd, NULL, TRUE );
  3719. UpdateWindow( wnd );
  3720. }
  3721. void
  3722. ControlPanel::setLODMetric( float metric )
  3723. {
  3724. static int saveMetric = -10;
  3725. int intMetric = ( int )metric;
  3726. if( intMetric == saveMetric )
  3727. {
  3728. return;
  3729. }
  3730. saveMetric = intMetric;
  3731. char tmp[128];
  3732. sprintf( tmp, "%d", intMetric );
  3733. lLODMetric->setLabel( tmp );
  3734. }
  3735. void
  3736. ControlPanel::setPolycount( int polycount )
  3737. {
  3738. static int savePolycount = -10;
  3739. if( polycount == savePolycount )
  3740. {
  3741. return;
  3742. }
  3743. savePolycount = polycount;
  3744. char tmp[128];
  3745. sprintf( tmp, "Polycount: %d", polycount );
  3746. lModelInfo3->setLabel( tmp );
  3747. }
  3748. void
  3749. ControlPanel::setTransparent( bool isTransparent )
  3750. {
  3751. static int saveTransparent = -1;
  3752. if( (int)isTransparent == saveTransparent )
  3753. return;
  3754. saveTransparent = isTransparent;
  3755. char tmp[128];
  3756. sprintf( tmp, "Model is: %s", isTransparent ? "transparent" : "opaque" );
  3757. lModelInfo4->setLabel( tmp );
  3758. }
  3759. void
  3760. ControlPanel::updatePoseParameters( )
  3761. {
  3762. for (int i = 0; i < NUM_POSEPARAMETERS; i++)
  3763. {
  3764. if (slPoseParameter[i]->isEnabled())
  3765. {
  3766. int j = cPoseParameter[i]->getSelectedIndex();
  3767. float value = g_pStudioModel->GetPoseParameter( j );
  3768. float temp = atof( lePoseParameter[i]->getLabel( ) );
  3769. if (fabs( temp - value ) > 0.1)
  3770. {
  3771. slPoseParameter[i]->setValue( value );
  3772. lePoseParameter[i]->setLabel( "%.1f", value );
  3773. }
  3774. }
  3775. }
  3776. }
  3777. void
  3778. ControlPanel::setShowGround (bool b)
  3779. {
  3780. g_viewerSettings.showGround = b;
  3781. cbGround->setChecked (b);
  3782. }
  3783. void
  3784. ControlPanel::setAutoLOD( bool b )
  3785. {
  3786. g_viewerSettings.autoLOD = b;
  3787. cbAutoLOD->setChecked( b );
  3788. }
  3789. void
  3790. ControlPanel::setSoftwareSkin( bool b )
  3791. {
  3792. g_viewerSettings.softwareSkin = b;
  3793. cbSoftwareSkin->setChecked( b );
  3794. }
  3795. void
  3796. ControlPanel::setOverbright( bool b )
  3797. {
  3798. g_viewerSettings.overbright = b;
  3799. cbOverbright2->setChecked( b );
  3800. }
  3801. void
  3802. ControlPanel::setShowMovement (bool b)
  3803. {
  3804. g_viewerSettings.showMovement = b;
  3805. cbMovement->setChecked (b);
  3806. }
  3807. void
  3808. ControlPanel::setShowBackground (bool b)
  3809. {
  3810. g_viewerSettings.showBackground = b;
  3811. cbBackground->setChecked (b);
  3812. }
  3813. void
  3814. ControlPanel::setShowNormals (bool b)
  3815. {
  3816. g_viewerSettings.showNormals = b;
  3817. cbNormals->setChecked (b);
  3818. }
  3819. void
  3820. ControlPanel::setShowTangentFrame (bool b)
  3821. {
  3822. g_viewerSettings.showTangentFrame = b;
  3823. cbTangentFrame->setChecked (b);
  3824. }
  3825. void
  3826. ControlPanel::setOverlayWireframe (bool b)
  3827. {
  3828. g_viewerSettings.overlayWireframe = b;
  3829. cbOverlayWireframe->setChecked (b);
  3830. }
  3831. void
  3832. ControlPanel::setDisplacementMapping( bool b )
  3833. {
  3834. g_viewerSettings.enableDisplacementMapping = b;
  3835. cbDisplacementMap->setChecked( b );
  3836. }
  3837. void
  3838. ControlPanel::setShowShadow (bool b)
  3839. {
  3840. g_viewerSettings.showShadow = b;
  3841. cbShadow->setChecked (b);
  3842. }
  3843. void
  3844. ControlPanel::setShowHitBoxes (bool b)
  3845. {
  3846. g_viewerSettings.showHitBoxes = b;
  3847. cbHitBoxes->setChecked (b);
  3848. }
  3849. void
  3850. ControlPanel::setShowBones (bool b)
  3851. {
  3852. g_viewerSettings.showBones = b;
  3853. cbBones->setChecked (b);
  3854. }
  3855. void
  3856. ControlPanel::setShowAttachments (bool b)
  3857. {
  3858. g_viewerSettings.showAttachments = b;
  3859. cbAttachments->setChecked (b);
  3860. }
  3861. void
  3862. ControlPanel::setPlaySounds (bool b)
  3863. {
  3864. g_viewerSettings.playSounds = b;
  3865. cbPlaySounds->setChecked (b);
  3866. }
  3867. void
  3868. ControlPanel::setShowOriginAxis (bool b)
  3869. {
  3870. g_viewerSettings.showOriginAxis = b;
  3871. cbShowOriginAxis->setChecked (b);
  3872. }
  3873. void ComposeSequenceDisplayName( CStudioHdr *hdr, int nSequence, char *buffer, int bufferLength )
  3874. {
  3875. if ( g_viewerSettings.showSequenceIndices )
  3876. {
  3877. if ( g_viewerSettings.showActivities )
  3878. {
  3879. V_snprintf( buffer, bufferLength, "[%d] %s", nSequence, hdr->pSeqdesc(nSequence).pszActivityName() );
  3880. }
  3881. else
  3882. {
  3883. V_snprintf( buffer, bufferLength, "[%d] %s", nSequence, hdr->pSeqdesc(nSequence).pszLabel() );
  3884. }
  3885. }
  3886. else if ( g_viewerSettings.showActivities )
  3887. {
  3888. V_strncpy( buffer, hdr->pSeqdesc(nSequence).pszActivityName(), bufferLength );
  3889. }
  3890. else
  3891. {
  3892. V_strncpy( buffer, hdr->pSeqdesc(nSequence).pszLabel(), bufferLength );
  3893. }
  3894. }
  3895. struct SortInfo_t
  3896. {
  3897. int m_nSequence;
  3898. char m_szName[256];
  3899. int m_nType;
  3900. };
  3901. int SortSequenceFunc( const void *p1, const void *p2 )
  3902. {
  3903. const SortInfo_t* pSort1 = (const SortInfo_t*)p1;
  3904. const SortInfo_t* pSort2 = (const SortInfo_t*)p2;
  3905. if ( pSort1->m_nType < pSort2->m_nType )
  3906. return -10000;
  3907. if ( pSort1->m_nType > pSort2->m_nType )
  3908. return 10000;
  3909. return Q_stricmp( pSort1->m_szName, pSort2->m_szName );
  3910. }
  3911. void ControlPanel::CreateSortedSequenceList( CStudioHdr* hdr, int *pSequence )
  3912. {
  3913. int nSequenceCount = hdr->GetNumSeq();
  3914. SortInfo_t *pSort = (SortInfo_t*)malloc( nSequenceCount * sizeof(SortInfo_t) );
  3915. // Set up sort info
  3916. for ( int j = 0; j < nSequenceCount; j++ )
  3917. {
  3918. pSort[j].m_nSequence = j;
  3919. ComposeSequenceDisplayName( hdr, j, pSort[j].m_szName, sizeof( pSort[j].m_szName ) );
  3920. pSort[j].m_nType = 0;
  3921. const char *pKeyValuesText = Studio_GetKeyValueText( hdr, j );
  3922. if ( !pKeyValuesText )
  3923. continue;
  3924. KeyValues *pKeyValues = new KeyValues( "sort" );
  3925. if ( pKeyValues->LoadFromBuffer( "mdl", pKeyValuesText ) )
  3926. {
  3927. KeyValues *pFacePoserKeys = pKeyValues->FindKey( "faceposer" );
  3928. if ( pFacePoserKeys )
  3929. {
  3930. const char *pType = pFacePoserKeys->GetString( "type", "" );
  3931. if ( !Q_stricmp( pType, "posture" ) )
  3932. {
  3933. pSort[j].m_nType = 2;
  3934. }
  3935. else if ( !Q_stricmp( pType, "gesture" ) )
  3936. {
  3937. pSort[j].m_nType = 1;
  3938. }
  3939. }
  3940. }
  3941. pKeyValues->deleteThis();
  3942. }
  3943. if ( g_viewerSettings.sortSequences )
  3944. {
  3945. qsort( pSort, nSequenceCount, sizeof(SortInfo_t), SortSequenceFunc );
  3946. }
  3947. for ( int i = 0; i < nSequenceCount; ++i )
  3948. {
  3949. pSequence[i] = pSort[i].m_nSequence;
  3950. }
  3951. free( pSort );
  3952. }
  3953. void ControlPanel::initSequenceChoices( int iOnlyInitSlot /* = -1 */ )
  3954. {
  3955. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  3956. if (hdr)
  3957. {
  3958. int nSequenceCount = hdr->GetNumSeq();
  3959. m_iLastSequenceCount = nSequenceCount;
  3960. int *pSequence = (int*)malloc( nSequenceCount * sizeof(int) );
  3961. CreateSortedSequenceList( hdr, pSequence );
  3962. char composedName[256];
  3963. char filter[64];
  3964. for (int i = 0; i < MAX_SEQUENCES; i++)
  3965. {
  3966. if ( iOnlyInitSlot >= 0 && i != iOnlyInitSlot )
  3967. continue;
  3968. if ( iSelectionToSequence[i] )
  3969. {
  3970. free( iSelectionToSequence[i] );
  3971. }
  3972. int iAllocSize = nSequenceCount * sizeof(int);
  3973. iSelectionToSequence[i] = (int*)malloc( iAllocSize );
  3974. memset( iSelectionToSequence[i], 0, iAllocSize );
  3975. if ( iSequenceToSelection[i] )
  3976. {
  3977. free( iSequenceToSelection[i] );
  3978. }
  3979. iSequenceToSelection[i] = (int*)malloc( iAllocSize );
  3980. memset( iSequenceToSelection[i], 0, iAllocSize );
  3981. GetSequenceFilter( i, filter, sizeof(filter) );
  3982. cSequence[i]->removeAll();
  3983. // filter sequence list
  3984. int k = 0;
  3985. for (int j = 0; j < nSequenceCount; j++)
  3986. {
  3987. int nSequence = pSequence[j];
  3988. ComposeSequenceDisplayName( hdr, nSequence, composedName, sizeof( composedName ) );
  3989. bool bFilteredOut = ( *filter && !V_stristr( composedName, filter ) );
  3990. if ( !bFilteredOut && ( g_viewerSettings.showHidden || !(hdr->pSeqdesc(nSequence).flags & STUDIO_HIDDEN) ) )
  3991. {
  3992. cSequence[i]->add( composedName );
  3993. SetSequenceForSelection( i, k, nSequence );
  3994. SetSelectionForSequence( i, nSequence, k );
  3995. k++;
  3996. }
  3997. else
  3998. {
  3999. // previous valid selection
  4000. SetSelectionForSequence( i, nSequence, (k > 0) ? (k - 1) : 0 );
  4001. }
  4002. }
  4003. if ( k == 0 )
  4004. {
  4005. ComposeSequenceDisplayName( hdr, 0, composedName, sizeof( composedName ) );
  4006. cSequence[i]->add( composedName );
  4007. SetSequenceForSelection( i, 0, 0 );
  4008. SetSelectionForSequence( i, 0, 0 );
  4009. }
  4010. cSequence[i]->select( 0 );
  4011. if ( iOnlyInitSlot == -1 )
  4012. slSequence[i]->setValue( 0 );
  4013. int iSequence = GetSequenceForSelection( i, 0 );
  4014. if (i == 0)
  4015. {
  4016. setSequence( iSequence );
  4017. showActivityModifiers( iSequence );
  4018. }
  4019. else
  4020. {
  4021. setOverlaySequence( i, iSequence, slSequence[i]->getValue() );
  4022. }
  4023. }
  4024. free( pSequence );
  4025. }
  4026. if ( iOnlyInitSlot == -1 )
  4027. {
  4028. float flMin, flMax;
  4029. for (int i = 0; i < NUM_POSEPARAMETERS; i++)
  4030. {
  4031. if (g_pStudioModel->GetPoseParameterRange( i, &flMin, &flMax ))
  4032. {
  4033. cPoseParameter[i]->removeAll();
  4034. for (int j = 0; j < hdr->GetNumPoseParameters(); j++)
  4035. {
  4036. cPoseParameter[i]->add( hdr->pPoseParameter(j).pszName() );
  4037. }
  4038. cPoseParameter[i]->select( i );
  4039. cPoseParameter[i]->setEnabled( true );
  4040. cPoseParameter[i]->setVisible( true );
  4041. slPoseParameter[i]->setEnabled( true );
  4042. slPoseParameter[i]->setRange( flMin, flMax, 1000 );
  4043. mxToolTip::add (slPoseParameter[i], hdr->pPoseParameter(i).pszName() );
  4044. slPoseParameter[i]->setVisible( true );
  4045. lePoseParameter[i]->setVisible( true );
  4046. lePoseParameter[i]->setLabel( "%.1f", 0.0 );
  4047. }
  4048. else
  4049. {
  4050. cPoseParameter[i]->setEnabled( false );
  4051. cPoseParameter[i]->setVisible( false );
  4052. slPoseParameter[i]->setEnabled( false );
  4053. slPoseParameter[i]->setVisible( false );
  4054. lePoseParameter[i]->setVisible( false );
  4055. }
  4056. slPoseParameter[i]->setValue( 0.0 );
  4057. setBlend( i, 0.0 );
  4058. }
  4059. if ( hdr )
  4060. {
  4061. for (int i = 0; i < hdr->GetNumPoseParameters(); i++)
  4062. {
  4063. setBlend( i, 0.0 );
  4064. }
  4065. }
  4066. }
  4067. }
  4068. void ControlPanel::setSequence( int nSequence )
  4069. {
  4070. int nSelection = GetSelectionForSequence( 0, nSequence );
  4071. if ( nSelection >= 0 )
  4072. {
  4073. cSequence[0]->select( nSelection );
  4074. g_pStudioModel->SetSequence( nSequence );
  4075. }
  4076. else
  4077. {
  4078. cSequence[0]->select( 0 );
  4079. g_pStudioModel->SetSequence( GetSequenceForSelection( 0, nSelection ) );
  4080. }
  4081. updateFrameSelection();
  4082. updateGroundSpeed();
  4083. }
  4084. void ControlPanel::updateGroundSpeed( void )
  4085. {
  4086. char sz[100];
  4087. float flGroundSpeed = g_pStudioModel->GetGroundSpeed();
  4088. sprintf( sz, "Speed: %.2f", flGroundSpeed );
  4089. laGroundSpeed->setLabel( sz );
  4090. }
  4091. void ControlPanel::setOverlaySequence( int num, int nSequence, float weight )
  4092. {
  4093. int nSelection = GetSelectionForSequence( num, nSequence );
  4094. if ( nSelection >= 0 )
  4095. {
  4096. cSequence[num]->select( nSelection );
  4097. g_pStudioModel->SetOverlaySequence( num-1, nSequence, weight );
  4098. }
  4099. else
  4100. {
  4101. cSequence[num]->select( 0 );
  4102. nSequence = GetSequenceForSelection( num, 0 );
  4103. g_pStudioModel->SetOverlaySequence( num-1, nSequence, weight );
  4104. }
  4105. slSequence[num]->setValue( weight );
  4106. updateFrameSelection();
  4107. }
  4108. void ControlPanel::startBlending( void )
  4109. {
  4110. g_pStudioModel->StartBlending();
  4111. }
  4112. void ControlPanel::updateTransitionAmount( void )
  4113. {
  4114. char sz[ 256 ];
  4115. sprintf( sz, "%.3f %%", 100.0f * g_pStudioModel->GetTransitionAmount() );
  4116. laBlendAmount->setLabel( sz );
  4117. }
  4118. int ControlPanel::getFrameSelection( void )
  4119. {
  4120. for ( int i = 0; i < MAX_SEQUENCES; i++ )
  4121. if ( rbFrameSelection[i]->isChecked() )
  4122. return i;
  4123. return 0;
  4124. }
  4125. void ControlPanel::setFrame( float frame )
  4126. {
  4127. int iLayer = getFrameSelection();
  4128. int iFrame = g_pStudioModel->SetFrame( iLayer, frame );
  4129. char buf[128];
  4130. sprintf(buf, "%3d", iFrame );
  4131. lForcedFrame->setLabel( buf );
  4132. }
  4133. void ControlPanel::updateFrameSelection( void )
  4134. {
  4135. int iLayer = getFrameSelection();
  4136. int maxFrame = g_pStudioModel->GetMaxFrame( iLayer );
  4137. slForceFrame->setRange( 0, maxFrame, maxFrame );
  4138. slForceFrame->setSteps(1,1);
  4139. }
  4140. void ControlPanel::updateFrameSlider( void )
  4141. {
  4142. int iLayer = getFrameSelection();
  4143. float flFrame = g_pStudioModel->GetFrame( iLayer );
  4144. char buf[128];
  4145. sprintf(buf, "%3.1f", flFrame );
  4146. lForcedFrame->setLabel( buf );
  4147. slForceFrame->setValue( flFrame );
  4148. UpdateEventHistory();
  4149. }
  4150. void ControlPanel::UpdateEventHistory( void )
  4151. {
  4152. int iLayer = getFrameSelection();
  4153. float cycle = g_pStudioModel->GetCycle( iLayer );
  4154. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4155. if ( !hdr )
  4156. {
  4157. return;
  4158. }
  4159. int sequence = 0;
  4160. if ( !iLayer )
  4161. {
  4162. sequence = g_pStudioModel->GetSequence();
  4163. }
  4164. else
  4165. {
  4166. sequence = g_pStudioModel->GetOverlaySequence( iLayer-1 );
  4167. }
  4168. if ( !hdr->SequencesAvailable() )
  4169. return;
  4170. if ( sequence < 0 || sequence >= hdr->GetNumSeq() )
  4171. return;
  4172. mstudioseqdesc_t &desc = hdr->pSeqdesc( sequence );
  4173. for ( int i=0; i<desc.numevents; ++i )
  4174. {
  4175. mstudioevent_t *e = desc.pEvent( i );
  4176. bool isInCycleRange = false;
  4177. if ( cycle >= m_lastEventCycle )
  4178. {
  4179. if ( e->cycle >= m_lastEventCycle && e->cycle < cycle )
  4180. {
  4181. isInCycleRange = true;
  4182. }
  4183. }
  4184. else
  4185. {
  4186. // wrap-around
  4187. if ( e->cycle >= m_lastEventCycle && e->cycle < 1.0f )
  4188. {
  4189. isInCycleRange = true;
  4190. }
  4191. if ( e->cycle >= 0.0f && e->cycle < cycle )
  4192. {
  4193. isInCycleRange = true;
  4194. }
  4195. }
  4196. if ( isInCycleRange )
  4197. {
  4198. const char *eventName = e->pszEventName();
  4199. const char *eventOptions = e->pszOptions();
  4200. while ( lbEventHistory->getItemCount() > 10 )
  4201. {
  4202. lbEventHistory->remove( 0 );
  4203. }
  4204. char buf[128];
  4205. if ( e->event == 0 )
  4206. {
  4207. sprintf( buf, "%.2f: %s %s", e->cycle, eventName, eventOptions );
  4208. }
  4209. else
  4210. {
  4211. sprintf( buf, "%.2f: %d %s", e->cycle, e->event, eventOptions );
  4212. }
  4213. lbEventHistory->add( buf );
  4214. int count = lbEventHistory->getItemCount();
  4215. lbEventHistory->select( count - 1 );
  4216. ComposeSequenceDisplayName( hdr, sequence, buf, sizeof( buf ) );
  4217. lEventSequence->setLabel( "%s", buf );
  4218. }
  4219. }
  4220. m_lastEventCycle = cycle;
  4221. }
  4222. void ControlPanel::setSpeedScale( float scale )
  4223. {
  4224. slSpeedScale->setValue( scale );
  4225. g_viewerSettings.speedScale = scale;
  4226. updateSpeedScale( );
  4227. }
  4228. void ControlPanel::updateSpeedScale( void )
  4229. {
  4230. char szFPS[32];
  4231. sprintf( szFPS, "x %.2f = %.1f fps", g_viewerSettings.speedScale, g_viewerSettings.speedScale * g_pStudioModel->GetFPS( ) );
  4232. laFPS->setLabel( szFPS );
  4233. }
  4234. void ControlPanel::setBlend(int index, float value )
  4235. {
  4236. g_pStudioModel->SetPoseParameter( index, value );
  4237. // reset number of frames....
  4238. updateFrameSelection( );
  4239. updateGroundSpeed( );
  4240. }
  4241. void
  4242. ControlPanel::initBodypartChoices()
  4243. {
  4244. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4245. if (hdr)
  4246. {
  4247. int i;
  4248. mstudiobodyparts_t *pbodyparts = hdr->pBodypart(0);
  4249. cBodypart->removeAll();
  4250. if (hdr->numbodyparts() > 0)
  4251. {
  4252. for (i = 0; i < hdr->numbodyparts(); i++)
  4253. cBodypart->add (pbodyparts[i].pszName());
  4254. cBodypart->select (0);
  4255. cSubmodel->removeAll();
  4256. for (i = 0; i < pbodyparts[0].nummodels; i++)
  4257. {
  4258. char str[64];
  4259. sprintf (str, "Submodel %d", i + 1);
  4260. cSubmodel->add (str);
  4261. }
  4262. cSubmodel->select (0);
  4263. }
  4264. cBodyGroupPreset->removeAll();
  4265. if ( hdr->GetNumBodyGroupPresets() > 0 )
  4266. {
  4267. const mstudiobodygrouppreset_t *pbodygrouppresets = hdr->GetBodyGroupPreset(0);
  4268. for (i = 0; i < hdr->GetNumBodyGroupPresets(); i++)
  4269. {
  4270. cBodyGroupPreset->add( pbodygrouppresets[i].pszName() );
  4271. }
  4272. cBodyGroupPreset->setEnabled( true );
  4273. }
  4274. else
  4275. {
  4276. cBodyGroupPreset->setEnabled( false );
  4277. }
  4278. }
  4279. }
  4280. void
  4281. ControlPanel::setBodypart (int index)
  4282. {
  4283. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4284. if (hdr)
  4285. {
  4286. //cBodypart->setEn
  4287. cBodypart->select (index);
  4288. if (index < hdr->numbodyparts())
  4289. {
  4290. mstudiobodyparts_t *pbodyparts = hdr->pBodypart(0);
  4291. cSubmodel->removeAll();
  4292. for (int i = 0; i < pbodyparts[index].nummodels; i++)
  4293. {
  4294. char str[64];
  4295. sprintf (str, "Submodel %d", i + 1);
  4296. cSubmodel->add (str);
  4297. }
  4298. //instead of bashing the dropdown selection to 0, select whatever the state of this bodygroup is on the model
  4299. cSubmodel->select ( g_pStudioModel->GetBodygroup( index ) );
  4300. }
  4301. }
  4302. setModelInfo();
  4303. }
  4304. void
  4305. ControlPanel::setSubmodel (int index)
  4306. {
  4307. g_pStudioModel->SetBodygroup (cBodypart->getSelectedIndex(), index);
  4308. //!!g_viewerSettings.submodels[cBodypart->getSelectedIndex()] = index;
  4309. setModelInfo();
  4310. }
  4311. void
  4312. ControlPanel::initPhysicsBones()
  4313. {
  4314. cHighlightBone->removeAll();
  4315. cHighlightBone->add( "None" );
  4316. for ( int i = 0; i < g_pStudioModel->Physics_GetBoneCount(); i++ )
  4317. {
  4318. cHighlightBone->add (g_pStudioModel->Physics_GetBoneName( i ) );
  4319. }
  4320. cHighlightBone->select (0);
  4321. }
  4322. void
  4323. ControlPanel::initIncludedModels()
  4324. {
  4325. cIncludedModels->removeAll();
  4326. cIncludedModels->add( "Included Models" );
  4327. cIncludedModels->add( "---------------" );
  4328. int iNumIncludeModels = g_pStudioModel->GetNumIncludeModels();
  4329. for ( int i=0; i<iNumIncludeModels; i++ )
  4330. {
  4331. cIncludedModels->add( g_pStudioModel->GetIncludeModelName(i) );
  4332. }
  4333. cIncludedModels->select (0);
  4334. cIncludedModels->setEnabled( iNumIncludeModels > 0 );
  4335. }
  4336. void
  4337. ControlPanel::initLODs()
  4338. {
  4339. cLODChoice->removeAll();
  4340. for ( int i = 0; i < g_pStudioModel->GetNumLODs(); i++ )
  4341. {
  4342. char tmp[10];
  4343. sprintf( tmp, "%d", i );
  4344. cLODChoice->add( tmp );
  4345. }
  4346. setLOD( 0, true, true );
  4347. }
  4348. void
  4349. ControlPanel::initBoneControllers()
  4350. {
  4351. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4352. if (hdr)
  4353. {
  4354. cController->setEnabled (hdr->numbonecontrollers() > 0);
  4355. slController->setEnabled (hdr->numbonecontrollers() > 0);
  4356. cController->removeAll();
  4357. int i = 0;
  4358. for (i; i < hdr->numbonecontrollers(); i++)
  4359. {
  4360. char str[32];
  4361. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(i);
  4362. sprintf (str, "Controller %d", pbonecontroller->inputfield);
  4363. cController->add (str);
  4364. }
  4365. if (hdr->numbonecontrollers() > 0)
  4366. {
  4367. cController->select (0);
  4368. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(0);
  4369. slController->setRange (pbonecontroller->start, pbonecontroller->end);
  4370. slController->setValue (0);
  4371. }
  4372. }
  4373. }
  4374. void
  4375. ControlPanel::setBoneController (int index)
  4376. {
  4377. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4378. if (hdr)
  4379. {
  4380. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
  4381. slController->setRange ( pbonecontroller->start, pbonecontroller->end);
  4382. slController->setValue (0);
  4383. }
  4384. }
  4385. void
  4386. ControlPanel::setBoneControllerValue (int index, float value)
  4387. {
  4388. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4389. if (hdr)
  4390. {
  4391. mstudiobonecontroller_t *pbonecontroller = hdr->pBonecontroller(index);
  4392. g_pStudioModel->SetController (pbonecontroller->inputfield, value);
  4393. }
  4394. }
  4395. void
  4396. ControlPanel::initSkinChoices()
  4397. {
  4398. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4399. if (hdr)
  4400. {
  4401. cSkin->setEnabled (hdr->numskinfamilies() > 0);
  4402. cSkin->removeAll();
  4403. for (int i = 0; i < hdr->numskinfamilies(); i++)
  4404. {
  4405. char str[32];
  4406. sprintf (str, "Skin %d", i + 1);
  4407. cSkin->add (str);
  4408. }
  4409. cSkin->select (0);
  4410. g_pStudioModel->SetSkin (0);
  4411. g_viewerSettings.skin = 0;
  4412. }
  4413. }
  4414. void ControlPanel::initMaterialChoices()
  4415. {
  4416. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4417. if (hdr)
  4418. {
  4419. const studiohdr_t *pStudioHdr = hdr->GetRenderHdr();
  4420. if (pStudioHdr)
  4421. {
  4422. cMaterials->setEnabled(pStudioHdr->numtextures > 0);
  4423. cMaterials->removeAll();
  4424. for (int i = 0; i < pStudioHdr->numtextures; i++)
  4425. {
  4426. char str[512];
  4427. sprintf (str, "%s", pStudioHdr->pTexture(i)->pszName() );
  4428. cMaterials->add (str);
  4429. }
  4430. cMaterials->select (0);
  4431. g_viewerSettings.materialIndex = 0;
  4432. }
  4433. }
  4434. }
  4435. void ControlPanel::showActivityModifiers( int sequence )
  4436. {
  4437. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4438. if ( !hdr->SequencesAvailable() )
  4439. return;
  4440. if ( sequence < 0 || sequence >= hdr->GetNumSeq() )
  4441. return;
  4442. mstudioseqdesc_t &desc = hdr->pSeqdesc( sequence );
  4443. cActivityModifiers->setEnabled( desc.numactivitymodifiers > 0);
  4444. cActivityModifiers->removeAll();
  4445. for (int i = 0; i < desc.numactivitymodifiers; i++)
  4446. {
  4447. char str[512];
  4448. sprintf (str, "%s", desc.pActivityModifier( i )->pszName() );
  4449. cActivityModifiers->add (str);
  4450. }
  4451. cActivityModifiers->select (0);
  4452. }
  4453. void
  4454. ControlPanel::GetSequenceFilter( int sequenceSlot, char *pszFilterBuf, int iBufSize )
  4455. {
  4456. if ( sequenceSlot < 0 || sequenceSlot >= MAX_SEQUENCES )
  4457. {
  4458. if ( iBufSize > 0 )
  4459. pszFilterBuf[0] = '\0';
  4460. return;
  4461. }
  4462. leSequenceFilter[sequenceSlot]->getText( pszFilterBuf, iBufSize );
  4463. }
  4464. void
  4465. ControlPanel::setModelInfo()
  4466. {
  4467. static char str[2048];
  4468. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4469. if (!hdr)
  4470. return;
  4471. static int checkSum = 0;
  4472. static int boneLODCount = 0;
  4473. static int numBatches = 0;
  4474. if ( g_pStudioModel && !m_bVMTInfoLoaded )
  4475. {
  4476. UpdateMaterialList();
  4477. UpdateMaterialVars();
  4478. }
  4479. if( checkSum == hdr->GetRenderHdr()->checksum && boneLODCount == g_DrawModelResults.m_NumHardwareBones && numBatches == g_DrawModelResults.m_NumBatches)
  4480. {
  4481. return;
  4482. }
  4483. checkSum = hdr->GetRenderHdr()->checksum;
  4484. boneLODCount = g_DrawModelResults.m_NumHardwareBones;
  4485. numBatches = g_DrawModelResults.m_NumBatches;
  4486. int hbcount = 0;
  4487. for ( int s = 0; s < hdr->numhitboxsets(); s++ )
  4488. {
  4489. hbcount += hdr->iHitboxCount( s );
  4490. }
  4491. sprintf (str,
  4492. "Total bones: %d\n"
  4493. "HW Bones: %d\n"
  4494. "Batches: %d\n"
  4495. "Bone Controllers: %d\n"
  4496. "Hit Boxes: %d in %d sets\n"
  4497. "Sequences: %d\n",
  4498. hdr->numbones(),
  4499. boneLODCount,
  4500. numBatches,
  4501. hdr->numbonecontrollers(),
  4502. hbcount,
  4503. hdr->numhitboxsets(),
  4504. hdr->GetNumSeq()
  4505. );
  4506. lModelInfo1->setLabel (str);
  4507. Vector vecHullExtent;
  4508. vecHullExtent.Init();
  4509. if ( hdr )
  4510. {
  4511. vecHullExtent.x = abs( hdr->hull_min().x - hdr->hull_max().x );
  4512. vecHullExtent.y = abs( hdr->hull_min().y - hdr->hull_max().y );
  4513. vecHullExtent.z = abs( hdr->hull_min().z - hdr->hull_max().z );
  4514. }
  4515. sprintf (str,
  4516. "Materials: %d\n"
  4517. "Skin Families: %d\n"
  4518. "Bodyparts: %d\n"
  4519. "Attachments: %d\n"
  4520. "Body index: %d\n"
  4521. "Hull extent (X): %.2f\n"
  4522. "Hull extent (Y): %.2f\n"
  4523. "Hull extent (Z): %.2f\n",
  4524. g_DrawModelResults.m_NumMaterials,
  4525. hdr->numskinfamilies(),
  4526. hdr->numbodyparts(),
  4527. hdr->GetNumAttachments(),
  4528. g_pStudioModel->GetBodyIndex(),
  4529. vecHullExtent.x,
  4530. vecHullExtent.y,
  4531. vecHullExtent.z
  4532. );
  4533. lModelInfo2->setLabel (str);
  4534. }
  4535. void ControlPanel::UpdateMaterialList( )
  4536. {
  4537. cMessageList->removeAll();
  4538. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  4539. if ( pStudioR )
  4540. {
  4541. IMaterial *pMaterials[128];
  4542. int nMaterials = g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  4543. for ( int i = 0; i < nMaterials; i++ )
  4544. {
  4545. char c_MaterialLine[256];
  4546. Q_strcpy( c_MaterialLine, "" );
  4547. if ( pMaterials[i]->IsErrorMaterial() )
  4548. {
  4549. Q_strcat( c_MaterialLine, "*** ERROR *** Model attempted to load one or more VMTs it can't find." , sizeof( c_MaterialLine ) );
  4550. }
  4551. else
  4552. {
  4553. Q_strcat( c_MaterialLine, pMaterials[i]->GetName() , sizeof( c_MaterialLine ) );
  4554. }
  4555. cMessageList->add( c_MaterialLine );
  4556. }
  4557. m_bVMTInfoLoaded = true;
  4558. }
  4559. }
  4560. void ControlPanel::UpdateMaterialVars( )
  4561. {
  4562. cMaterialList->removeAll();
  4563. cMaterialParamList->removeAll();
  4564. leMaterialParamText->clear();
  4565. //hide slider controls
  4566. slMaterialParamMatrixSliderRotation->setVisible(false);
  4567. slMaterialParamMatrixSliderScaleX->setVisible(false);
  4568. slMaterialParamMatrixSliderScaleY->setVisible(false);
  4569. slMaterialParamMatrixSliderTranslateX->setVisible(false);
  4570. slMaterialParamMatrixSliderTranslateY->setVisible(false);
  4571. lblMatrixRotation->setVisible(false);
  4572. lblMatrixScaleX->setVisible(false);
  4573. lblMatrixScaleY->setVisible(false);
  4574. lblMatrixTranslateX->setVisible(false);
  4575. lblMatrixTranslateY->setVisible(false);
  4576. slMaterialParamFloat->setVisible(false);
  4577. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  4578. if ( pStudioR )
  4579. {
  4580. IMaterial *pMaterials[128];
  4581. int nMaterials = g_pStudioRender->GetMaterialList( pStudioR, ARRAYSIZE( pMaterials ), &pMaterials[0] );
  4582. //first parse all materials to see if any materials want to hide any others
  4583. g_OnlyEditMaterialsThatWantToBeEdited = false;
  4584. for (int i = 0; i < nMaterials; i++)
  4585. {
  4586. bool bLocalHideOthersInHLMV = false;
  4587. pMaterials[i]->FindVar("$hlmvallowedit", &bLocalHideOthersInHLMV, false);
  4588. if ( bLocalHideOthersInHLMV )
  4589. {
  4590. g_OnlyEditMaterialsThatWantToBeEdited = true;
  4591. break;
  4592. }
  4593. }
  4594. for ( int i = 0; i < nMaterials; i++ )
  4595. {
  4596. char c_MaterialLine[256];
  4597. Q_strcpy( c_MaterialLine, "" );
  4598. bool bLocalHideOthersInHLMV = false;
  4599. pMaterials[i]->FindVar( "$hlmvallowedit", &bLocalHideOthersInHLMV, false );
  4600. if ( pMaterials[i]->IsErrorMaterial() )
  4601. {
  4602. Q_strcpy( c_MaterialLine, "[error] could not load material" );
  4603. }
  4604. else if ( g_OnlyEditMaterialsThatWantToBeEdited && !bLocalHideOthersInHLMV )
  4605. {
  4606. Q_strcpy( c_MaterialLine, "[ " );
  4607. Q_strcat( c_MaterialLine, V_GetFileName( pMaterials[i]->GetName() ), sizeof( c_MaterialLine ) );
  4608. Q_strcat( c_MaterialLine, " ]", sizeof( c_MaterialLine ) );
  4609. }
  4610. else
  4611. {
  4612. Q_strcat( c_MaterialLine, V_GetFileName( pMaterials[i]->GetName() ), sizeof( c_MaterialLine ) );
  4613. }
  4614. cMaterialList->add(c_MaterialLine);
  4615. }
  4616. }
  4617. }
  4618. extern matrix3x4a_t g_viewtransform;
  4619. void ControlPanel::centerView( )
  4620. {
  4621. Vector min, max;
  4622. int hitboxset = 0; //g_MDLViewer->GetCurrentHitboxSet();
  4623. min.Init( 999999,999999,999999);
  4624. max.Init( -999999,-999999,-999999);
  4625. matrix3x4_t rootxform;
  4626. MatrixInvert( g_viewtransform, rootxform );
  4627. HitboxList_t &list = g_pStudioModel->m_HitboxSets[ hitboxset ].m_Hitboxes;
  4628. for (unsigned short j = list.Head(); j != list.InvalidIndex(); j = list.Next(j) )
  4629. {
  4630. mstudiobbox_t *pBBox = &list[j].m_BBox;
  4631. Vector tmpmin, tmpmax;
  4632. matrix3x4_t bonesetup;
  4633. ConcatTransforms( rootxform, *g_pStudioModel->BoneToWorld( pBBox->bone ), bonesetup );
  4634. TransformAABB( bonesetup, pBBox->bbmin, pBBox->bbmax, tmpmin, tmpmax );
  4635. if (tmpmin.x < min.x) min.x = tmpmin.x;
  4636. if (tmpmin.y < min.y) min.y = tmpmin.y;
  4637. if (tmpmin.z < min.z) min.z = tmpmin.z;
  4638. if (tmpmax.x > max.x) max.x = tmpmax.x;
  4639. if (tmpmax.y > max.y) max.y = tmpmax.y;
  4640. if (tmpmax.z > max.z) max.z = tmpmax.z;
  4641. }
  4642. if (min.x > max.x)
  4643. {
  4644. g_pStudioModel->ExtractBbox(min, max);
  4645. }
  4646. float dx = max[0] - min[0];
  4647. float dy = max[1] - min[1];
  4648. float dz = max[2] - min[2];
  4649. // Determine the distance from the model such that it will fit in the screen.
  4650. float d = dx;
  4651. if (dy > d)
  4652. d = dy;
  4653. if (dz > d)
  4654. d = dz;
  4655. g_pStudioModel->m_origin[0] = d * 1.34f;
  4656. g_pStudioModel->m_origin[1] = 0.0f;
  4657. g_pStudioModel->m_origin[2] = min[2] + dz / 2;
  4658. g_pStudioModel->m_angles[0] = 0.0f;
  4659. g_pStudioModel->m_angles[1] = 0.0f;
  4660. g_pStudioModel->m_angles[2] = 0.0f;
  4661. g_viewerSettings.lightrot[0] = 0.0f;
  4662. g_viewerSettings.lightrot[1] = 180.0f; // light should aim at models front
  4663. g_viewerSettings.lightrot[2] = 0.0f;
  4664. setFOV( 65.0f );
  4665. d_MatSysWindow->redraw();
  4666. }
  4667. void ControlPanel::centerVerts( )
  4668. {
  4669. g_pStudioModel->m_origin[0] = 0.0f;
  4670. g_pStudioModel->m_origin[1] = 0.0f;
  4671. g_pStudioModel->m_origin[2] = 0.0f;
  4672. AngleMatrix( g_pStudioModel->m_angles, g_viewtransform );
  4673. PositionMatrix( -g_pStudioModel->m_origin, g_viewtransform );
  4674. Vector vecMin, vecMax;
  4675. g_pStudioModel->ExtractVertExtents( vecMin, vecMax );
  4676. g_pStudioModel->m_origin.x = vecMax.x;
  4677. g_pStudioModel->m_origin.y = (vecMax.y + vecMin.y) * 0.5;
  4678. g_pStudioModel->m_origin.z = (vecMax.z + vecMin.z) * 0.5;
  4679. AngleMatrix( g_pStudioModel->m_angles, g_viewtransform );
  4680. PositionMatrix( -g_pStudioModel->m_origin, g_viewtransform );
  4681. d_MatSysWindow->redraw();
  4682. }
  4683. void ControlPanel::cs_gunsidemodelView()
  4684. {
  4685. for (int i=0; i<HLMV_MAX_MERGED_MODELS; i++)
  4686. {
  4687. // FIXME: move to d_cpl
  4688. if (g_pStudioExtraModel[i])
  4689. {
  4690. g_pStudioExtraModel[i]->FreeModel( false );
  4691. delete g_pStudioExtraModel[i];
  4692. g_pStudioExtraModel[i] = NULL;
  4693. }
  4694. }
  4695. setFOV( 80.0f );
  4696. g_pStudioModel->m_angles[0] = 0.0f;
  4697. g_pStudioModel->m_angles[1] = -90.0f;
  4698. g_pStudioModel->m_angles[2] = 0.0f;
  4699. centerVerts();
  4700. Vector vecMin, vecMax;
  4701. g_pStudioModel->ExtractVertExtents( vecMin, vecMax );
  4702. g_pStudioModel->m_origin.x = MAX( MAX( MAX( abs(vecMax.z) * 2.0f, abs(vecMin.x) * 2.0f ), vecMax.y), abs(vecMin.y) );
  4703. g_pStudioModel->m_origin.x *= 1.25f;
  4704. g_viewerSettings.lightrot[0] = 0.0f;
  4705. g_viewerSettings.lightrot[1] = 180.0f;
  4706. g_viewerSettings.lightrot[2] = 0.0f;
  4707. d_MatSysWindow->redraw();
  4708. }
  4709. void ControlPanel::viewmodelView()
  4710. {
  4711. // Sit the camera at the origin with a 54 degree FOV for viewmodels
  4712. g_pStudioModel->m_origin[0] = 0.0f;
  4713. g_pStudioModel->m_origin[1] = 0.0f;
  4714. g_pStudioModel->m_origin[2] = 0.0f;
  4715. g_pStudioModel->m_angles[0] = 0.0f;
  4716. g_pStudioModel->m_angles[1] = 180.0f;
  4717. g_pStudioModel->m_angles[2] = 0.0f;
  4718. g_viewerSettings.lightrot[0] = 0.0f;
  4719. g_viewerSettings.lightrot[1] = 180.0f; // light should aim at models front
  4720. g_viewerSettings.lightrot[2] = 0.0f;
  4721. setFOV( 54.0f );
  4722. d_MatSysWindow->redraw();
  4723. }
  4724. void ControlPanel::dotaView()
  4725. {
  4726. // Set the camera to the standard DotA view
  4727. g_pStudioModel->m_origin[0] = 1334.0f;
  4728. g_pStudioModel->m_origin[1] = 0.0f;
  4729. g_pStudioModel->m_origin[2] = 0.0f;
  4730. g_pStudioModel->m_angles[0] = -60.0f;
  4731. g_pStudioModel->m_angles[1] = 180.0f;
  4732. g_pStudioModel->m_angles[2] = 0.0f;
  4733. g_viewerSettings.lightrot[YAW] = 180.0f; // light should aim at models front
  4734. g_viewerSettings.lightrot[PITCH] = 0.0f;
  4735. g_viewerSettings.lightrot[ROLL] = 0.0f;
  4736. setFOV( 65.0f );
  4737. d_MatSysWindow->redraw();
  4738. }
  4739. void ControlPanel::setFOV( float fov )
  4740. {
  4741. char buf[64];
  4742. g_viewerSettings.fov = fov;
  4743. sprintf( buf, "%.0f", fov );
  4744. leFOV->setLabel( buf );
  4745. }
  4746. void ControlPanel::setOriginAxisLength( float originAxisLength )
  4747. {
  4748. leOriginAxisLength->setValue( originAxisLength );
  4749. }
  4750. void ControlPanel::setCameraOrigin( float flX, float flY, float flZ )
  4751. {
  4752. g_pStudioModel->m_origin[0] = flX;
  4753. g_pStudioModel->m_origin[1] = flY;
  4754. g_pStudioModel->m_origin[2] = flZ;
  4755. d_MatSysWindow->redraw();
  4756. }
  4757. void ControlPanel::setCameraAngles(float flX, float flY, float flZ)
  4758. {
  4759. g_pStudioModel->m_angles[0] = flX;
  4760. g_pStudioModel->m_angles[1] = flY;
  4761. g_pStudioModel->m_angles[2] = flZ;
  4762. d_MatSysWindow->redraw();
  4763. }
  4764. void ControlPanel::setLightAngles(float flX, float flY, float flZ)
  4765. {
  4766. g_viewerSettings.lightrot[YAW] = flX;
  4767. g_viewerSettings.lightrot[PITCH] = flY;
  4768. g_viewerSettings.lightrot[ROLL] = flZ;
  4769. d_MatSysWindow->redraw();
  4770. }
  4771. void ControlPanel::setMaterialVar( const char *p_szMatParameterName, const char *p_szMatParameterValue )
  4772. {
  4773. studiohdr_t* pStudioR = g_pStudioModel->GetStudioRenderHdr();
  4774. if (!pStudioR)
  4775. return;
  4776. IMaterial *pMaterials[128];
  4777. int nMaterials = g_pStudioRender->GetMaterialList(pStudioR, ARRAYSIZE(pMaterials), &pMaterials[0]);
  4778. for (int i = 0; i < nMaterials; i++)
  4779. {
  4780. bool bFoundParam;
  4781. IMaterialVar *pThisVar = pMaterials[i]->FindVar( p_szMatParameterName, &bFoundParam, false);
  4782. if (bFoundParam)
  4783. pThisVar->SetValueAutodetectType( p_szMatParameterValue );
  4784. pMaterials[i]->RefreshPreservingMaterialVars();
  4785. }
  4786. }
  4787. void ControlPanel::redrawMatSysWin( void )
  4788. {
  4789. d_MatSysWindow->redraw();
  4790. }
  4791. //-----------------------------------------------------------------------------
  4792. // For any models in g_pStudioExtraModel, simply map the flex controllers
  4793. // locally but don't expose in the UI. Previously they weren't accessible
  4794. // at all but this will allow them to be controlled via the bone flex drivers
  4795. //-----------------------------------------------------------------------------
  4796. void ControlPanel::MapExtraFlexes( int nSlot )
  4797. {
  4798. if ( nSlot < 0 || nSlot >= ARRAYSIZE( g_pStudioExtraModel ) )
  4799. return;
  4800. StudioModel *pExtraStudioModel = g_pStudioExtraModel[ nSlot ];
  4801. if ( !pExtraStudioModel )
  4802. return;
  4803. CStudioHdr *pExtraStudioHdr = pExtraStudioModel->GetStudioHdr();
  4804. if ( !pExtraStudioHdr )
  4805. return;
  4806. for ( LocalFlexController_t i = static_cast< LocalFlexController_t >( 0 ); i < pExtraStudioHdr->numflexcontrollers(); ++i )
  4807. {
  4808. pExtraStudioHdr->pFlexcontroller( i )->localToGlobal = i;
  4809. }
  4810. }
  4811. void ControlPanel::initFlexes()
  4812. {
  4813. CStudioHdr *hdr = g_pStudioModel->GetStudioHdr();
  4814. LocalFlexController_t i;
  4815. int j;
  4816. if (hdr)
  4817. {
  4818. for (j = 0; j < NUM_FLEX_SLIDERS; j++)
  4819. {
  4820. cFlex[j]->removeAll();
  4821. for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  4822. {
  4823. cFlex[j]->add( hdr->pFlexcontroller(i)->pszName() );
  4824. }
  4825. if ( false ) // TODO: Add a configuration option to do it the sensible way
  4826. {
  4827. cFlex[j]->select( j );
  4828. }
  4829. else
  4830. {
  4831. cFlex[j]->select( hdr->numflexcontrollers() - NUM_FLEX_SLIDERS + j );
  4832. }
  4833. }
  4834. }
  4835. for (i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++)
  4836. {
  4837. g_pStudioModel->SetFlexController( i, 0.0f );
  4838. hdr->pFlexcontroller( i )->localToGlobal = i;
  4839. }
  4840. for (j = 0; j < NUM_FLEX_SLIDERS; j++)
  4841. {
  4842. i = (LocalFlexController_t)cFlex[j]->getSelectedIndex();
  4843. if (i >= 0)
  4844. {
  4845. slFlexScale[j]->setValue( g_pStudioModel->GetFlexControllerRaw( i ) );
  4846. }
  4847. }
  4848. }
  4849. static void UpdateSliderLabel( mxSlider *slider, mxLabel *label )
  4850. {
  4851. float value = slider->getValue();
  4852. char buf[80];
  4853. sprintf( buf, "%0.2f", value );
  4854. label->setLabel( buf );
  4855. }
  4856. void ControlPanel::UpdateConstraintSliders( int clamp )
  4857. {
  4858. float vmin = slPhysicsConMin->getValue();
  4859. float vmax = slPhysicsConMax->getValue();
  4860. // reflect mins/maxs
  4861. if ( cbLinked->isChecked() )
  4862. {
  4863. if ( clamp == IDC_PHYS_CON_MIN && vmin <= 0 )
  4864. {
  4865. vmax = -vmin;
  4866. }
  4867. else if ( vmax >= 0 )
  4868. {
  4869. vmin = -vmax;
  4870. }
  4871. }
  4872. if ( vmax < vmin )
  4873. {
  4874. if ( clamp == IDC_PHYS_CON_MIN )
  4875. vmin = vmax;
  4876. else
  4877. vmax = vmin;
  4878. }
  4879. slPhysicsConMin->setValue( vmin );
  4880. slPhysicsConMax->setValue( vmax );
  4881. UpdateSliderLabel( slPhysicsConMin, lPhysicsConMin );
  4882. UpdateSliderLabel( slPhysicsConMax, lPhysicsConMax );
  4883. UpdateSliderLabel( slPhysicsFriction, lPhysicsFriction );
  4884. }
  4885. int ControlPanel::handlePhysicsEvent( mxEvent *event )
  4886. {
  4887. switch( event->action )
  4888. {
  4889. case IDC_PHYS_BONE:
  4890. setupPhysicsBone( cPhysicsBone->getSelectedIndex() );
  4891. break;
  4892. case IDC_PHYS_CON_AXIS_X:
  4893. case IDC_PHYS_CON_AXIS_Y:
  4894. case IDC_PHYS_CON_AXIS_Z:
  4895. setupPhysicsAxis( cPhysicsBone->getSelectedIndex(), event->action - IDC_PHYS_CON_AXIS_X );
  4896. break;
  4897. case IDC_PHYS_CON_TYPE_FREE:
  4898. case IDC_PHYS_CON_TYPE_FIXED:
  4899. case IDC_PHYS_CON_TYPE_LIMIT:
  4900. break;
  4901. case IDC_PHYS_CON_MIN:
  4902. case IDC_PHYS_CON_MAX:
  4903. case IDC_PHYS_CON_FRICTION:
  4904. UpdateConstraintSliders( event->action );
  4905. break;
  4906. case IDC_PHYS_CON_TEST:
  4907. g_pStudioModel->Physics_SetPreview( cPhysicsBone->getSelectedIndex(), getPhysicsAxis(), slPhysicsConTest->getValue() );
  4908. break;
  4909. case IDC_PHYS_P_MASSBIAS:
  4910. UpdateSliderLabel( slPhysicsParamMassBias, lPhysicsParamMassBias );
  4911. break;
  4912. case IDC_PHYS_P_INERTIA:
  4913. UpdateSliderLabel( slPhysicsParamInertia, lPhysicsParamInertia );
  4914. break;
  4915. case IDC_PHYS_P_DAMPING:
  4916. UpdateSliderLabel( slPhysicsParamDamping, lPhysicsParamDamping );
  4917. break;
  4918. case IDC_PHYS_P_ROT_DAMPING:
  4919. UpdateSliderLabel( slPhysicsParamRotDamping, lPhysicsParamRotDamping );
  4920. break;
  4921. case IDC_PHYS_QCFILE:
  4922. {
  4923. writePhysicsData();
  4924. char *pOut = g_pStudioModel->Physics_DumpQC();
  4925. if ( pOut )
  4926. {
  4927. Sys_CopyStringToClipboard( pOut );
  4928. }
  4929. delete[] pOut;
  4930. return 1;
  4931. }
  4932. break;
  4933. }
  4934. writePhysicsData();
  4935. return 1;
  4936. }
  4937. int ControlPanel::handleSoftbodyEvent( mxEvent *event )
  4938. {
  4939. switch ( event->action )
  4940. {
  4941. case IDC_SOFT_ITERATIONS:
  4942. {
  4943. int nIterations = int( slSoftbodyIterations->getValue() );
  4944. leSoftbodyIterations->setLabel( CFmtStr( "Iterations: %d", nIterations ).Get() );
  4945. g_SoftbodyEnvironment.SetSoftbodyIterations( nIterations );
  4946. }
  4947. break;
  4948. case IDC_SOFT_SURFACE_STRETCH:
  4949. if ( CSoftbody *pSoftbody = g_pStudioModel->GetSoftbody() )
  4950. {
  4951. pSoftbody->SetSurfaceStretch( slSoftbodySurfaceStretch->getValue() );
  4952. }
  4953. break;
  4954. case IDC_SOFT_THREAD_STRETCH:
  4955. if ( CSoftbody *pSoftbody = g_pStudioModel->GetSoftbody() )
  4956. {
  4957. pSoftbody->SetThreadStretch( slSoftbodyThreadStretch->getValue() );
  4958. }
  4959. break;
  4960. case IDC_SOFT_WIND_STRENGTH:
  4961. case IDC_SOFT_WIND_YAW:
  4962. {
  4963. QAngle vecWindAngle( 0, slSoftbodyWindYaw->getValue(), 0 );
  4964. Vector vWindDir;
  4965. AngleVectors( vecWindAngle, &vWindDir );
  4966. g_SoftbodyEnvironment.SetWindDesc( vWindDir, slSoftbodyWindStrength->getValue() );
  4967. }
  4968. break;
  4969. case IDC_SOFT_SIMULATE:
  4970. g_viewerSettings.simulateSoftbodies = cbSoftbodySimulate->isChecked();
  4971. if ( CSoftbody *pSoftbody = g_pStudioModel->GetSoftbody() )
  4972. {
  4973. pSoftbody->SetPose( MatrixTransform( g_viewtransform ) );
  4974. }
  4975. break;
  4976. case IDC_SOFT_SHOW_POLYGONS:
  4977. g_viewerSettings.softbodyDrawOptions.EnableLayers( RN_SOFTBODY_DRAW_POLYGONS, cbSoftbodyPolygons->isChecked() );
  4978. break;
  4979. case IDC_SOFT_SHOW_WIND:
  4980. g_viewerSettings.softbodyDrawOptions.EnableLayers( RN_SOFTBODY_DRAW_WIND, cbSoftbodyWind->isChecked() );
  4981. break;
  4982. case IDC_SOFT_SHOW_INDICES:
  4983. g_viewerSettings.softbodyDrawOptions.EnableLayers( RN_SOFTBODY_DRAW_INDICES, cbSoftbodyIndices->isChecked() );
  4984. break;
  4985. case IDC_SOFT_SHOW_EDGES:
  4986. g_viewerSettings.softbodyDrawOptions.EnableLayers( RN_SOFTBODY_DRAW_EDGES, cbSoftbodyEdges->isChecked() );
  4987. break;
  4988. case IDC_SOFT_SHOW_BASES:
  4989. g_viewerSettings.softbodyDrawOptions.EnableLayers( RN_SOFTBODY_DRAW_BASES, cbSoftbodyBases->isChecked() );
  4990. break;
  4991. }
  4992. return 1;
  4993. }
  4994. void ControlPanel::handlePhysicsKey( mxEvent *event )
  4995. {
  4996. if ( event->key == '[' || event->key == ']' )
  4997. {
  4998. int boneIndex = cPhysicsBone->getSelectedIndex();
  4999. int boneCount = cPhysicsBone->getItemCount();
  5000. int axisIndex = getPhysicsAxis();
  5001. int axisCount = 3;
  5002. if ( event->key == '[' )
  5003. {
  5004. axisIndex = (axisIndex+axisCount-1) % axisCount;
  5005. if ( axisIndex == (axisCount-1) )
  5006. {
  5007. boneIndex = (boneIndex+boneCount-1) % boneCount;
  5008. }
  5009. }
  5010. else
  5011. {
  5012. axisIndex = (axisIndex+1) % axisCount;
  5013. if ( axisIndex == 0 )
  5014. {
  5015. boneIndex = (boneIndex+1) % boneCount;
  5016. }
  5017. }
  5018. setPhysicsAxis( axisIndex );
  5019. cPhysicsBone->select( boneIndex );
  5020. setupPhysicsBone( boneIndex );
  5021. }
  5022. }
  5023. void ControlPanel::setupPhysics( void )
  5024. {
  5025. if (!PopulatePhysicsBoneList( cPhysicsBone) )
  5026. return;
  5027. cPhysicsBone->select (0);
  5028. setPhysicsAxis(0);
  5029. setupPhysicsBone( 0 );
  5030. char buf[64];
  5031. sprintf( buf, "%.2f", g_pStudioModel->Physics_GetMass() );
  5032. leMass->setLabel( buf );
  5033. // Default to "None"
  5034. setHighlightBone(0);
  5035. }
  5036. static void SetSlider( mxSlider *slider, mxLabel *label, float value )
  5037. {
  5038. slider->setValue( value );
  5039. UpdateSliderLabel( slider, label );
  5040. }
  5041. int ControlPanel::getPhysicsAxis( void )
  5042. {
  5043. for ( int i = 0; i < 3; i++ )
  5044. if ( rbConstraintAxis[i]->isChecked() )
  5045. return i;
  5046. return 0;
  5047. }
  5048. void ControlPanel::setPhysicsAxis( int axisIndex )
  5049. {
  5050. for ( int i = 0; i < 3; i++ )
  5051. {
  5052. rbConstraintAxis[i]->setChecked( (i==axisIndex)?true : false );
  5053. }
  5054. }
  5055. void ControlPanel::setSoftbodyAxis( int axisIndex )
  5056. {
  5057. for ( int i = 0; i < 3; i++ )
  5058. {
  5059. rbSoftbodyAxis[ i ]->setChecked( ( i == axisIndex ) ? true : false );
  5060. }
  5061. }
  5062. void ControlPanel::setupPhysicsBone( int boneIndex )
  5063. {
  5064. if (!g_pStudioModel->m_pPhysics)
  5065. return;
  5066. int axisIndex = getPhysicsAxis();
  5067. setupPhysicsAxis( boneIndex, axisIndex );
  5068. // read per-bone data
  5069. hlmvsolid_t solid;
  5070. g_pStudioModel->Physics_GetData( boneIndex, &solid, NULL );
  5071. SetSlider( slPhysicsParamMassBias, lPhysicsParamMassBias, solid.massBias );
  5072. SetSlider( slPhysicsParamInertia, lPhysicsParamInertia, solid.params.inertia );
  5073. SetSlider( slPhysicsParamDamping, lPhysicsParamDamping, solid.params.damping );
  5074. SetSlider( slPhysicsParamRotDamping, lPhysicsParamRotDamping, solid.params.rotdamping );
  5075. // Find the bone
  5076. CStudioHdr* pHdr = g_pStudioModel->GetStudioHdr();
  5077. for ( int i = 0; i < pHdr->numbones(); i++ )
  5078. {
  5079. const mstudiobone_t* pBone = pHdr->pBone(i);
  5080. if (!stricmp(pBone->pszName(), solid.name ))
  5081. {
  5082. // Once found, set the surface property accordingly
  5083. lPhysicsMaterial->setLabel( g_pStudioModel->m_SurfaceProps[i].String() );
  5084. break;
  5085. }
  5086. }
  5087. // select the render/highlight bone
  5088. setHighlightBone( boneIndex + 1 );
  5089. redraw();
  5090. }
  5091. void ControlPanel::setupPhysicsAxis( int boneIndex, int axis )
  5092. {
  5093. // read the per-axis data
  5094. constraint_ragdollparams_t constraint;
  5095. g_pStudioModel->Physics_GetData( boneIndex, NULL, &constraint );
  5096. setPhysicsAxis( axis );
  5097. SetSlider( slPhysicsConMin, lPhysicsConMin, constraint.axes[axis].minRotation );
  5098. SetSlider( slPhysicsConMax, lPhysicsConMax, constraint.axes[axis].maxRotation );
  5099. SetSlider( slPhysicsFriction, lPhysicsFriction, constraint.axes[axis].torque );
  5100. g_pStudioModel->Physics_SetPreview( -1, 0, 0 );
  5101. redraw();
  5102. }
  5103. void ControlPanel::writePhysicsData( void )
  5104. {
  5105. int boneIndex = cPhysicsBone->getSelectedIndex();
  5106. int axis = getPhysicsAxis();
  5107. hlmvsolid_t solid;
  5108. constraint_ragdollparams_t constraint;
  5109. // read the existing data
  5110. g_pStudioModel->Physics_GetData( boneIndex, &solid, &constraint );
  5111. const char *pMass = leMass->getLabel();
  5112. float mass = 0;
  5113. if ( pMass )
  5114. {
  5115. mass = atof( pMass );
  5116. }
  5117. g_pStudioModel->Physics_SetMass( mass );
  5118. // write back the data we're editing on this dialog
  5119. constraint.axes[axis].minRotation = slPhysicsConMin->getValue();
  5120. constraint.axes[axis].maxRotation = slPhysicsConMax->getValue();
  5121. constraint.axes[axis].torque = slPhysicsFriction->getValue();
  5122. solid.massBias = slPhysicsParamMassBias->getValue();
  5123. solid.index = boneIndex;
  5124. //solid.params.mass;
  5125. solid.params.inertia = slPhysicsParamInertia->getValue();
  5126. solid.params.damping = slPhysicsParamDamping->getValue();
  5127. solid.params.rotdamping = slPhysicsParamRotDamping->getValue();
  5128. // store it in the model
  5129. g_pStudioModel->Physics_SetData( boneIndex, &solid, &constraint );
  5130. }
  5131. int ControlPanel::GetSequenceForSelection( int sequenceSlot, int selection )
  5132. {
  5133. DbgAssert( selection >= 0 );
  5134. return iSelectionToSequence[sequenceSlot][selection];
  5135. }
  5136. int ControlPanel::GetSelectionForSequence( int sequenceSlot, int sequence )
  5137. {
  5138. DbgAssert( sequence >= 0 );
  5139. return iSequenceToSelection[sequenceSlot][sequence];
  5140. }
  5141. int ControlPanel::SetSequenceForSelection( int sequenceSlot, int selection, int sequence )
  5142. {
  5143. DbgAssert( selection >= 0 && sequence >= 0 );
  5144. return iSelectionToSequence[sequenceSlot][selection] = sequence;
  5145. }
  5146. int ControlPanel::SetSelectionForSequence( int sequenceSlot, int sequence, int selection )
  5147. {
  5148. DbgAssert( selection >= 0 && sequence >= 0 );
  5149. return iSequenceToSelection[sequenceSlot][sequence] = selection;
  5150. }
  5151. void ControlPanel::SaveSelectedSequences( void )
  5152. {
  5153. // Save the currently selected sequences
  5154. for ( int i=0; i<MAX_SEQUENCES; i++ )
  5155. {
  5156. int index = cSequence[i]->getSelectedIndex();
  5157. int iSequence = (index >= 0 ) ? GetSequenceForSelection( i, index ) : 0;
  5158. m_iSavedSequences[i] = iSequence;
  5159. if ( i > 0 )
  5160. {
  5161. m_flSavedWeights[i] = slSequence[i]->getValue();
  5162. }
  5163. }
  5164. }
  5165. void ControlPanel::SetFrameSlider( float flFrame )
  5166. {
  5167. slForceFrame->setValue( flFrame );
  5168. }
  5169. void ControlPanel::RestoreSelectedSequences( void )
  5170. {
  5171. for ( int i=0; i<MAX_SEQUENCES; i++ )
  5172. {
  5173. int iSequence = m_iSavedSequences[i];
  5174. if ( i == 0 )
  5175. {
  5176. setSequence( iSequence );
  5177. }
  5178. else
  5179. {
  5180. setOverlaySequence( i, iSequence, m_flSavedWeights[i] );
  5181. }
  5182. }
  5183. }