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.

2811 lines
67 KiB

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