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

2752 lines
64 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include <direct.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <errno.h>
  11. #include <string.h>
  12. #include <mxtk/mx.h>
  13. #include <mxtk/mxTga.h>
  14. #include <mxtk/mxEvent.h>
  15. #include "mdlviewer.h"
  16. #include "ViewerSettings.h"
  17. #include "MatSysWin.h"
  18. #include "ControlPanel.h"
  19. #include "FlexPanel.h"
  20. #include "StudioModel.h"
  21. #include "mxExpressionTray.h"
  22. #include "mxStatusWindow.h"
  23. #include "ChoreoView.h"
  24. #include "ifaceposersound.h"
  25. #include "ifaceposerworkspace.h"
  26. #include "expclass.h"
  27. #include "PhonemeEditor.h"
  28. #include "filesystem.h"
  29. #include "ExpressionTool.h"
  30. #include "ControlPanel.h"
  31. #include "choreowidgetdrawhelper.h"
  32. #include "choreoviewcolors.h"
  33. #include "tabwindow.h"
  34. #include "faceposer_models.h"
  35. #include "choiceproperties.h"
  36. #include "choreoscene.h"
  37. #include "choreoactor.h"
  38. #include "tier1/strtools.h"
  39. #include "InputProperties.h"
  40. #include "GestureTool.h"
  41. #include "SoundEmitterSystem/isoundemittersystembase.h"
  42. #include "inputsystem/iinputsystem.h"
  43. #include "RampTool.h"
  44. #include "SceneRampTool.h"
  45. #include "tier0/icommandline.h"
  46. #include "phonemeextractor/PhonemeExtractor.h"
  47. #include "animationbrowser.h"
  48. #include "CloseCaptionTool.h"
  49. #include "wavebrowser.h"
  50. #include "vcdbrowser.h"
  51. #include "ifilesystemopendialog.h"
  52. #include <vgui/ILocalize.h>
  53. #include <vgui/IVGui.h>
  54. #include "appframework/appframework.h"
  55. #include "icvar.h"
  56. #include "vstdlib/cvar.h"
  57. #include "istudiorender.h"
  58. #include "materialsystem/imaterialsystem.h"
  59. #include "vphysics_interface.h"
  60. #include "Datacache/imdlcache.h"
  61. #include "datacache/idatacache.h"
  62. #include "filesystem_init.h"
  63. #include "materialsystem/imaterialsystemhardwareconfig.h"
  64. #include "tier1/strtools.h"
  65. #include "appframework/tier3app.h"
  66. #include "faceposer_vgui.h"
  67. #include "vguiwnd.h"
  68. #include "vgui_controls/Frame.h"
  69. #include "vgui/ISurface.h"
  70. #include "p4lib/ip4.h"
  71. #include "tier2/p4helpers.h"
  72. #include "ProgressDialog.h"
  73. #include "scriplib.h"
  74. #define WINDOW_TAB_OFFSET 24
  75. MDLViewer *g_MDLViewer = 0;
  76. char g_appTitle[] = "Half-Life Face Poser";
  77. static char recentFiles[8][256] = { "", "", "", "", "", "", "", "" };
  78. using namespace vgui;
  79. //-----------------------------------------------------------------------------
  80. // Singleton interfaces
  81. //-----------------------------------------------------------------------------
  82. IPhysicsSurfaceProps *physprop;
  83. IPhysicsCollision *physcollision;
  84. IStudioDataCache *g_pStudioDataCache;
  85. vgui::ILocalize *g_pLocalize = NULL;
  86. ISoundEmitterSystemBase *soundemitter = NULL;
  87. CreateInterfaceFn g_Factory;
  88. IFileSystem *g_pFileSystem = NULL;
  89. bool g_bInError = false;
  90. static char gamedir[MAX_PATH]; // full path to gamedir U:\main\game\ep2
  91. static char gamedirsimple[MAX_PATH]; // just short name: ep2
  92. // Filesystem dialog module wrappers.
  93. CSysModule *g_pFSDialogModule = 0;
  94. CreateInterfaceFn g_FSDialogFactory = 0;
  95. #include "vgui_controls/TextEntry.h"
  96. #include "vgui_controls/Button.h"
  97. #include "vgui_controls/Label.h"
  98. #include "vgui_controls/ComboBox.h"
  99. #include "tier1/fmtstr.h"
  100. class CFacePoserVguiFrame : public Frame
  101. {
  102. DECLARE_CLASS_SIMPLE( CFacePoserVguiFrame, Frame );
  103. public:
  104. CFacePoserVguiFrame( Panel *parent, const char *panelName ) :
  105. BaseClass( parent, panelName )
  106. {
  107. SetTitle( panelName, true );
  108. SetTitleBarVisible( false );
  109. SetSizeable( false );
  110. SetMoveable( false );
  111. SetPaintBackgroundEnabled( true );
  112. SetCloseButtonVisible( false );
  113. m_pEntry = new TextEntry( this, "textentry" );
  114. m_pEntry->AddActionSignalTarget( this );
  115. m_pButton = new Button( this, "button", "Button1", this );
  116. m_pButton->SetCommand( new KeyValues( "OnButtonPressed" ) );
  117. m_pLabel = new Label( this, "label", "..." );
  118. m_pCombo = new ComboBox( this, "combo", 5, true );
  119. for ( int i = 0; i < 10; ++i )
  120. {
  121. m_pCombo->AddItem( CFmtStr( "item%02d", i + 1 ), NULL );
  122. }
  123. }
  124. MESSAGE_FUNC( OnButtonPressed, "OnButtonPressed" )
  125. {
  126. Msg( "OnButtonPressed\n" );
  127. }
  128. MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", str )
  129. {
  130. char sz[ 256 ];
  131. m_pEntry->GetText( sz, sizeof( sz ) );
  132. m_pLabel->SetText( sz );
  133. m_pCombo->GetText( sz, sizeof( sz ) );
  134. Msg( "Combo %s\n", sz );
  135. }
  136. virtual void PerformLayout()
  137. {
  138. BaseClass::PerformLayout();
  139. int w, h;
  140. GetSize( w, h );
  141. int y = 30;
  142. int skip = 20;
  143. m_pEntry->SetBounds( 5, y, w, skip - 2 );
  144. y += skip;
  145. m_pButton->SetBounds( 5, y, w, skip - 2 );
  146. y += skip;
  147. m_pCombo->SetBounds( 5, y, w, skip - 2 );
  148. y += skip;
  149. m_pLabel->SetBounds( 5, y, w, skip - 2 );
  150. y += skip;
  151. }
  152. private:
  153. TextEntry *m_pEntry;
  154. Button *m_pButton;
  155. Label *m_pLabel;
  156. ComboBox *m_pCombo;
  157. };
  158. class TestWindow : public CVGuiPanelWnd, public IFacePoserToolWindow
  159. {
  160. typedef CVGuiPanelWnd BaseClass;
  161. public:
  162. TestWindow( mxWindow *parent, int x, int y, int w, int h) :
  163. BaseClass(parent, x, y, w, h ),
  164. IFacePoserToolWindow( "FacePoser Frame", "FacePoser Frame" )
  165. {
  166. CFacePoserVguiFrame *f = new CFacePoserVguiFrame( NULL, "FacePoser Frame" );
  167. SetParentWindow( this );
  168. SetMainPanel( f );
  169. f->SetVisible( true );
  170. f->SetPaintBackgroundEnabled( true );
  171. FacePoser_MakeToolWindow( this, true );
  172. }
  173. virtual int handleEvent( mxEvent *event )
  174. {
  175. if ( HandleToolEvent( event ) )
  176. return 1;
  177. return BaseClass::handleEvent( event );
  178. }
  179. };
  180. //-----------------------------------------------------------------------------
  181. // FIXME: Remove this crap (from cmdlib.cpp)
  182. // We can't include cmdlib owing to appframework incompatibilities
  183. //-----------------------------------------------------------------------------
  184. void Q_mkdir( const char *path )
  185. {
  186. #if defined( _WIN32 ) || defined( WIN32 )
  187. if (_mkdir (path) != -1)
  188. return;
  189. #else
  190. if (mkdir (path, 0777) != -1)
  191. return;
  192. #endif
  193. if (errno != EEXIST)
  194. {
  195. Error ("mkdir %s: %s",path, strerror(errno));
  196. }
  197. }
  198. void CreatePath( const char *relative )
  199. {
  200. char fullpath[ 512 ];
  201. Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", GetGameDirectory(), relative );
  202. char *path = fullpath;
  203. char *ofs, c;
  204. if (path[1] == ':')
  205. {
  206. path += 2;
  207. }
  208. for (ofs = const_cast<char*>(path+1); *ofs ; ofs++)
  209. {
  210. c = *ofs;
  211. if (c == '/' || c == '\\')
  212. {
  213. // create the directory, but not if it's actually a filename with a dot in it!!!
  214. *ofs = 0;
  215. if ( !Q_stristr( path, "." ) )
  216. {
  217. Q_mkdir (path);
  218. }
  219. *ofs = c;
  220. }
  221. }
  222. }
  223. //-----------------------------------------------------------------------------
  224. // LoadFile
  225. //-----------------------------------------------------------------------------
  226. int LoadFile (const char *filename, void **bufferptr)
  227. {
  228. FileHandle_t f = filesystem->Open( filename, "rb" );
  229. int length = filesystem->Size( f );
  230. void *buffer = malloc (length+1);
  231. ((char *)buffer)[length] = 0;
  232. if ( filesystem->Read (buffer, length, f) != (int)length )
  233. {
  234. Error ("File read failure");
  235. }
  236. filesystem->Close (f);
  237. *bufferptr = buffer;
  238. return length;
  239. }
  240. char *ExpandPath(char *path)
  241. {
  242. static char full[1024];
  243. if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
  244. return path;
  245. V_sprintf_safe( full, "%s%s", gamedir, path );
  246. return full;
  247. }
  248. //-----------------------------------------------------------------------------
  249. // This is here because scriplib.cpp is included in this project but cmdlib.cpp
  250. // is not, but scriplib.cpp uses some stuff from cmdlib.cpp, same with
  251. // LoadFile and ExpandPath above. The only thing that currently uses this
  252. // is $include in scriptlib, if this function returns 0, $include will
  253. // behave the way it did before this change
  254. //-----------------------------------------------------------------------------
  255. int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath )
  256. {
  257. return 0;
  258. }
  259. //-----------------------------------------------------------------------------
  260. // FIXME: Move into appsystem framework
  261. //-----------------------------------------------------------------------------
  262. void LoadFileSystemDialogModule()
  263. {
  264. Assert( !g_pFSDialogModule );
  265. // Load the module with the file system open dialog.
  266. const char *pDLLName = "FileSystemOpenDialog.dll";
  267. g_pFSDialogModule = Sys_LoadModule( pDLLName );
  268. if ( g_pFSDialogModule )
  269. {
  270. g_FSDialogFactory = Sys_GetFactory( g_pFSDialogModule );
  271. }
  272. if ( !g_pFSDialogModule || !g_FSDialogFactory )
  273. {
  274. if ( g_pFSDialogModule )
  275. {
  276. Sys_UnloadModule( g_pFSDialogModule );
  277. g_pFSDialogModule = NULL;
  278. }
  279. }
  280. }
  281. void UnloadFileSystemDialogModule()
  282. {
  283. if ( g_pFSDialogModule )
  284. {
  285. Sys_UnloadModule( g_pFSDialogModule );
  286. g_pFSDialogModule = 0;
  287. }
  288. }
  289. void
  290. MDLViewer::initRecentFiles ()
  291. {
  292. for (int i = 0; i < 8; i++)
  293. {
  294. if (strlen (recentFiles[i]))
  295. {
  296. mb->modify (IDC_FILE_RECENTFILES1 + i, IDC_FILE_RECENTFILES1 + i, recentFiles[i]);
  297. }
  298. else
  299. {
  300. mb->modify (IDC_FILE_RECENTFILES1 + i, IDC_FILE_RECENTFILES1 + i, "(empty)");
  301. mb->setEnabled (IDC_FILE_RECENTFILES1 + i, false);
  302. }
  303. }
  304. }
  305. #define RECENTFILESPATH "/hlfaceposer.rf"
  306. void
  307. MDLViewer::loadRecentFiles ()
  308. {
  309. char path[256];
  310. strcpy (path, mx::getApplicationPath ());
  311. strcat (path, RECENTFILESPATH);
  312. FILE *file = fopen (path, "rb");
  313. if (file)
  314. {
  315. fread (recentFiles, sizeof recentFiles, 1, file);
  316. fclose (file);
  317. }
  318. }
  319. void
  320. MDLViewer::saveRecentFiles ()
  321. {
  322. char path[256];
  323. strcpy (path, mx::getApplicationPath ());
  324. strcat (path, RECENTFILESPATH);
  325. FILE *file = fopen (path, "wb");
  326. if (file)
  327. {
  328. fwrite (recentFiles, sizeof recentFiles, 1, file);
  329. fclose (file);
  330. }
  331. }
  332. bool MDLViewer::AreSoundScriptsDirty()
  333. {
  334. // Save any changed sound script files
  335. int c = soundemitter->GetNumSoundScripts();
  336. for ( int i = 0; i < c; i++ )
  337. {
  338. if ( soundemitter->IsSoundScriptDirty( i ) )
  339. {
  340. return true;
  341. }
  342. }
  343. return false;
  344. }
  345. bool MDLViewer::CanClose()
  346. {
  347. Con_Printf( "Checking for vcd changes...\n" );
  348. if ( m_bVCDSaved )
  349. {
  350. int retval = mxMessageBox( NULL, "Rebuild scenes.image?", g_appTitle, MX_MB_YESNOCANCEL );
  351. if ( retval == 2 )
  352. {
  353. return false;
  354. }
  355. m_bVCDSaved = false;
  356. if ( retval == 0 ) // YES
  357. {
  358. OnRebuildScenesImage();
  359. }
  360. }
  361. Con_Printf( "Checking for sound script changes...\n" );
  362. // Save any changed sound script files
  363. int c = soundemitter->GetNumSoundScripts();
  364. for ( int i = 0; i < c; i++ )
  365. {
  366. if ( !soundemitter->IsSoundScriptDirty( i ) )
  367. continue;
  368. char const *scriptname = soundemitter->GetSoundScriptName( i );
  369. if ( !scriptname )
  370. continue;
  371. if ( !filesystem->FileExists( scriptname ) ||
  372. !filesystem->IsFileWritable( scriptname ) )
  373. {
  374. continue;
  375. }
  376. int retval = mxMessageBox( NULL, va( "Save changes to sound script '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
  377. if ( retval == 2 )
  378. {
  379. return false;
  380. }
  381. if ( retval == 0 )
  382. {
  383. soundemitter->SaveChangesToSoundScript( i );
  384. }
  385. }
  386. SaveWindowPositions();
  387. models->SaveModelList();
  388. models->CloseAllModels();
  389. return true;
  390. }
  391. bool MDLViewer::Closing( void )
  392. {
  393. return true;
  394. }
  395. #define IDC_GRIDSETTINGS_FPS 1001
  396. #define IDC_GRIDSETTINGS_SNAP 1002
  397. class CFlatButton : public mxButton
  398. {
  399. public:
  400. CFlatButton( mxWindow *parent, int id )
  401. : mxButton( parent, 0, 0, 0, 0, "", id )
  402. {
  403. HWND wnd = (HWND)getHandle();
  404. DWORD exstyle = GetWindowLong( wnd, GWL_EXSTYLE );
  405. exstyle |= WS_EX_CLIENTEDGE;
  406. SetWindowLong( wnd, GWL_EXSTYLE, exstyle );
  407. DWORD style = GetWindowLong( wnd, GWL_STYLE );
  408. style &= ~WS_BORDER;
  409. SetWindowLong( wnd, GWL_STYLE, style );
  410. }
  411. };
  412. class CMDLViewerGridSettings : public mxWindow
  413. {
  414. public:
  415. typedef mxWindow BaseClass;
  416. CMDLViewerGridSettings( mxWindow *parent, int x, int y, int w, int h ) :
  417. mxWindow( parent, x, y, w, h )
  418. {
  419. FacePoser_AddWindowStyle( this, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
  420. m_btnFPS = new CFlatButton( this, IDC_GRIDSETTINGS_FPS );
  421. m_btnGridSnap = new CFlatButton( this, IDC_GRIDSETTINGS_SNAP );
  422. }
  423. void Init( void )
  424. {
  425. if ( g_pChoreoView )
  426. {
  427. CChoreoScene *scene = g_pChoreoView->GetScene();
  428. if ( scene )
  429. {
  430. char sz[ 256 ];
  431. Q_snprintf( sz, sizeof( sz ), "%i fps", scene->GetSceneFPS() );
  432. m_btnFPS->setLabel( sz );
  433. Q_snprintf( sz, sizeof( sz ), "snap: %s", scene->IsUsingFrameSnap() ? "on" : "off" );
  434. m_btnGridSnap->setLabel( sz );
  435. m_btnFPS->setVisible( true );
  436. m_btnGridSnap->setVisible( true );
  437. return;
  438. }
  439. }
  440. m_btnFPS->setVisible( false );
  441. m_btnGridSnap->setVisible( false );
  442. }
  443. virtual int handleEvent( mxEvent *event )
  444. {
  445. int iret = 0;
  446. switch ( event->event )
  447. {
  448. default:
  449. break;
  450. case mxEvent::Size:
  451. {
  452. int leftedge = w2() * 0.45f;
  453. m_btnFPS->setBounds( 0, 0, leftedge, h2() );
  454. m_btnGridSnap->setBounds( leftedge, 0, w2() - leftedge, h2() );
  455. iret = 1;
  456. }
  457. break;
  458. case mxEvent::Action:
  459. {
  460. iret = 1;
  461. switch ( event->action )
  462. {
  463. default:
  464. iret = 0;
  465. break;
  466. case IDC_GRIDSETTINGS_FPS:
  467. {
  468. if ( g_pChoreoView )
  469. {
  470. CChoreoScene *scene = g_pChoreoView->GetScene();
  471. if ( scene )
  472. {
  473. int currentFPS = scene->GetSceneFPS();
  474. CInputParams params;
  475. memset( &params, 0, sizeof( params ) );
  476. strcpy( params.m_szDialogTitle, "Change FPS" );
  477. Q_snprintf( params.m_szInputText, sizeof( params.m_szInputText ),
  478. "%i", currentFPS );
  479. strcpy( params.m_szPrompt, "Current FPS:" );
  480. if ( InputProperties( &params ) )
  481. {
  482. int newFPS = atoi( params.m_szInputText );
  483. if ( ( newFPS > 0 ) && ( newFPS != currentFPS ) )
  484. {
  485. g_pChoreoView->SetDirty( true );
  486. g_pChoreoView->PushUndo( "Change Scene FPS" );
  487. scene->SetSceneFPS( newFPS );
  488. g_pChoreoView->PushRedo( "Change Scene FPS" );
  489. Init();
  490. Con_Printf( "FPS changed to %i\n", newFPS );
  491. }
  492. }
  493. }
  494. }
  495. }
  496. break;
  497. case IDC_GRIDSETTINGS_SNAP:
  498. {
  499. if ( g_pChoreoView )
  500. {
  501. CChoreoScene *scene = g_pChoreoView->GetScene();
  502. if ( scene )
  503. {
  504. g_pChoreoView->SetDirty( true );
  505. g_pChoreoView->PushUndo( "Change Snap Frame" );
  506. scene->SetUsingFrameSnap( !scene->IsUsingFrameSnap() );
  507. g_pChoreoView->PushRedo( "Change Snap Frame" );
  508. Init();
  509. Con_Printf( "Time frame snapping: %s\n",
  510. scene->IsUsingFrameSnap() ? "on" : "off" );
  511. }
  512. }
  513. }
  514. break;
  515. }
  516. }
  517. }
  518. return iret;
  519. }
  520. bool PaintBackground( void )
  521. {
  522. CChoreoWidgetDrawHelper drawHelper( this );
  523. RECT rc;
  524. drawHelper.GetClientRect( rc );
  525. drawHelper.DrawFilledRect( GetSysColor( COLOR_BTNFACE ), rc );
  526. return false;
  527. }
  528. private:
  529. CFlatButton *m_btnFPS;
  530. CFlatButton *m_btnGridSnap;
  531. };
  532. #define IDC_MODELTAB_LOAD 1000
  533. #define IDC_MODELTAB_CLOSE 1001
  534. #define IDC_MODELTAB_CLOSEALL 1002
  535. #define IDC_MODELTAB_CENTERONFACE 1003
  536. #define IDC_MODELTAB_ASSOCIATEACTOR 1004
  537. #define IDC_MODELTAB_TOGGLE3DVIEW 1005
  538. #define IDC_MODELTAB_SHOWALL 1006
  539. #define IDC_MODELTAB_HIDEALL 1007
  540. //-----------------------------------------------------------------------------
  541. // Purpose:
  542. //-----------------------------------------------------------------------------
  543. class CMDLViewerModelTab : public CTabWindow
  544. {
  545. public:
  546. typedef CTabWindow BaseClass;
  547. CMDLViewerModelTab( mxWindow *parent, int x, int y, int w, int h, int id = 0, int style = 0 ) :
  548. CTabWindow( parent, x, y, w, h, id, style )
  549. {
  550. SetInverted( true );
  551. }
  552. virtual void ShowRightClickMenu( int mx, int my )
  553. {
  554. mxPopupMenu *pop = new mxPopupMenu();
  555. Assert( pop );
  556. char const *current = "";
  557. char const *filename = "";
  558. int idx = getSelectedIndex();
  559. if ( idx >= 0 )
  560. {
  561. current = models->GetModelName( idx );
  562. filename = models->GetModelFileName( idx );
  563. }
  564. if ( models->Count() < MAX_FP_MODELS )
  565. {
  566. pop->add( "Load Model...", IDC_MODELTAB_LOAD );
  567. }
  568. if ( idx >= 0 )
  569. {
  570. pop->add( va( "Close '%s'", current ), IDC_MODELTAB_CLOSE );
  571. }
  572. if ( models->Count() > 0 )
  573. {
  574. pop->add( "Close All", IDC_MODELTAB_CLOSEALL );
  575. }
  576. if ( idx >= 0 )
  577. {
  578. pop->addSeparator();
  579. pop->add( va( "Center %s's face", current ), IDC_MODELTAB_CENTERONFACE );
  580. CChoreoScene *scene = g_pChoreoView->GetScene();
  581. if ( scene )
  582. {
  583. // See if there is already an actor with this model associated
  584. int c = scene->GetNumActors();
  585. bool hasassoc = false;
  586. for ( int i = 0; i < c; i++ )
  587. {
  588. CChoreoActor *a = scene->GetActor( i );
  589. Assert( a );
  590. if ( stricmp( a->GetFacePoserModelName(), filename ) )
  591. continue;
  592. hasassoc = true;
  593. break;
  594. }
  595. if ( hasassoc )
  596. {
  597. pop->add( va( "Change associated actor for %s", current ), IDC_MODELTAB_ASSOCIATEACTOR );
  598. }
  599. else
  600. {
  601. pop->add( va( "Associate actor to %s", current ), IDC_MODELTAB_ASSOCIATEACTOR );
  602. }
  603. }
  604. pop->addSeparator();
  605. bool visible = models->IsModelShownIn3DView( idx );
  606. if ( visible )
  607. {
  608. pop->add( va( "Remove %s from 3D View", current ), IDC_MODELTAB_TOGGLE3DVIEW );
  609. }
  610. else
  611. {
  612. pop->add( va( "Show %s in 3D View", current ), IDC_MODELTAB_TOGGLE3DVIEW );
  613. }
  614. }
  615. if ( models->Count() > 0 )
  616. {
  617. pop->addSeparator();
  618. pop->add( "Show All", IDC_MODELTAB_SHOWALL );
  619. pop->add( "Hide All", IDC_MODELTAB_HIDEALL );
  620. }
  621. // Convert click position
  622. POINT pt;
  623. pt.x = mx;
  624. pt.y = my;
  625. // Convert coordinate space
  626. pop->popup( this, pt.x, pt.y );
  627. }
  628. virtual int handleEvent( mxEvent *event )
  629. {
  630. int iret = 0;
  631. switch ( event->event )
  632. {
  633. default:
  634. break;
  635. case mxEvent::Action:
  636. {
  637. iret = 1;
  638. switch ( event->action )
  639. {
  640. default:
  641. iret = 0;
  642. break;
  643. case IDC_MODELTAB_SHOWALL:
  644. case IDC_MODELTAB_HIDEALL:
  645. {
  646. bool show = ( event->action == IDC_MODELTAB_SHOWALL ) ? true : false;
  647. int c = models->Count();
  648. for ( int i = 0; i < c ; i++ )
  649. {
  650. models->ShowModelIn3DView( i, show );
  651. }
  652. }
  653. break;
  654. case IDC_MODELTAB_LOAD:
  655. {
  656. if ( ! CommandLine()->FindParm( "-NoSteamDialog" ) )
  657. {
  658. g_MDLViewer->LoadModel_Steam();
  659. }
  660. else
  661. {
  662. char modelfile[ 512 ];
  663. if ( FacePoser_ShowOpenFileNameDialog( modelfile, sizeof( modelfile ), "models", "*.mdl" ) )
  664. {
  665. g_MDLViewer->LoadModelFile( modelfile );
  666. }
  667. }
  668. }
  669. break;
  670. case IDC_MODELTAB_CLOSE:
  671. {
  672. int idx = getSelectedIndex();
  673. if ( idx >= 0 )
  674. {
  675. models->FreeModel( idx );
  676. }
  677. }
  678. break;
  679. case IDC_MODELTAB_CLOSEALL:
  680. {
  681. models->CloseAllModels();
  682. }
  683. break;
  684. case IDC_MODELTAB_CENTERONFACE:
  685. {
  686. g_pControlPanel->CenterOnFace();
  687. }
  688. break;
  689. case IDC_MODELTAB_TOGGLE3DVIEW:
  690. {
  691. int idx = getSelectedIndex();
  692. if ( idx >= 0 )
  693. {
  694. bool visible = models->IsModelShownIn3DView( idx );
  695. models->ShowModelIn3DView( idx, !visible );
  696. }
  697. }
  698. break;
  699. case IDC_MODELTAB_ASSOCIATEACTOR:
  700. {
  701. int idx = getSelectedIndex();
  702. if ( idx >= 0 )
  703. {
  704. char const *modelname = models->GetModelFileName( idx );
  705. CChoreoScene *scene = g_pChoreoView->GetScene();
  706. if ( scene )
  707. {
  708. CChoiceParams params;
  709. strcpy( params.m_szDialogTitle, "Associate Actor" );
  710. params.m_bPositionDialog = false;
  711. params.m_nLeft = 0;
  712. params.m_nTop = 0;
  713. strcpy( params.m_szPrompt, "Choose actor:" );
  714. params.m_Choices.RemoveAll();
  715. params.m_nSelected = -1;
  716. int oldsel = -1;
  717. int c = scene->GetNumActors();
  718. ChoiceText text;
  719. for ( int i = 0; i < c; i++ )
  720. {
  721. CChoreoActor *a = scene->GetActor( i );
  722. Assert( a );
  723. strcpy( text.choice, a->GetName() );
  724. if ( !stricmp( a->GetFacePoserModelName(), modelname ) )
  725. {
  726. params.m_nSelected = i;
  727. oldsel = -1;
  728. }
  729. params.m_Choices.AddToTail( text );
  730. }
  731. if ( ChoiceProperties( &params ) &&
  732. params.m_nSelected != oldsel )
  733. {
  734. // Chose something new...
  735. CChoreoActor *a = scene->GetActor( params.m_nSelected );
  736. g_pChoreoView->AssociateModelToActor( a, idx );
  737. }
  738. }
  739. }
  740. }
  741. }
  742. }
  743. break;
  744. }
  745. if ( iret )
  746. return iret;
  747. return BaseClass::handleEvent( event );
  748. }
  749. void HandleModelSelect( void )
  750. {
  751. int idx = getSelectedIndex();
  752. if ( idx < 0 )
  753. return;
  754. // FIXME: Do any necessary window resetting here!!!
  755. g_pControlPanel->ChangeModel( models->GetModelFileName( idx ) );
  756. }
  757. void Init( void )
  758. {
  759. removeAll();
  760. int c = models->Count();
  761. int i;
  762. for ( i = 0; i < c ; i++ )
  763. {
  764. char const *name = models->GetModelName( i );
  765. // Strip it down to the base name
  766. char cleanname[ 256 ];
  767. Q_FileBase( name, cleanname, sizeof( cleanname ) );
  768. add( cleanname );
  769. }
  770. }
  771. };
  772. #define IDC_TOOL_TOGGLEVISIBILITY 1000
  773. #define IDC_TOOL_TOGGLELOCK 1001
  774. //-----------------------------------------------------------------------------
  775. // Purpose:
  776. //-----------------------------------------------------------------------------
  777. class CMDLViewerWindowTab : public CTabWindow
  778. {
  779. public:
  780. typedef CTabWindow BaseClass;
  781. CMDLViewerWindowTab( mxWindow *parent, int x, int y, int w, int h, int id = 0, int style = 0 ) :
  782. CTabWindow( parent, x, y, w, h, id, style )
  783. {
  784. SetInverted( true );
  785. m_nLastSelected = -1;
  786. m_flLastSelectedTime = -1;
  787. }
  788. virtual void ShowRightClickMenu( int mx, int my )
  789. {
  790. IFacePoserToolWindow *tool = GetSelectedTool();
  791. if ( !tool )
  792. return;
  793. mxWindow *toolw = tool->GetMxWindow();
  794. if ( !toolw )
  795. return;
  796. mxPopupMenu *pop = new mxPopupMenu();
  797. Assert( pop );
  798. bool isVisible = toolw->isVisible();
  799. bool isLocked = tool->IsLocked();
  800. pop->add( isVisible ? "Hide" : "Show", IDC_TOOL_TOGGLEVISIBILITY );
  801. pop->add( isLocked ? "Unlock" : "Lock", IDC_TOOL_TOGGLELOCK );
  802. // Convert click position
  803. POINT pt;
  804. pt.x = mx;
  805. pt.y = my;
  806. /*
  807. ClientToScreen( (HWND)getHandle(), &pt );
  808. ScreenToClient( (HWND)g_MDLViewer->getHandle(), &pt );
  809. */
  810. // Convert coordinate space
  811. pop->popup( this, pt.x, pt.y );
  812. }
  813. virtual int handleEvent( mxEvent *event )
  814. {
  815. int iret = 0;
  816. switch ( event->event )
  817. {
  818. case mxEvent::Action:
  819. {
  820. iret = 1;
  821. switch ( event->action )
  822. {
  823. default:
  824. iret = 0;
  825. break;
  826. case IDC_TOOL_TOGGLEVISIBILITY:
  827. {
  828. IFacePoserToolWindow *tool = GetSelectedTool();
  829. if ( tool )
  830. {
  831. mxWindow *toolw = tool->GetMxWindow();
  832. if ( toolw )
  833. {
  834. toolw->setVisible( !toolw->isVisible() );
  835. g_MDLViewer->UpdateWindowMenu();
  836. }
  837. }
  838. }
  839. break;
  840. case IDC_TOOL_TOGGLELOCK:
  841. {
  842. IFacePoserToolWindow *tool = GetSelectedTool();
  843. if ( tool )
  844. {
  845. tool->ToggleLockedState();
  846. }
  847. }
  848. break;
  849. }
  850. }
  851. break;
  852. default:
  853. break;
  854. }
  855. if ( iret )
  856. return iret;
  857. return BaseClass::handleEvent( event );
  858. }
  859. void Init( void )
  860. {
  861. int c = IFacePoserToolWindow::GetToolCount();
  862. int i;
  863. for ( i = 0; i < c ; i++ )
  864. {
  865. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
  866. add( tool->GetDisplayNameRoot() );
  867. }
  868. }
  869. #define WINDOW_DOUBLECLICK_TIME 0.4
  870. void HandleWindowSelect( void )
  871. {
  872. extern double realtime;
  873. IFacePoserToolWindow *tool = GetSelectedTool();
  874. if ( !tool )
  875. return;
  876. bool doubleclicked = false;
  877. double curtime = realtime;
  878. int clickedItem = getSelectedIndex();
  879. if ( clickedItem == m_nLastSelected )
  880. {
  881. if ( curtime < m_flLastSelectedTime + WINDOW_DOUBLECLICK_TIME )
  882. {
  883. doubleclicked = true;
  884. }
  885. }
  886. m_flLastSelectedTime = curtime;
  887. m_nLastSelected = clickedItem;
  888. mxWindow *toolw = tool->GetMxWindow();
  889. if ( !toolw )
  890. return;
  891. if ( doubleclicked )
  892. {
  893. toolw->setVisible( !toolw->isVisible() );
  894. m_flLastSelectedTime = -1;
  895. }
  896. if ( !toolw->isVisible() )
  897. {
  898. return;
  899. }
  900. // Move window to front
  901. HWND wnd = (HWND)tool->GetMxWindow()->getHandle();
  902. SetFocus( wnd );
  903. SetWindowPos( wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  904. }
  905. private:
  906. IFacePoserToolWindow *GetSelectedTool()
  907. {
  908. int idx = getSelectedIndex();
  909. int c = IFacePoserToolWindow::GetToolCount();
  910. if ( idx < 0 || idx >= c )
  911. return NULL;
  912. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( idx );
  913. return tool;
  914. }
  915. // HACKY double click handler
  916. int m_nLastSelected;
  917. double m_flLastSelectedTime;
  918. };
  919. //-----------------------------------------------------------------------------
  920. // Purpose: The workspace is the parent of all of the tool windows
  921. //-----------------------------------------------------------------------------
  922. class CMDLViewerWorkspace : public mxWindow
  923. {
  924. public:
  925. CMDLViewerWorkspace( mxWindow *parent, int x, int y, int w, int h, const char *label = 0, int style = 0)
  926. : mxWindow( parent, x, y, w, h, label, style )
  927. {
  928. FacePoser_AddWindowStyle( this, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
  929. }
  930. //-----------------------------------------------------------------------------
  931. // Purpose:
  932. // Output : Returns true on success, false on failure.
  933. //-----------------------------------------------------------------------------
  934. bool PaintBackground( void )
  935. {
  936. CChoreoWidgetDrawHelper drawHelper( this );
  937. RECT rc;
  938. drawHelper.GetClientRect( rc );
  939. drawHelper.DrawFilledRect( GetSysColor( COLOR_APPWORKSPACE ), rc );
  940. return false;
  941. }
  942. };
  943. void MDLViewer::LoadPosition( void )
  944. {
  945. bool visible;
  946. bool locked;
  947. bool zoomed;
  948. int x, y, w, h;
  949. FacePoser_LoadWindowPositions( "MDLViewer", visible, x, y, w, h, locked, zoomed );
  950. if ( w == 0 || h == 0 )
  951. {
  952. zoomed = true;
  953. visible = true;
  954. }
  955. setBounds( x, y, w, h );
  956. if ( zoomed )
  957. {
  958. ShowWindow( (HWND)getHandle(), SW_SHOWMAXIMIZED );
  959. }
  960. else
  961. {
  962. setVisible( visible );
  963. }
  964. }
  965. void MDLViewer::SavePosition( void )
  966. {
  967. bool visible;
  968. int xpos, ypos, width, height;
  969. visible = isVisible();
  970. xpos = x();
  971. ypos = y();
  972. width = w();
  973. height = h();
  974. // xpos and ypos are screen space
  975. POINT pt;
  976. pt.x = xpos;
  977. pt.y = ypos;
  978. // Convert from screen space to relative to client area of parent window so
  979. // the setBounds == MoveWindow call will offset to the same location
  980. if ( getParent() )
  981. {
  982. ScreenToClient( (HWND)getParent()->getHandle(), &pt );
  983. xpos = (short)pt.x;
  984. ypos = (short)pt.y;
  985. }
  986. bool zoomed = IsZoomed( (HWND)getHandle() ) ? true : false;
  987. bool iconic = IsIconic( (HWND)getHandle() ) ? true : false;
  988. // Don't reset values if it's minimized during shutdown
  989. if ( iconic )
  990. return;
  991. FacePoser_SaveWindowPositions( "MDLViewer", visible, xpos, ypos, width, height, false, zoomed );
  992. }
  993. MDLViewer::MDLViewer () :
  994. mxWindow (0, 0, 0, 0, 0, g_appTitle, mxWindow::Normal),
  995. menuCloseCaptionLanguages(0),
  996. m_bOldSoundScriptsDirty( -1 ),
  997. m_bVCDSaved( false )
  998. {
  999. int i;
  1000. g_MDLViewer = this;
  1001. FacePoser_MakeToolWindow( this, false );
  1002. workspace = new CMDLViewerWorkspace( this, 0, 0, 500, 500, "" );
  1003. windowtab = new CMDLViewerWindowTab( this, 0, 500, 500, 20, IDC_WINDOW_TAB );
  1004. modeltab = new CMDLViewerModelTab( this, 500, 500, 200, 20, IDC_MODEL_TAB );
  1005. gridsettings = new CMDLViewerGridSettings( this, 0, 500, 500, 20 );
  1006. modeltab->SetRightJustify( true );
  1007. g_pStatusWindow = new mxStatusWindow( workspace, 0, 0, 1024, 150, "" );
  1008. g_pStatusWindow->setVisible( true );
  1009. InitViewerSettings( "faceposer" );
  1010. g_viewerSettings.speechapiindex = SPEECH_API_LIPSINC;
  1011. g_viewerSettings.m_iEditAttachment = -1;
  1012. LoadViewerRootSettings( );
  1013. LoadPosition();
  1014. // ShowWindow( (HWND)getHandle(), SW_SHOWMAXIMIZED );
  1015. g_pStatusWindow->setBounds( 0, h2() - 150, w2(), 150 );
  1016. Con_Printf( "MDLViewer started\n" );
  1017. Con_Printf( "Creating menu bar\n" );
  1018. // create menu stuff
  1019. mb = new mxMenuBar (this);
  1020. menuFile = new mxMenu ();
  1021. menuOptions = new mxMenu ();
  1022. menuWindow = new mxMenu ();
  1023. menuHelp = new mxMenu ();
  1024. menuEdit = new mxMenu ();
  1025. menuExpressions = new mxMenu();
  1026. menuChoreography = new mxMenu();
  1027. mb->addMenu ("File", menuFile);
  1028. //mb->addMenu( "Edit", menuEdit );
  1029. mb->addMenu ("Options", menuOptions);
  1030. mb->addMenu ( "Expression", menuExpressions );
  1031. mb->addMenu ( "Choreography", menuChoreography );
  1032. mb->addMenu ("Window", menuWindow);
  1033. mb->addMenu ("Help", menuHelp);
  1034. mxMenu *menuRecentFiles = new mxMenu ();
  1035. menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES1);
  1036. menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES2);
  1037. menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES3);
  1038. menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES4);
  1039. menuFile->add ("Load Model...", IDC_FILE_LOADMODEL);
  1040. menuFile->add( "Refresh\tF5", IDC_FILE_REFRESH );
  1041. menuFile->addSeparator();
  1042. menuFile->add ("Save Sound Changes...", IDC_FILE_SAVESOUNDSCRIPTCHANGES );
  1043. menuFile->add( "Rebuild scenes.image...", IDC_FILE_REBUILDSCENESIMAGE );
  1044. menuFile->addSeparator();
  1045. menuFile->add ("Load Background Texture...", IDC_FILE_LOADBACKGROUNDTEX);
  1046. menuFile->add ("Load Ground Texture...", IDC_FILE_LOADGROUNDTEX);
  1047. menuFile->addSeparator ();
  1048. menuFile->add ("Unload Ground Texture", IDC_FILE_UNLOADGROUNDTEX);
  1049. menuFile->addSeparator ();
  1050. menuFile->addMenu ("Recent Files", menuRecentFiles);
  1051. menuFile->addSeparator ();
  1052. menuFile->add ("Exit", IDC_FILE_EXIT);
  1053. menuFile->setEnabled(IDC_FILE_LOADBACKGROUNDTEX, false);
  1054. menuFile->setEnabled(IDC_FILE_LOADGROUNDTEX, false);
  1055. menuFile->setEnabled(IDC_FILE_UNLOADGROUNDTEX, false);
  1056. menuFile->setEnabled(IDC_FILE_SAVESOUNDSCRIPTCHANGES, false);
  1057. menuOptions->add ("Background Color...", IDC_OPTIONS_COLORBACKGROUND);
  1058. menuOptions->add ("Ground Color...", IDC_OPTIONS_COLORGROUND);
  1059. menuOptions->add ("Light Color...", IDC_OPTIONS_COLORLIGHT);
  1060. {
  1061. menuCloseCaptionLanguages = new mxMenu();
  1062. for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
  1063. {
  1064. int id = IDC_OPTIONS_LANGUAGESTART + i;
  1065. menuCloseCaptionLanguages->add( CSentence::NameForLanguage( i ), id );
  1066. }
  1067. menuOptions->addSeparator();
  1068. menuOptions->addMenu( "CC Language", menuCloseCaptionLanguages );
  1069. }
  1070. menuOptions->addSeparator ();
  1071. menuOptions->add ("Center View", IDC_OPTIONS_CENTERVIEW);
  1072. menuOptions->add ("Center on Face", IDC_OPTIONS_CENTERONFACE );
  1073. #ifdef WIN32
  1074. menuOptions->addSeparator ();
  1075. menuOptions->add ("Make Screenshot...", IDC_OPTIONS_MAKESCREENSHOT);
  1076. //menuOptions->add ("Dump Model Info", IDC_OPTIONS_DUMP);
  1077. menuOptions->addSeparator ();
  1078. menuOptions->add ("Clear model sounds.", IDC_OPTIONS_CLEARMODELSOUNDS );
  1079. #endif
  1080. menuExpressions->add( "New...", IDC_EXPRESSIONS_NEW );
  1081. menuExpressions->addSeparator ();
  1082. menuExpressions->add( "Load...", IDC_EXPRESSIONS_LOAD );
  1083. menuExpressions->add( "Save", IDC_EXPRESSIONS_SAVE );
  1084. menuExpressions->addSeparator ();
  1085. menuExpressions->add( "Export to VFE", IDC_EXPRESSIONS_EXPORT );
  1086. menuExpressions->addSeparator ();
  1087. menuExpressions->add( "Close class", IDC_EXPRESSIONS_CLOSE );
  1088. menuExpressions->add( "Close all classes", IDC_EXPRESSIONS_CLOSEALL );
  1089. menuExpressions->addSeparator();
  1090. menuExpressions->add( "Recreate all bitmaps", IDC_EXPRESSIONS_REDOBITMAPS );
  1091. menuChoreography->add( "New...", IDC_CHOREOSCENE_NEW );
  1092. menuChoreography->addSeparator();
  1093. menuChoreography->add( "Load...", IDC_CHOREOSCENE_LOAD );
  1094. menuChoreography->add( "Save", IDC_CHOREOSCENE_SAVE );
  1095. menuChoreography->add( "Save As...", IDC_CHOREOSCENE_SAVEAS );
  1096. menuChoreography->addSeparator();
  1097. menuChoreography->add( "Close", IDC_CHOREOSCENE_CLOSE );
  1098. menuChoreography->addSeparator();
  1099. menuChoreography->add( "Add Actor...", IDC_CHOREOSCENE_ADDACTOR );
  1100. menuChoreography->addSeparator();
  1101. menuChoreography->add( "Load Next", IDC_CHOREOSCENE_LOADNEXT );
  1102. #ifdef WIN32
  1103. menuHelp->add ("Goto Homepage...", IDC_HELP_GOTOHOMEPAGE);
  1104. menuHelp->addSeparator ();
  1105. #endif
  1106. menuHelp->add ("About...", IDC_HELP_ABOUT);
  1107. // create the Material System window
  1108. Con_Printf( "Creating 3D View\n" );
  1109. g_pMatSysWindow = new MatSysWindow (workspace, 0, 0, 100, 100, "", mxWindow::Normal);
  1110. Con_Printf( "Creating Close Caption tool" );
  1111. g_pCloseCaptionTool = new CloseCaptionTool( workspace );
  1112. Con_Printf( "Creating control panel\n" );
  1113. g_pControlPanel = new ControlPanel (workspace);
  1114. Con_Printf( "Creating phoneme editor\n" );
  1115. g_pPhonemeEditor = new PhonemeEditor( workspace );
  1116. Con_Printf( "Creating expression tool\n" );
  1117. g_pExpressionTool = new ExpressionTool( workspace );
  1118. Con_Printf( "Creating gesture tool\n" );
  1119. g_pGestureTool = new GestureTool( workspace );
  1120. Con_Printf( "Creating ramp tool\n" );
  1121. g_pRampTool = new RampTool( workspace );
  1122. Con_Printf( "Creating scene ramp tool\n" );
  1123. g_pSceneRampTool = new SceneRampTool( workspace );
  1124. Con_Printf( "Creating expression tray\n" );
  1125. g_pExpressionTrayTool = new mxExpressionTray( workspace, IDC_EXPRESSIONTRAY );
  1126. Con_Printf( "Creating animation browser\n" );
  1127. g_pAnimationBrowserTool = new AnimationBrowser( workspace, IDC_ANIMATIONBROWSER );
  1128. Con_Printf( "Creating flex slider window\n" );
  1129. g_pFlexPanel = new FlexPanel( workspace );
  1130. Con_Printf( "Creating wave browser\n" );
  1131. g_pWaveBrowser = new CWaveBrowser( workspace );
  1132. Con_Printf( "Creating VCD browser\n" );
  1133. g_pVCDBrowser = new CVCDBrowser( workspace );
  1134. Con_Printf( "Creating choreography view\n" );
  1135. g_pChoreoView = new CChoreoView( workspace, 200, 200, 400, 300, 0 );
  1136. // Choreo scene file drives main window title name
  1137. g_pChoreoView->SetUseForMainWindowTitle( true );
  1138. #if 0
  1139. new TestWindow( workspace, 100, 100, 256, 256 );
  1140. #endif
  1141. Con_Printf( "IFacePoserToolWindow::Init\n" );
  1142. IFacePoserToolWindow::InitTools();
  1143. Con_Printf( "windowtab->Init\n" );
  1144. windowtab->Init();
  1145. Con_Printf( "loadRecentFiles\n" );
  1146. loadRecentFiles ();
  1147. initRecentFiles ();
  1148. Con_Printf( "RestoreThumbnailSize\n" );
  1149. g_pExpressionTrayTool->RestoreThumbnailSize();
  1150. g_pAnimationBrowserTool->RestoreThumbnailSize();
  1151. Con_Printf( "Add Tool Windows\n" );
  1152. int c = IFacePoserToolWindow::GetToolCount();
  1153. for ( i = 0; i < c ; i++ )
  1154. {
  1155. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
  1156. menuWindow->add( tool->GetToolName(), IDC_WINDOW_FIRSTTOOL + i );
  1157. }
  1158. menuWindow->addSeparator();
  1159. menuWindow->add( "Cascade", IDC_WINDOW_CASCADE );
  1160. menuWindow->addSeparator();
  1161. menuWindow->add( "Tile", IDC_WINDOW_TILE );
  1162. menuWindow->add( "Tile Horizontally", IDC_WINDOW_TILE_HORIZ );
  1163. menuWindow->add( "Tile Vertically", IDC_WINDOW_TILE_VERT );
  1164. menuWindow->addSeparator();
  1165. menuWindow->add( "Hide All", IDC_WINDOW_HIDEALL );
  1166. menuWindow->add( "Show All", IDC_WINDOW_SHOWALL );
  1167. Con_Printf( "UpdateWindowMenu\n" );
  1168. UpdateWindowMenu();
  1169. // Check the default item
  1170. UpdateLanguageMenu( g_viewerSettings.cclanguageid );
  1171. m_nCurrentFrame = 0;
  1172. Con_Printf( "gridsettings->Init()\n" );
  1173. gridsettings->Init();
  1174. Con_Printf( "LoadWindowPositions\n" );
  1175. LoadWindowPositions();
  1176. Con_Printf( "Model viewer created\n" );
  1177. }
  1178. //-----------------------------------------------------------------------------
  1179. // Purpose:
  1180. //-----------------------------------------------------------------------------
  1181. void MDLViewer::UpdateWindowMenu( void )
  1182. {
  1183. int c = IFacePoserToolWindow::GetToolCount();
  1184. for ( int i = 0; i < c ; i++ )
  1185. {
  1186. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
  1187. menuWindow->setChecked( IDC_WINDOW_FIRSTTOOL + i, tool->GetMxWindow()->isVisible() );
  1188. }
  1189. }
  1190. //-----------------------------------------------------------------------------
  1191. // Purpose:
  1192. // Input : currentLanguageId -
  1193. //-----------------------------------------------------------------------------
  1194. void MDLViewer::UpdateLanguageMenu( int currentLanguageId )
  1195. {
  1196. if ( !menuCloseCaptionLanguages )
  1197. return;
  1198. for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
  1199. {
  1200. int id = IDC_OPTIONS_LANGUAGESTART + i;
  1201. menuCloseCaptionLanguages->setChecked( id, i == currentLanguageId ? true : false );
  1202. }
  1203. }
  1204. void MDLViewer::OnDelete()
  1205. {
  1206. saveRecentFiles ();
  1207. SaveViewerRootSettings( );
  1208. #ifdef WIN32
  1209. DeleteFile ("hlmv.cfg");
  1210. DeleteFile ("midump.txt");
  1211. #endif
  1212. IFacePoserToolWindow::ShutdownTools();
  1213. g_MDLViewer = NULL;
  1214. }
  1215. MDLViewer::~MDLViewer ()
  1216. {
  1217. }
  1218. //-----------------------------------------------------------------------------
  1219. // Purpose:
  1220. //-----------------------------------------------------------------------------
  1221. void MDLViewer::InitModelTab( void )
  1222. {
  1223. modeltab->Init();
  1224. }
  1225. //-----------------------------------------------------------------------------
  1226. // Purpose:
  1227. //-----------------------------------------------------------------------------
  1228. void MDLViewer::InitGridSettings( void )
  1229. {
  1230. gridsettings->Init();
  1231. }
  1232. //-----------------------------------------------------------------------------
  1233. // Purpose:
  1234. // Output : int
  1235. //-----------------------------------------------------------------------------
  1236. int MDLViewer::GetActiveModelTab( void )
  1237. {
  1238. return modeltab->getSelectedIndex();
  1239. }
  1240. //-----------------------------------------------------------------------------
  1241. // Purpose:
  1242. // Input : modelindex -
  1243. //-----------------------------------------------------------------------------
  1244. void MDLViewer::SetActiveModelTab( int modelindex )
  1245. {
  1246. modeltab->select( modelindex );
  1247. modeltab->HandleModelSelect();
  1248. }
  1249. //-----------------------------------------------------------------------------
  1250. // Purpose: Reloads the currently loaded model file.
  1251. //-----------------------------------------------------------------------------
  1252. void MDLViewer::Refresh( void )
  1253. {
  1254. Con_ColorPrintf( RGB( 0, 125, 255 ), "Refreshing...\n" );
  1255. bool reinit_soundemitter = true;
  1256. // Save any changed sound script files
  1257. int c = soundemitter->GetNumSoundScripts();
  1258. for ( int i = 0; i < c; i++ )
  1259. {
  1260. if ( !soundemitter->IsSoundScriptDirty( i ) )
  1261. continue;
  1262. char const *scriptname = soundemitter->GetSoundScriptName( i );
  1263. if ( !scriptname )
  1264. continue;
  1265. if ( !filesystem->FileExists( scriptname ) ||
  1266. !filesystem->IsFileWritable( scriptname ) )
  1267. {
  1268. continue;
  1269. }
  1270. int retval = mxMessageBox( NULL, va( "Save changes to sound script '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
  1271. if ( retval != 0 )
  1272. {
  1273. reinit_soundemitter = false;
  1274. continue;
  1275. }
  1276. if ( retval == 0 )
  1277. {
  1278. soundemitter->SaveChangesToSoundScript( i );
  1279. Con_ColorPrintf( RGB( 50, 255, 100 ), " saving changes to script file '%s'\n", scriptname );
  1280. }
  1281. }
  1282. // kill the soundemitter system
  1283. if ( reinit_soundemitter )
  1284. {
  1285. soundemitter->Shutdown();
  1286. }
  1287. Con_ColorPrintf( RGB( 50, 255, 100 ), " reloading textures\n" );
  1288. g_pMaterialSystem->ReloadTextures();
  1289. models->ReleaseModels();
  1290. Con_ColorPrintf( RGB( 50, 255, 100 ), " reloading models\n" );
  1291. models->RestoreModels();
  1292. // restart the soundemitter system
  1293. if ( reinit_soundemitter )
  1294. {
  1295. Con_ColorPrintf( RGB( 50, 255, 100 ), " reloading sound emitter system\n" );
  1296. soundemitter->Init();
  1297. }
  1298. else
  1299. {
  1300. Con_ColorPrintf( RGB( 250, 50, 50 ), " NOT reloading sound emitter system\n" );
  1301. }
  1302. Con_ColorPrintf( RGB( 0, 125, 255 ), "done.\n" );
  1303. }
  1304. void MDLViewer::OnFileLoaded( char const *pszFile )
  1305. {
  1306. int i;
  1307. for (i = 0; i < 8; i++)
  1308. {
  1309. if (!Q_stricmp( recentFiles[i], pszFile ))
  1310. break;
  1311. }
  1312. // swap existing recent file
  1313. if (i < 8)
  1314. {
  1315. char tmp[256];
  1316. strcpy (tmp, recentFiles[0]);
  1317. strcpy (recentFiles[0], recentFiles[i]);
  1318. strcpy (recentFiles[i], tmp);
  1319. }
  1320. // insert recent file
  1321. else
  1322. {
  1323. for (i = 7; i > 0; i--)
  1324. strcpy (recentFiles[i], recentFiles[i - 1]);
  1325. strcpy( recentFiles[0], pszFile );
  1326. }
  1327. initRecentFiles ();
  1328. if ( g_pVCDBrowser )
  1329. {
  1330. g_pVCDBrowser->SetCurrent( pszFile );
  1331. }
  1332. }
  1333. //-----------------------------------------------------------------------------
  1334. // Purpose: Loads the file and updates the MRU list.
  1335. // Input : pszFile - File to load.
  1336. //-----------------------------------------------------------------------------
  1337. void MDLViewer::LoadModelFile( const char *pszFile )
  1338. {
  1339. models->LoadModel( pszFile );
  1340. OnFileLoaded( pszFile );
  1341. g_pControlPanel->CenterOnFace();
  1342. }
  1343. //-----------------------------------------------------------------------------
  1344. // Purpose:
  1345. // Input : *wnd -
  1346. // x -
  1347. // y -
  1348. // Output : static bool
  1349. //-----------------------------------------------------------------------------
  1350. static bool WindowContainsPoint( mxWindow *wnd, int x, int y )
  1351. {
  1352. POINT pt;
  1353. pt.x = (short)x;
  1354. pt.y = (short)y;
  1355. HWND window = (HWND)wnd->getHandle();
  1356. if ( !window )
  1357. return false;
  1358. ScreenToClient( window, &pt );
  1359. if ( pt.x < 0 )
  1360. return false;
  1361. if ( pt.y < 0 )
  1362. return false;
  1363. if ( pt.x > wnd->w() )
  1364. return false;
  1365. if ( pt.y > wnd->h() )
  1366. return false;
  1367. return true;
  1368. }
  1369. void MDLViewer::LoadModel_Steam()
  1370. {
  1371. if ( !g_FSDialogFactory )
  1372. return;
  1373. IFileSystemOpenDialog *pDlg;
  1374. pDlg = (IFileSystemOpenDialog*)g_FSDialogFactory( FILESYSTEMOPENDIALOG_VERSION, NULL );
  1375. if ( !pDlg )
  1376. {
  1377. char str[512];
  1378. Q_snprintf( str, sizeof( str ), "Can't create %s interface.", FILESYSTEMOPENDIALOG_VERSION );
  1379. ::MessageBox( NULL, str, "Error", MB_OK );
  1380. return;
  1381. }
  1382. pDlg->Init( g_Factory, NULL );
  1383. pDlg->AddFileMask( "*.jpg" );
  1384. pDlg->AddFileMask( "*.mdl" );
  1385. pDlg->SetInitialDir( "models", "game" );
  1386. pDlg->SetFilterMdlAndJpgFiles( true );
  1387. if (pDlg->DoModal() == IDOK)
  1388. {
  1389. char filename[MAX_PATH];
  1390. pDlg->GetFilename( filename, sizeof( filename ) );
  1391. LoadModelFile( filename );
  1392. }
  1393. pDlg->Release();
  1394. }
  1395. int MDLViewer::handleEvent (mxEvent *event)
  1396. {
  1397. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  1398. int iret = 0;
  1399. switch (event->event)
  1400. {
  1401. case mxEvent::Size:
  1402. {
  1403. int width = w2();
  1404. int height = h2();
  1405. windowtab->SetRowHeight( WINDOW_TAB_OFFSET - 2 );
  1406. modeltab->SetRowHeight( WINDOW_TAB_OFFSET - 2 );
  1407. int gridsettingswide = 100;
  1408. int gridstart = width - gridsettingswide - 5;
  1409. int modelwide = gridstart / 3;
  1410. int windowwide = gridstart - modelwide;
  1411. int rowheight = max( windowtab->GetBestHeight( windowwide ), modeltab->GetBestHeight( modelwide ) );
  1412. workspace->setBounds( 0, 0, width, height - rowheight );
  1413. gridsettings->setBounds( gridstart, height - rowheight + 1, gridsettingswide, WINDOW_TAB_OFFSET - 2 );
  1414. windowtab->setBounds( 0, height - rowheight, windowwide, rowheight );
  1415. modeltab->setBounds( windowwide, height - rowheight, modelwide, rowheight );
  1416. iret = 1;
  1417. }
  1418. break;
  1419. case mxEvent::Action:
  1420. {
  1421. iret = 1;
  1422. switch (event->action)
  1423. {
  1424. case IDC_WINDOW_TAB:
  1425. {
  1426. windowtab->HandleWindowSelect();
  1427. }
  1428. break;
  1429. case IDC_MODEL_TAB:
  1430. {
  1431. modeltab->HandleModelSelect();
  1432. }
  1433. break;
  1434. case IDC_FILE_LOADMODEL:
  1435. {
  1436. if ( ! CommandLine()->FindParm( "-NoSteamDialog" ) )
  1437. {
  1438. g_MDLViewer->LoadModel_Steam();
  1439. }
  1440. else
  1441. {
  1442. char modelfile[ 512 ];
  1443. if ( FacePoser_ShowOpenFileNameDialog( modelfile, sizeof( modelfile ), "models", "*.mdl" ) )
  1444. {
  1445. LoadModelFile( modelfile );
  1446. }
  1447. }
  1448. }
  1449. break;
  1450. case IDC_FILE_REFRESH:
  1451. {
  1452. Refresh();
  1453. break;
  1454. }
  1455. case IDC_FILE_SAVESOUNDSCRIPTCHANGES:
  1456. {
  1457. OnSaveSoundScriptChanges();
  1458. }
  1459. break;
  1460. case IDC_FILE_REBUILDSCENESIMAGE:
  1461. {
  1462. OnRebuildScenesImage();
  1463. }
  1464. break;
  1465. case IDC_FILE_LOADBACKGROUNDTEX:
  1466. case IDC_FILE_LOADGROUNDTEX:
  1467. {
  1468. const char *ptr = mxGetOpenFileName (this, 0, "*.*");
  1469. if (ptr)
  1470. {
  1471. if (0 /* g_pMatSysWindow->loadTexture (ptr, event->action - IDC_FILE_LOADBACKGROUNDTEX) */)
  1472. {
  1473. if (event->action == IDC_FILE_LOADBACKGROUNDTEX)
  1474. g_pControlPanel->setShowBackground (true);
  1475. else
  1476. g_pControlPanel->setShowGround (true);
  1477. }
  1478. else
  1479. mxMessageBox (this, "Error loading texture.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
  1480. }
  1481. }
  1482. break;
  1483. case IDC_FILE_UNLOADGROUNDTEX:
  1484. {
  1485. // g_pMatSysWindow->loadTexture (0, 1);
  1486. g_pControlPanel->setShowGround (false);
  1487. }
  1488. break;
  1489. case IDC_FILE_RECENTFILES1:
  1490. case IDC_FILE_RECENTFILES2:
  1491. case IDC_FILE_RECENTFILES3:
  1492. case IDC_FILE_RECENTFILES4:
  1493. case IDC_FILE_RECENTFILES5:
  1494. case IDC_FILE_RECENTFILES6:
  1495. case IDC_FILE_RECENTFILES7:
  1496. case IDC_FILE_RECENTFILES8:
  1497. {
  1498. int i = event->action - IDC_FILE_RECENTFILES1;
  1499. if ( recentFiles[ i ] && recentFiles[ i ][ 0 ] )
  1500. {
  1501. char ext[ 4 ];
  1502. Q_ExtractFileExtension( recentFiles[ i ], ext, sizeof( ext ) );
  1503. bool valid = false;
  1504. if ( !Q_stricmp( ext, "mdl" ) )
  1505. {
  1506. // Check extension
  1507. LoadModelFile( recentFiles[ i ] );
  1508. valid = true;
  1509. }
  1510. else if ( !Q_stricmp( ext, "vcd" ) )
  1511. {
  1512. g_pChoreoView->LoadSceneFromFile( recentFiles[ i ] );
  1513. valid = true;
  1514. }
  1515. if ( valid )
  1516. {
  1517. char tmp[256];
  1518. strcpy (tmp, recentFiles[0]);
  1519. strcpy (recentFiles[0], recentFiles[i]);
  1520. strcpy (recentFiles[i], tmp);
  1521. initRecentFiles ();
  1522. }
  1523. }
  1524. redraw ();
  1525. }
  1526. break;
  1527. case IDC_FILE_EXIT:
  1528. {
  1529. redraw ();
  1530. mx::quit ();
  1531. }
  1532. break;
  1533. case IDC_OPTIONS_COLORBACKGROUND:
  1534. case IDC_OPTIONS_COLORGROUND:
  1535. case IDC_OPTIONS_COLORLIGHT:
  1536. {
  1537. float *cols[3] = { g_viewerSettings.bgColor, g_viewerSettings.gColor, g_viewerSettings.lColor };
  1538. float *col = cols[event->action - IDC_OPTIONS_COLORBACKGROUND];
  1539. int r = (int) (col[0] * 255.0f);
  1540. int g = (int) (col[1] * 255.0f);
  1541. int b = (int) (col[2] * 255.0f);
  1542. if (mxChooseColor (this, &r, &g, &b))
  1543. {
  1544. col[0] = (float) r / 255.0f;
  1545. col[1] = (float) g / 255.0f;
  1546. col[2] = (float) b / 255.0f;
  1547. }
  1548. }
  1549. break;
  1550. case IDC_OPTIONS_CENTERVIEW:
  1551. g_pControlPanel->centerView ();
  1552. break;
  1553. case IDC_OPTIONS_CENTERONFACE:
  1554. g_pControlPanel->CenterOnFace();
  1555. break;
  1556. case IDC_OPTIONS_CLEARMODELSOUNDS:
  1557. {
  1558. sound->StopAll();
  1559. Con_ColorPrintf( RGB( 0, 100, 255 ), "Resetting model sound channels\n" );
  1560. }
  1561. break;
  1562. case IDC_OPTIONS_MAKESCREENSHOT:
  1563. {
  1564. char *ptr = (char *) mxGetSaveFileName (this, "", "*.tga");
  1565. if (ptr)
  1566. {
  1567. char fn[ 512 ];
  1568. Q_strncpy( fn, ptr, sizeof( fn ) );
  1569. Q_SetExtension( fn, ".tga", sizeof( fn ) );
  1570. g_pMatSysWindow->TakeScreenShot( fn );
  1571. }
  1572. }
  1573. break;
  1574. case IDC_OPTIONS_DUMP:
  1575. g_pControlPanel->dumpModelInfo ();
  1576. break;
  1577. #ifdef WIN32
  1578. case IDC_HELP_GOTOHOMEPAGE:
  1579. ShellExecute (0, "open", "http://developer.valvesoftware.com/wiki/Category:Choreography", 0, 0, SW_SHOW);
  1580. break;
  1581. #endif
  1582. case IDC_HELP_ABOUT:
  1583. mxMessageBox (this,
  1584. "v1.0 Copyright � 1996-2007, Valve Corporation. All rights reserved.\r\nBuild Date: " __DATE__ "",
  1585. "Valve Face Poser",
  1586. MX_MB_OK | MX_MB_INFORMATION);
  1587. break;
  1588. case IDC_EXPRESSIONS_REDOBITMAPS:
  1589. {
  1590. CExpClass *active = expressions->GetActiveClass();
  1591. if ( active )
  1592. {
  1593. g_pProgressDialog->Start( "Rebuild Bitmaps", "", true );
  1594. g_pMatSysWindow->EnableStickySnapshotMode( );
  1595. for ( int i = 0; i < active->GetNumExpressions() ; i++ )
  1596. {
  1597. CExpression *exp = active->GetExpression( i );
  1598. if ( !exp )
  1599. continue;
  1600. g_pProgressDialog->UpdateText( exp->name );
  1601. g_pProgressDialog->Update( (float)i / (float)active->GetNumExpressions() );
  1602. if ( g_pProgressDialog->IsCancelled() )
  1603. {
  1604. Msg( "Cancelled\n" );
  1605. break;
  1606. }
  1607. exp->CreateNewBitmap( models->GetActiveModelIndex() );
  1608. if ( ! ( i % 5 ) )
  1609. {
  1610. g_pExpressionTrayTool->redraw();
  1611. }
  1612. }
  1613. g_pMatSysWindow->DisableStickySnapshotMode( );
  1614. g_pProgressDialog->Finish();
  1615. active->SelectExpression( 0 );
  1616. }
  1617. }
  1618. break;
  1619. case IDC_EXPRESSIONS_NEW:
  1620. {
  1621. char classfile[ 512 ];
  1622. if ( FacePoser_ShowSaveFileNameDialog( classfile, sizeof( classfile ), "expressions", "*.txt" ) )
  1623. {
  1624. Q_DefaultExtension( classfile, ".txt", sizeof( classfile ) );
  1625. expressions->CreateNewClass( classfile );
  1626. }
  1627. }
  1628. break;
  1629. case IDC_EXPRESSIONS_LOAD:
  1630. {
  1631. char classfile[ 512 ];
  1632. if ( FacePoser_ShowOpenFileNameDialog( classfile, sizeof( classfile ), "expressions", "*.txt" ) )
  1633. {
  1634. expressions->LoadClass( classfile );
  1635. }
  1636. }
  1637. break;
  1638. case IDC_EXPRESSIONS_SAVE:
  1639. {
  1640. CExpClass *active = expressions->GetActiveClass();
  1641. if ( active )
  1642. {
  1643. active->Save();
  1644. active->Export();
  1645. }
  1646. }
  1647. break;
  1648. case IDC_EXPRESSIONS_EXPORT:
  1649. {
  1650. CExpClass *active = expressions->GetActiveClass();
  1651. if ( active )
  1652. {
  1653. active->Export();
  1654. }
  1655. }
  1656. break;
  1657. case IDC_EXPRESSIONS_CLOSE:
  1658. g_pControlPanel->Close();
  1659. break;
  1660. case IDC_EXPRESSIONS_CLOSEALL:
  1661. g_pControlPanel->Closeall();
  1662. break;
  1663. case IDC_CHOREOSCENE_NEW:
  1664. g_pChoreoView->New();
  1665. break;
  1666. case IDC_CHOREOSCENE_LOAD:
  1667. g_pChoreoView->Load();
  1668. break;
  1669. case IDC_CHOREOSCENE_LOADNEXT:
  1670. g_pChoreoView->LoadNext();
  1671. break;
  1672. case IDC_CHOREOSCENE_SAVE:
  1673. g_pChoreoView->Save();
  1674. break;
  1675. case IDC_CHOREOSCENE_SAVEAS:
  1676. g_pChoreoView->SaveAs();
  1677. break;
  1678. case IDC_CHOREOSCENE_CLOSE:
  1679. g_pChoreoView->Close();
  1680. break;
  1681. case IDC_CHOREOSCENE_ADDACTOR:
  1682. g_pChoreoView->NewActor();
  1683. break;
  1684. case IDC_WINDOW_TILE:
  1685. {
  1686. OnTile();
  1687. }
  1688. break;
  1689. case IDC_WINDOW_TILE_HORIZ:
  1690. {
  1691. OnTileHorizontally();
  1692. }
  1693. break;
  1694. case IDC_WINDOW_TILE_VERT:
  1695. {
  1696. OnTileVertically();
  1697. }
  1698. break;
  1699. case IDC_WINDOW_CASCADE:
  1700. {
  1701. OnCascade();
  1702. }
  1703. break;
  1704. case IDC_WINDOW_HIDEALL:
  1705. {
  1706. OnHideAll();
  1707. }
  1708. break;
  1709. case IDC_WINDOW_SHOWALL:
  1710. {
  1711. OnShowAll();
  1712. }
  1713. break;
  1714. default:
  1715. {
  1716. iret = 0;
  1717. int tool_number = event->action - IDC_WINDOW_FIRSTTOOL;
  1718. int max_tools = IDC_WINDOW_LASTTOOL - IDC_WINDOW_FIRSTTOOL;
  1719. if ( tool_number >= 0 &&
  1720. tool_number <= max_tools &&
  1721. tool_number < IFacePoserToolWindow::GetToolCount() )
  1722. {
  1723. iret = 1;
  1724. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( tool_number );
  1725. if ( tool )
  1726. {
  1727. mxWindow *toolw = tool->GetMxWindow();
  1728. bool wasvisible = toolw->isVisible();
  1729. toolw->setVisible( !wasvisible );
  1730. g_MDLViewer->UpdateWindowMenu();
  1731. }
  1732. }
  1733. int lang_number = event->action - IDC_OPTIONS_LANGUAGESTART;
  1734. if ( lang_number >= 0 &&
  1735. lang_number < CC_NUM_LANGUAGES )
  1736. {
  1737. iret = 1;
  1738. SetCloseCaptionLanguageId( lang_number );
  1739. }
  1740. }
  1741. break;
  1742. } //switch (event->action)
  1743. } // mxEvent::Action
  1744. break;
  1745. case KeyDown:
  1746. {
  1747. //g_pMatSysWindow->handleEvent(event);
  1748. // Send it to the active tool
  1749. IFacePoserToolWindow *active = IFacePoserToolWindow::GetActiveTool();
  1750. if ( active )
  1751. {
  1752. mxWindow *w = active->GetMxWindow();
  1753. if ( w )
  1754. {
  1755. w->handleEvent( event );
  1756. }
  1757. }
  1758. else
  1759. {
  1760. g_pMatSysWindow->handleEvent(event);
  1761. }
  1762. iret = 1;
  1763. }
  1764. break;
  1765. case mxEvent::Activate:
  1766. {
  1767. if (event->action)
  1768. {
  1769. mx::setIdleWindow( g_pMatSysWindow );
  1770. // Force reload of localization data
  1771. SetCloseCaptionLanguageId( GetCloseCaptionLanguageId(), true );
  1772. }
  1773. else
  1774. {
  1775. mx::setIdleWindow( 0 );
  1776. }
  1777. iret = 1;
  1778. }
  1779. break;
  1780. } // event->event
  1781. return iret;
  1782. }
  1783. void MDLViewer::SaveWindowPositions( void )
  1784. {
  1785. // Save the model viewer position
  1786. SavePosition();
  1787. int c = IFacePoserToolWindow::GetToolCount();
  1788. for ( int i = 0; i < c; i++ )
  1789. {
  1790. IFacePoserToolWindow *w = IFacePoserToolWindow::GetTool( i );
  1791. w->SavePosition();
  1792. }
  1793. }
  1794. void MDLViewer::LoadWindowPositions( void )
  1795. {
  1796. // NOTE: Don't do this here, we do the mdlviewer position earlier in startup
  1797. // LoadPosition();
  1798. int w = this->w();
  1799. int h = this->h();
  1800. g_viewerSettings.width = w;
  1801. g_viewerSettings.height = h;
  1802. int c = IFacePoserToolWindow::GetToolCount();
  1803. for ( int i = 0; i < c; i++ )
  1804. {
  1805. IFacePoserToolWindow *w = IFacePoserToolWindow::GetTool( i );
  1806. w->LoadPosition();
  1807. }
  1808. }
  1809. void
  1810. MDLViewer::redraw ()
  1811. {
  1812. }
  1813. int MDLViewer::GetCurrentFrame( void )
  1814. {
  1815. return m_nCurrentFrame;
  1816. }
  1817. void MDLViewer::Think( float dt )
  1818. {
  1819. ++m_nCurrentFrame;
  1820. // Iterate across tools
  1821. IFacePoserToolWindow::ToolThink( dt );
  1822. sound->Update( dt );
  1823. bool soundscriptsdirty = AreSoundScriptsDirty();
  1824. if ( soundscriptsdirty != m_bOldSoundScriptsDirty )
  1825. {
  1826. // Update the menu item when this changes
  1827. menuFile->setEnabled(IDC_FILE_SAVESOUNDSCRIPTCHANGES, soundscriptsdirty );
  1828. }
  1829. m_bOldSoundScriptsDirty = soundscriptsdirty;
  1830. }
  1831. static int CountVisibleTools( void )
  1832. {
  1833. int i;
  1834. int c = IFacePoserToolWindow::GetToolCount();
  1835. int viscount = 0;
  1836. for ( i = 0; i < c; i++ )
  1837. {
  1838. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
  1839. mxWindow *w = tool->GetMxWindow();
  1840. if ( !w->isVisible() )
  1841. continue;
  1842. viscount++;
  1843. }
  1844. return viscount;
  1845. }
  1846. void MDLViewer::OnCascade()
  1847. {
  1848. int i;
  1849. int c = IFacePoserToolWindow::GetToolCount();
  1850. int viscount = CountVisibleTools();
  1851. int x = 0, y = 0;
  1852. int offset = 20;
  1853. int wide = workspace->w2() - viscount * offset;
  1854. int tall = ( workspace->h2() - viscount * offset ) / 2;
  1855. for ( i = 0; i < c; i++ )
  1856. {
  1857. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
  1858. mxWindow *w = tool->GetMxWindow();
  1859. if ( !w->isVisible() )
  1860. continue;
  1861. w->setBounds( x, y, wide, tall );
  1862. x += offset;
  1863. y += offset;
  1864. }
  1865. }
  1866. void MDLViewer::OnTile()
  1867. {
  1868. int c = CountVisibleTools();
  1869. int rows = (int)sqrt( ( float )c );
  1870. rows = clamp( rows, 1, rows );
  1871. int cols = 1;
  1872. while ( rows * cols < c )
  1873. {
  1874. cols++;
  1875. }
  1876. DoTile( rows, cols );
  1877. }
  1878. void MDLViewer::OnTileHorizontally()
  1879. {
  1880. int c = CountVisibleTools();
  1881. DoTile( c, 1 );
  1882. }
  1883. void MDLViewer::OnTileVertically()
  1884. {
  1885. int c = CountVisibleTools();
  1886. DoTile( 1, c );
  1887. }
  1888. void MDLViewer::OnHideAll()
  1889. {
  1890. int c = IFacePoserToolWindow::GetToolCount();
  1891. for ( int i = 0; i < c; i++ )
  1892. {
  1893. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
  1894. mxWindow *w = tool->GetMxWindow();
  1895. w->setVisible( false );
  1896. }
  1897. UpdateWindowMenu();
  1898. }
  1899. void MDLViewer::OnShowAll()
  1900. {
  1901. int c = IFacePoserToolWindow::GetToolCount();
  1902. for ( int i = 0; i < c; i++ )
  1903. {
  1904. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
  1905. mxWindow *w = tool->GetMxWindow();
  1906. w->setVisible( true );
  1907. }
  1908. UpdateWindowMenu();
  1909. }
  1910. void MDLViewer::DoTile( int x, int y )
  1911. {
  1912. int c = IFacePoserToolWindow::GetToolCount();
  1913. if ( x < 1 )
  1914. x = 1;
  1915. if ( y < 1 )
  1916. y = 1;
  1917. int wide = workspace->w2() / y;
  1918. int tall = workspace->h2() / x;
  1919. int obj = 0;
  1920. for ( int row = 0 ; row < x ; row++ )
  1921. {
  1922. for ( int col = 0; col < y; col++ )
  1923. {
  1924. bool found = false;
  1925. while ( 1 )
  1926. {
  1927. if ( obj >= c )
  1928. break;
  1929. IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( obj++ );
  1930. mxWindow *w = tool->GetMxWindow();
  1931. if ( w->isVisible() )
  1932. {
  1933. w->setBounds( col * wide, row * tall, wide, tall );
  1934. found = true;
  1935. break;
  1936. }
  1937. }
  1938. if ( !found )
  1939. break;
  1940. }
  1941. }
  1942. }
  1943. //-----------------------------------------------------------------------------
  1944. // Purpose: Not used by faceposer
  1945. // Output : int
  1946. //-----------------------------------------------------------------------------
  1947. int MDLViewer::GetCurrentHitboxSet(void)
  1948. {
  1949. return 0;
  1950. }
  1951. //-----------------------------------------------------------------------------
  1952. // Purpose:
  1953. // Output : Returns true on success, false on failure.
  1954. //-----------------------------------------------------------------------------
  1955. bool MDLViewer::PaintBackground( void )
  1956. {
  1957. CChoreoWidgetDrawHelper drawHelper( this );
  1958. RECT rc;
  1959. drawHelper.GetClientRect( rc );
  1960. drawHelper.DrawFilledRect( COLOR_CHOREO_BACKGROUND, rc );
  1961. return false;
  1962. }
  1963. void MDLViewer::OnRebuildScenesImage()
  1964. {
  1965. g_pProgressDialog->Start( "Rebuilding scenes.image", "", false );
  1966. CUtlBuffer targetBuffer;
  1967. bool bLittleEndian = true;
  1968. const char *pFilename = bLittleEndian ? "scenes/scenes.image" : "scenes/scenes.360.image";
  1969. CP4AutoEditAddFile checkout( CFmtStr( "%s%s", gamedir, pFilename ) );
  1970. bool bSuccess = g_pSceneImage->CreateSceneImageFile( targetBuffer, gamedir, bLittleEndian, false, this );
  1971. if ( bSuccess )
  1972. {
  1973. scriptlib->WriteBufferToFile( pFilename, targetBuffer, WRITE_TO_DISK_ALWAYS );
  1974. }
  1975. g_pProgressDialog->Finish();
  1976. m_bVCDSaved = false;
  1977. }
  1978. void MDLViewer::UpdateStatus( char const *pchSceneName, bool bQuiet, int nIndex, int nCount )
  1979. {
  1980. g_pProgressDialog->UpdateText( pchSceneName );
  1981. g_pProgressDialog->Update( (float)nIndex / (float)nCount );
  1982. }
  1983. void MDLViewer::OnVCDSaved()
  1984. {
  1985. m_bVCDSaved = true;
  1986. }
  1987. SpewRetval_t HLFacePoserSpewFunc( SpewType_t spewType, char const *pMsg )
  1988. {
  1989. g_bInError = true;
  1990. switch (spewType)
  1991. {
  1992. case SPEW_ERROR:
  1993. ::MessageBox(NULL, pMsg, "FATAL ERROR", MB_OK);
  1994. g_bInError = false;
  1995. return SPEW_ABORT;
  1996. case SPEW_LOG:
  1997. g_bInError = false;
  1998. return SPEW_CONTINUE;
  1999. case SPEW_WARNING:
  2000. Con_ErrorPrintf( pMsg );
  2001. g_bInError = false;
  2002. return SPEW_CONTINUE;
  2003. default:
  2004. Con_Printf(pMsg);
  2005. g_bInError = false;
  2006. #ifdef _DEBUG
  2007. return spewType == SPEW_ASSERT ? SPEW_DEBUGGER : SPEW_CONTINUE;
  2008. #else
  2009. return SPEW_CONTINUE;
  2010. #endif
  2011. }
  2012. }
  2013. void MDLViewer::OnSaveSoundScriptChanges()
  2014. {
  2015. if ( !AreSoundScriptsDirty() )
  2016. {
  2017. return;
  2018. }
  2019. // Save any changed sound script files
  2020. int c = soundemitter->GetNumSoundScripts();
  2021. for ( int i = 0; i < c; i++ )
  2022. {
  2023. if ( !soundemitter->IsSoundScriptDirty( i ) )
  2024. continue;
  2025. char const *scriptname = soundemitter->GetSoundScriptName( i );
  2026. if ( !scriptname )
  2027. continue;
  2028. if ( !filesystem->FileExists( scriptname ) )
  2029. {
  2030. continue;
  2031. }
  2032. if ( !filesystem->IsFileWritable( scriptname ) )
  2033. {
  2034. mxMessageBox( NULL, va( "Can't save changes to sound script '%s', file is READ-ONLY?", scriptname ), g_appTitle, MX_MB_OK );
  2035. continue;
  2036. }
  2037. int retval = mxMessageBox( NULL, va( "Save changes to sound script '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
  2038. if ( retval == 2 )
  2039. {
  2040. return;
  2041. }
  2042. if ( retval == 0 )
  2043. {
  2044. soundemitter->SaveChangesToSoundScript( i );
  2045. }
  2046. }
  2047. }
  2048. //-----------------------------------------------------------------------------
  2049. // The application object
  2050. //-----------------------------------------------------------------------------
  2051. class CHLFacePoserApp : public CTier3SteamApp
  2052. {
  2053. typedef CTier3SteamApp BaseClass;
  2054. public:
  2055. // Methods of IApplication
  2056. virtual bool Create();
  2057. virtual bool PreInit();
  2058. virtual int Main();
  2059. virtual void PostShutdown();
  2060. virtual void Destroy();
  2061. private:
  2062. // Sets up the search paths
  2063. bool SetupSearchPaths();
  2064. };
  2065. //-----------------------------------------------------------------------------
  2066. // Create all singleton systems
  2067. //-----------------------------------------------------------------------------
  2068. bool CHLFacePoserApp::Create()
  2069. {
  2070. // Save some memory so engine/hammer isn't so painful
  2071. CommandLine()->AppendParm( "-disallowhwmorph", NULL );
  2072. SpewOutputFunc( HLFacePoserSpewFunc );
  2073. AppSystemInfo_t appSystems[] =
  2074. {
  2075. { "inputsystem.dll", INPUTSYSTEM_INTERFACE_VERSION },
  2076. { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION },
  2077. { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION },
  2078. { "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
  2079. { "datacache.dll", DATACACHE_INTERFACE_VERSION },
  2080. { "datacache.dll", MDLCACHE_INTERFACE_VERSION },
  2081. { "datacache.dll", STUDIO_DATA_CACHE_INTERFACE_VERSION },
  2082. { "vguimatsurface.dll", VGUI_SURFACE_INTERFACE_VERSION },
  2083. { "vgui2.dll", VGUI_IVGUI_INTERFACE_VERSION },
  2084. { "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
  2085. { "", "" } // Required to terminate the list
  2086. };
  2087. if ( !AddSystems( appSystems ) )
  2088. return false;
  2089. // Add the P4 module separately so that if it is absent (say in the SDK) then the other system will initialize properly
  2090. AppModule_t p4Module = LoadModule( "p4lib.dll" );
  2091. if ( p4Module != APP_MODULE_INVALID )
  2092. {
  2093. AddSystem( p4Module, P4_INTERFACE_VERSION );
  2094. }
  2095. g_Factory = GetFactory();
  2096. IMaterialSystem* pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
  2097. if ( !pMaterialSystem )
  2098. {
  2099. Warning( "Material System interface could not be found!\n" );
  2100. return false;
  2101. }
  2102. const char *pShaderDLL = CommandLine()->ParmValue("-shaderdll");
  2103. if(!pShaderDLL)
  2104. {
  2105. pShaderDLL = "shaderapidx9.dll";
  2106. }
  2107. pMaterialSystem->SetShaderAPI( pShaderDLL );
  2108. return true;
  2109. }
  2110. void CHLFacePoserApp::Destroy()
  2111. {
  2112. }
  2113. const char *GetGameDirectory()
  2114. {
  2115. // TODO: get rid of this and ONLY use the filesystem, so hlfaceposer works nicely for
  2116. // mods that get the base game resources from the Steam filesystem.
  2117. return gamedir;
  2118. }
  2119. char const *GetGameDirectorySimple()
  2120. {
  2121. return gamedirsimple;
  2122. }
  2123. //-----------------------------------------------------------------------------
  2124. // Sets up the game path
  2125. //-----------------------------------------------------------------------------
  2126. bool CHLFacePoserApp::SetupSearchPaths()
  2127. {
  2128. // Add paths...
  2129. if ( !BaseClass::SetupSearchPaths( NULL, false, true ) )
  2130. return false;
  2131. // Set gamedir.
  2132. Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), GetGameInfoPath() );
  2133. Q_FileBase( gamedir, gamedirsimple, sizeof( gamedirsimple ) );
  2134. Q_AppendSlash( gamedir, sizeof( gamedir ) );
  2135. workspacefiles->Init( GetGameDirectorySimple() );
  2136. return true;
  2137. }
  2138. //-----------------------------------------------------------------------------
  2139. // Init, shutdown
  2140. //-----------------------------------------------------------------------------
  2141. bool CHLFacePoserApp::PreInit( )
  2142. {
  2143. if ( !BaseClass::PreInit() )
  2144. return false;
  2145. g_pFileSystem = filesystem = g_pFullFileSystem;
  2146. g_pStudioDataCache = (IStudioDataCache*)FindSystem( STUDIO_DATA_CACHE_INTERFACE_VERSION );
  2147. physcollision = (IPhysicsCollision *)FindSystem( VPHYSICS_COLLISION_INTERFACE_VERSION );
  2148. physprop = (IPhysicsSurfaceProps *)FindSystem( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION );
  2149. g_pLocalize = (vgui::ILocalize *)FindSystem(VGUI_LOCALIZE_INTERFACE_VERSION );
  2150. soundemitter = (ISoundEmitterSystemBase*)FindSystem(SOUNDEMITTERSYSTEM_INTERFACE_VERSION);
  2151. if ( !soundemitter || !g_pLocalize || !filesystem || !physprop || !physcollision ||
  2152. !g_pMaterialSystem || !g_pStudioRender || !g_pMDLCache || !g_pDataCache )
  2153. {
  2154. Error("Unable to load required library interface!\n");
  2155. }
  2156. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
  2157. filesystem->SetWarningFunc( Warning );
  2158. // Add paths...
  2159. if ( !SetupSearchPaths() )
  2160. return false;
  2161. // Get the adapter from the command line....
  2162. const char *pAdapterString;
  2163. int nAdapter = 0;
  2164. if (CommandLine()->CheckParm( "-adapter", &pAdapterString ))
  2165. {
  2166. nAdapter = atoi( pAdapterString );
  2167. }
  2168. int adapterFlags = MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE;
  2169. if ( CommandLine()->CheckParm( "-ref" ) )
  2170. {
  2171. adapterFlags |= MATERIAL_INIT_REFERENCE_RASTERIZER;
  2172. }
  2173. g_pMaterialSystem->SetAdapter( nAdapter, adapterFlags );
  2174. LoadFileSystemDialogModule();
  2175. return true;
  2176. }
  2177. void CHLFacePoserApp::PostShutdown()
  2178. {
  2179. UnloadFileSystemDialogModule();
  2180. g_pFileSystem = filesystem = NULL;
  2181. g_pStudioDataCache = NULL;
  2182. physcollision = NULL;
  2183. physprop = NULL;
  2184. BaseClass::PostShutdown();
  2185. g_Factory = NULL;
  2186. }
  2187. //-----------------------------------------------------------------------------
  2188. // main application
  2189. //-----------------------------------------------------------------------------
  2190. int CHLFacePoserApp::Main()
  2191. {
  2192. // Do Perforce Stuff
  2193. g_p4factory->SetDummyMode( false );
  2194. if ( CommandLine()->FindParm( "-nop4" ) || !p4 )
  2195. {
  2196. g_p4factory->SetDummyMode( true );
  2197. }
  2198. g_p4factory->SetOpenFileChangeList( "FacePoser Auto Checkout" );
  2199. soundemitter->ModInit();
  2200. g_pMaterialSystem->ModInit();
  2201. g_pDataCache->SetSize( 64 * 1024 * 1024 );
  2202. // Always start with english
  2203. g_pLocalize->AddFile( "resource/closecaption_english.txt", "GAME", true );
  2204. sound->Init();
  2205. IFacePoserToolWindow::EnableToolRedraw( false );
  2206. g_MDLViewer = new MDLViewer ();
  2207. g_MDLViewer->setMenuBar (g_MDLViewer->getMenuBar ());
  2208. FaceposerVGui()->Init( (HWND)g_MDLViewer->getHandle() );
  2209. // Force reload of close captioning data file!!!
  2210. SetCloseCaptionLanguageId( g_viewerSettings.cclanguageid, true );
  2211. g_pStudioModel->Init();
  2212. int i;
  2213. bool modelloaded = false;
  2214. for ( i = 1; i < CommandLine()->ParmCount(); i++ )
  2215. {
  2216. if ( Q_stristr (CommandLine()->GetParm( i ), ".mdl") )
  2217. {
  2218. modelloaded = true;
  2219. g_MDLViewer->LoadModelFile( CommandLine()->GetParm( i ) );
  2220. break;
  2221. }
  2222. }
  2223. models->LoadModelList();
  2224. g_pPhonemeEditor->ValidateSpeechAPIIndex();
  2225. if ( models->Count() == 0 )
  2226. {
  2227. g_pFlexPanel->initFlexes( );
  2228. }
  2229. // Load expressions from last time
  2230. int files = workspacefiles->GetNumStoredFiles( IWorkspaceFiles::EXPRESSION );
  2231. for ( i = 0; i < files; i++ )
  2232. {
  2233. expressions->LoadClass( workspacefiles->GetStoredFile( IWorkspaceFiles::EXPRESSION, i ) );
  2234. }
  2235. IFacePoserToolWindow::EnableToolRedraw( true );
  2236. int nRetVal = mx::run ();
  2237. if (g_pStudioModel)
  2238. {
  2239. g_pStudioModel->Shutdown();
  2240. g_pStudioModel = NULL;
  2241. }
  2242. g_pMaterialSystem->ModShutdown();
  2243. soundemitter->ModShutdown();
  2244. g_pMaterialSystem->ModShutdown();
  2245. FaceposerVGui()->Shutdown();
  2246. return nRetVal;
  2247. }
  2248. static bool CHLFacePoserApp_SuggestGameInfoDirFn( CFSSteamSetupInfo const *pFsSteamSetupInfo, char *pchPathBuffer, int nBufferLength, bool *pbBubbleDirectories )
  2249. {
  2250. if ( pbBubbleDirectories )
  2251. *pbBubbleDirectories = true;
  2252. for ( int i = 1; i < CommandLine()->ParmCount(); i++ )
  2253. {
  2254. if ( Q_stristr( CommandLine()->GetParm( i ), ".mdl" ) )
  2255. {
  2256. Q_MakeAbsolutePath( pchPathBuffer, nBufferLength, CommandLine()->GetParm( i ) );
  2257. return true;
  2258. }
  2259. }
  2260. return false;
  2261. }
  2262. int main (int argc, char *argv[])
  2263. {
  2264. CommandLine()->CreateCmdLine( argc, argv );
  2265. CoInitialize(NULL);
  2266. // make sure, we start in the right directory
  2267. char szName[256];
  2268. strcpy (szName, mx::getApplicationPath() );
  2269. mx::init (argc, argv);
  2270. char workingdir[ 256 ];
  2271. workingdir[0] = 0;
  2272. Q_getwd( workingdir, sizeof( workingdir ) );
  2273. // Set game info directory suggestion callback
  2274. SetSuggestGameInfoDirFn( CHLFacePoserApp_SuggestGameInfoDirFn );
  2275. CHLFacePoserApp hlFacePoserApp;
  2276. CSteamApplication steamApplication( &hlFacePoserApp );
  2277. int nRetVal = steamApplication.Run();
  2278. CoUninitialize();
  2279. return nRetVal;
  2280. }