summaryrefslogtreecommitdiff
path: root/utils/hlfaceposer/mdlviewer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hlfaceposer/mdlviewer.cpp')
-rw-r--r--utils/hlfaceposer/mdlviewer.cpp2752
1 files changed, 2752 insertions, 0 deletions
diff --git a/utils/hlfaceposer/mdlviewer.cpp b/utils/hlfaceposer/mdlviewer.cpp
new file mode 100644
index 0000000..7c4d2ba
--- /dev/null
+++ b/utils/hlfaceposer/mdlviewer.cpp
@@ -0,0 +1,2752 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+#include "cbase.h"
+#include <direct.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <mxtk/mx.h>
+#include <mxtk/mxTga.h>
+#include <mxtk/mxEvent.h>
+#include "mdlviewer.h"
+#include "ViewerSettings.h"
+#include "MatSysWin.h"
+#include "ControlPanel.h"
+#include "FlexPanel.h"
+#include "StudioModel.h"
+#include "mxExpressionTray.h"
+#include "mxStatusWindow.h"
+#include "ChoreoView.h"
+#include "ifaceposersound.h"
+#include "ifaceposerworkspace.h"
+#include "expclass.h"
+#include "PhonemeEditor.h"
+#include "filesystem.h"
+#include "ExpressionTool.h"
+#include "ControlPanel.h"
+#include "choreowidgetdrawhelper.h"
+#include "choreoviewcolors.h"
+#include "tabwindow.h"
+#include "faceposer_models.h"
+#include "choiceproperties.h"
+#include "choreoscene.h"
+#include "choreoactor.h"
+#include "tier1/strtools.h"
+#include "InputProperties.h"
+#include "GestureTool.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "inputsystem/iinputsystem.h"
+#include "RampTool.h"
+#include "SceneRampTool.h"
+#include "tier0/icommandline.h"
+#include "phonemeextractor/PhonemeExtractor.h"
+#include "animationbrowser.h"
+#include "CloseCaptionTool.h"
+#include "wavebrowser.h"
+#include "vcdbrowser.h"
+#include "ifilesystemopendialog.h"
+#include <vgui/ILocalize.h>
+#include <vgui/IVGui.h>
+#include "appframework/appframework.h"
+#include "icvar.h"
+#include "vstdlib/cvar.h"
+#include "istudiorender.h"
+#include "materialsystem/imaterialsystem.h"
+#include "vphysics_interface.h"
+#include "Datacache/imdlcache.h"
+#include "datacache/idatacache.h"
+#include "filesystem_init.h"
+#include "materialsystem/imaterialsystemhardwareconfig.h"
+#include "tier1/strtools.h"
+#include "appframework/tier3app.h"
+#include "faceposer_vgui.h"
+#include "vguiwnd.h"
+#include "vgui_controls/Frame.h"
+#include "vgui/ISurface.h"
+#include "p4lib/ip4.h"
+#include "tier2/p4helpers.h"
+#include "ProgressDialog.h"
+#include "scriplib.h"
+
+#define WINDOW_TAB_OFFSET 24
+
+MDLViewer *g_MDLViewer = 0;
+char g_appTitle[] = "Half-Life Face Poser";
+static char recentFiles[8][256] = { "", "", "", "", "", "", "", "" };
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+IPhysicsSurfaceProps *physprop;
+IPhysicsCollision *physcollision;
+IStudioDataCache *g_pStudioDataCache;
+vgui::ILocalize *g_pLocalize = NULL;
+ISoundEmitterSystemBase *soundemitter = NULL;
+CreateInterfaceFn g_Factory;
+IFileSystem *g_pFileSystem = NULL;
+
+bool g_bInError = false;
+
+static char gamedir[MAX_PATH]; // full path to gamedir U:\main\game\ep2
+static char gamedirsimple[MAX_PATH]; // just short name: ep2
+
+// Filesystem dialog module wrappers.
+CSysModule *g_pFSDialogModule = 0;
+CreateInterfaceFn g_FSDialogFactory = 0;
+
+#include "vgui_controls/TextEntry.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/ComboBox.h"
+#include "tier1/fmtstr.h"
+
+class CFacePoserVguiFrame : public Frame
+{
+ DECLARE_CLASS_SIMPLE( CFacePoserVguiFrame, Frame );
+
+public:
+ CFacePoserVguiFrame( Panel *parent, const char *panelName ) :
+ BaseClass( parent, panelName )
+ {
+ SetTitle( panelName, true );
+
+ SetTitleBarVisible( false );
+
+ SetSizeable( false );
+ SetMoveable( false );
+
+ SetPaintBackgroundEnabled( true );
+ SetCloseButtonVisible( false );
+ m_pEntry = new TextEntry( this, "textentry" );
+ m_pEntry->AddActionSignalTarget( this );
+ m_pButton = new Button( this, "button", "Button1", this );
+ m_pButton->SetCommand( new KeyValues( "OnButtonPressed" ) );
+ m_pLabel = new Label( this, "label", "..." );
+
+ m_pCombo = new ComboBox( this, "combo", 5, true );
+ for ( int i = 0; i < 10; ++i )
+ {
+ m_pCombo->AddItem( CFmtStr( "item%02d", i + 1 ), NULL );
+ }
+ }
+
+ MESSAGE_FUNC( OnButtonPressed, "OnButtonPressed" )
+ {
+ Msg( "OnButtonPressed\n" );
+ }
+
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", str )
+ {
+ char sz[ 256 ];
+ m_pEntry->GetText( sz, sizeof( sz ) );
+ m_pLabel->SetText( sz );
+
+ m_pCombo->GetText( sz, sizeof( sz ) );
+ Msg( "Combo %s\n", sz );
+ }
+
+ virtual void PerformLayout()
+ {
+ BaseClass::PerformLayout();
+
+ int w, h;
+ GetSize( w, h );
+
+ int y = 30;
+ int skip = 20;
+ m_pEntry->SetBounds( 5, y, w, skip - 2 );
+ y += skip;
+ m_pButton->SetBounds( 5, y, w, skip - 2 );
+ y += skip;
+ m_pCombo->SetBounds( 5, y, w, skip - 2 );
+ y += skip;
+ m_pLabel->SetBounds( 5, y, w, skip - 2 );
+ y += skip;
+
+ }
+
+private:
+
+ TextEntry *m_pEntry;
+ Button *m_pButton;
+ Label *m_pLabel;
+ ComboBox *m_pCombo;
+};
+
+class TestWindow : public CVGuiPanelWnd, public IFacePoserToolWindow
+{
+ typedef CVGuiPanelWnd BaseClass;
+
+public:
+
+ TestWindow( mxWindow *parent, int x, int y, int w, int h) :
+ BaseClass(parent, x, y, w, h ),
+ IFacePoserToolWindow( "FacePoser Frame", "FacePoser Frame" )
+ {
+ CFacePoserVguiFrame *f = new CFacePoserVguiFrame( NULL, "FacePoser Frame" );
+
+ SetParentWindow( this );
+ SetMainPanel( f );
+ f->SetVisible( true );
+ f->SetPaintBackgroundEnabled( true );
+
+ FacePoser_MakeToolWindow( this, true );
+ }
+
+ virtual int handleEvent( mxEvent *event )
+ {
+ if ( HandleToolEvent( event ) )
+ return 1;
+ return BaseClass::handleEvent( event );
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// FIXME: Remove this crap (from cmdlib.cpp)
+// We can't include cmdlib owing to appframework incompatibilities
+//-----------------------------------------------------------------------------
+void Q_mkdir( const char *path )
+{
+#if defined( _WIN32 ) || defined( WIN32 )
+ if (_mkdir (path) != -1)
+ return;
+#else
+ if (mkdir (path, 0777) != -1)
+ return;
+#endif
+ if (errno != EEXIST)
+ {
+ Error ("mkdir %s: %s",path, strerror(errno));
+ }
+}
+
+void CreatePath( const char *relative )
+{
+ char fullpath[ 512 ];
+ Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", GetGameDirectory(), relative );
+
+ char *path = fullpath;
+
+ char *ofs, c;
+
+ if (path[1] == ':')
+ {
+ path += 2;
+ }
+
+ for (ofs = const_cast<char*>(path+1); *ofs ; ofs++)
+ {
+ c = *ofs;
+ if (c == '/' || c == '\\')
+ {
+ // create the directory, but not if it's actually a filename with a dot in it!!!
+ *ofs = 0;
+ if ( !Q_stristr( path, "." ) )
+ {
+ Q_mkdir (path);
+ }
+ *ofs = c;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// LoadFile
+//-----------------------------------------------------------------------------
+int LoadFile (const char *filename, void **bufferptr)
+{
+ FileHandle_t f = filesystem->Open( filename, "rb" );
+ int length = filesystem->Size( f );
+ void *buffer = malloc (length+1);
+ ((char *)buffer)[length] = 0;
+ if ( filesystem->Read (buffer, length, f) != (int)length )
+ {
+ Error ("File read failure");
+ }
+ filesystem->Close (f);
+
+ *bufferptr = buffer;
+ return length;
+}
+
+char *ExpandPath(char *path)
+{
+ static char full[1024];
+ if (path[0] == '/' || path[0] == '\\' || path[1] == ':')
+ return path;
+
+ V_sprintf_safe( full, "%s%s", gamedir, path );
+ return full;
+}
+
+
+//-----------------------------------------------------------------------------
+// This is here because scriplib.cpp is included in this project but cmdlib.cpp
+// is not, but scriplib.cpp uses some stuff from cmdlib.cpp, same with
+// LoadFile and ExpandPath above. The only thing that currently uses this
+// is $include in scriptlib, if this function returns 0, $include will
+// behave the way it did before this change
+//-----------------------------------------------------------------------------
+int CmdLib_ExpandWithBasePaths( CUtlVector< CUtlString > &expandedPathList, const char *pszPath )
+{
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// FIXME: Move into appsystem framework
+//-----------------------------------------------------------------------------
+void LoadFileSystemDialogModule()
+{
+ Assert( !g_pFSDialogModule );
+
+ // Load the module with the file system open dialog.
+ const char *pDLLName = "FileSystemOpenDialog.dll";
+ g_pFSDialogModule = Sys_LoadModule( pDLLName );
+ if ( g_pFSDialogModule )
+ {
+ g_FSDialogFactory = Sys_GetFactory( g_pFSDialogModule );
+ }
+
+ if ( !g_pFSDialogModule || !g_FSDialogFactory )
+ {
+ if ( g_pFSDialogModule )
+ {
+ Sys_UnloadModule( g_pFSDialogModule );
+ g_pFSDialogModule = NULL;
+ }
+ }
+}
+
+void UnloadFileSystemDialogModule()
+{
+ if ( g_pFSDialogModule )
+ {
+ Sys_UnloadModule( g_pFSDialogModule );
+ g_pFSDialogModule = 0;
+ }
+}
+
+
+
+void
+MDLViewer::initRecentFiles ()
+{
+ for (int i = 0; i < 8; i++)
+ {
+ if (strlen (recentFiles[i]))
+ {
+ mb->modify (IDC_FILE_RECENTFILES1 + i, IDC_FILE_RECENTFILES1 + i, recentFiles[i]);
+ }
+ else
+ {
+ mb->modify (IDC_FILE_RECENTFILES1 + i, IDC_FILE_RECENTFILES1 + i, "(empty)");
+ mb->setEnabled (IDC_FILE_RECENTFILES1 + i, false);
+ }
+ }
+}
+
+
+#define RECENTFILESPATH "/hlfaceposer.rf"
+void
+MDLViewer::loadRecentFiles ()
+{
+ char path[256];
+ strcpy (path, mx::getApplicationPath ());
+ strcat (path, RECENTFILESPATH);
+ FILE *file = fopen (path, "rb");
+ if (file)
+ {
+ fread (recentFiles, sizeof recentFiles, 1, file);
+ fclose (file);
+ }
+}
+
+
+
+void
+MDLViewer::saveRecentFiles ()
+{
+ char path[256];
+
+ strcpy (path, mx::getApplicationPath ());
+ strcat (path, RECENTFILESPATH);
+
+ FILE *file = fopen (path, "wb");
+ if (file)
+ {
+ fwrite (recentFiles, sizeof recentFiles, 1, file);
+ fclose (file);
+ }
+}
+
+bool MDLViewer::AreSoundScriptsDirty()
+{
+ // Save any changed sound script files
+ int c = soundemitter->GetNumSoundScripts();
+ for ( int i = 0; i < c; i++ )
+ {
+ if ( soundemitter->IsSoundScriptDirty( i ) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool MDLViewer::CanClose()
+{
+ Con_Printf( "Checking for vcd changes...\n" );
+
+ if ( m_bVCDSaved )
+ {
+ int retval = mxMessageBox( NULL, "Rebuild scenes.image?", g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval == 2 )
+ {
+ return false;
+ }
+
+ m_bVCDSaved = false;
+ if ( retval == 0 ) // YES
+ {
+ OnRebuildScenesImage();
+ }
+ }
+
+ Con_Printf( "Checking for sound script changes...\n" );
+
+ // Save any changed sound script files
+ int c = soundemitter->GetNumSoundScripts();
+ for ( int i = 0; i < c; i++ )
+ {
+ if ( !soundemitter->IsSoundScriptDirty( i ) )
+ continue;
+
+ char const *scriptname = soundemitter->GetSoundScriptName( i );
+ if ( !scriptname )
+ continue;
+
+ if ( !filesystem->FileExists( scriptname ) ||
+ !filesystem->IsFileWritable( scriptname ) )
+ {
+ continue;
+ }
+
+ int retval = mxMessageBox( NULL, va( "Save changes to sound script '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval == 2 )
+ {
+ return false;
+ }
+
+ if ( retval == 0 )
+ {
+ soundemitter->SaveChangesToSoundScript( i );
+ }
+ }
+
+ SaveWindowPositions();
+
+ models->SaveModelList();
+ models->CloseAllModels();
+
+ return true;
+}
+
+bool MDLViewer::Closing( void )
+{
+ return true;
+}
+
+#define IDC_GRIDSETTINGS_FPS 1001
+#define IDC_GRIDSETTINGS_SNAP 1002
+
+class CFlatButton : public mxButton
+{
+public:
+ CFlatButton( mxWindow *parent, int id )
+ : mxButton( parent, 0, 0, 0, 0, "", id )
+ {
+ HWND wnd = (HWND)getHandle();
+ DWORD exstyle = GetWindowLong( wnd, GWL_EXSTYLE );
+ exstyle |= WS_EX_CLIENTEDGE;
+ SetWindowLong( wnd, GWL_EXSTYLE, exstyle );
+
+ DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ style &= ~WS_BORDER;
+ SetWindowLong( wnd, GWL_STYLE, style );
+
+ }
+};
+
+class CMDLViewerGridSettings : public mxWindow
+{
+public:
+ typedef mxWindow BaseClass;
+
+ CMDLViewerGridSettings( mxWindow *parent, int x, int y, int w, int h ) :
+ mxWindow( parent, x, y, w, h )
+ {
+ FacePoser_AddWindowStyle( this, WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+ m_btnFPS = new CFlatButton( this, IDC_GRIDSETTINGS_FPS );
+ m_btnGridSnap = new CFlatButton( this, IDC_GRIDSETTINGS_SNAP );
+
+ }
+
+ void Init( void )
+ {
+ if ( g_pChoreoView )
+ {
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( scene )
+ {
+ char sz[ 256 ];
+ Q_snprintf( sz, sizeof( sz ), "%i fps", scene->GetSceneFPS() );
+ m_btnFPS->setLabel( sz );
+
+ Q_snprintf( sz, sizeof( sz ), "snap: %s", scene->IsUsingFrameSnap() ? "on" : "off" );
+ m_btnGridSnap->setLabel( sz );
+
+ m_btnFPS->setVisible( true );
+ m_btnGridSnap->setVisible( true );
+ return;
+ }
+ }
+
+ m_btnFPS->setVisible( false );
+ m_btnGridSnap->setVisible( false );
+ }
+
+ virtual int handleEvent( mxEvent *event )
+ {
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Size:
+ {
+ int leftedge = w2() * 0.45f;
+ m_btnFPS->setBounds( 0, 0, leftedge, h2() );
+ m_btnGridSnap->setBounds( leftedge, 0, w2() - leftedge, h2() );
+ iret = 1;
+ }
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ iret = 0;
+ break;
+ case IDC_GRIDSETTINGS_FPS:
+ {
+ if ( g_pChoreoView )
+ {
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( scene )
+ {
+ int currentFPS = scene->GetSceneFPS();
+
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+
+ strcpy( params.m_szDialogTitle, "Change FPS" );
+
+ Q_snprintf( params.m_szInputText, sizeof( params.m_szInputText ),
+ "%i", currentFPS );
+
+ strcpy( params.m_szPrompt, "Current FPS:" );
+
+ if ( InputProperties( &params ) )
+ {
+ int newFPS = atoi( params.m_szInputText );
+
+ if ( ( newFPS > 0 ) && ( newFPS != currentFPS ) )
+ {
+ g_pChoreoView->SetDirty( true );
+ g_pChoreoView->PushUndo( "Change Scene FPS" );
+ scene->SetSceneFPS( newFPS );
+ g_pChoreoView->PushRedo( "Change Scene FPS" );
+ Init();
+
+ Con_Printf( "FPS changed to %i\n", newFPS );
+ }
+ }
+
+ }
+ }
+ }
+ break;
+ case IDC_GRIDSETTINGS_SNAP:
+ {
+ if ( g_pChoreoView )
+ {
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( scene )
+ {
+ g_pChoreoView->SetDirty( true );
+ g_pChoreoView->PushUndo( "Change Snap Frame" );
+
+ scene->SetUsingFrameSnap( !scene->IsUsingFrameSnap() );
+
+ g_pChoreoView->PushRedo( "Change Snap Frame" );
+
+ Init();
+
+ Con_Printf( "Time frame snapping: %s\n",
+ scene->IsUsingFrameSnap() ? "on" : "off" );
+ }
+ }
+
+
+ }
+ break;
+ }
+ }
+ }
+ return iret;
+ }
+
+ bool PaintBackground( void )
+ {
+ CChoreoWidgetDrawHelper drawHelper( this );
+ RECT rc;
+ drawHelper.GetClientRect( rc );
+ drawHelper.DrawFilledRect( GetSysColor( COLOR_BTNFACE ), rc );
+ return false;
+ }
+
+private:
+
+ CFlatButton *m_btnFPS;
+ CFlatButton *m_btnGridSnap;
+};
+
+
+#define IDC_MODELTAB_LOAD 1000
+#define IDC_MODELTAB_CLOSE 1001
+#define IDC_MODELTAB_CLOSEALL 1002
+#define IDC_MODELTAB_CENTERONFACE 1003
+#define IDC_MODELTAB_ASSOCIATEACTOR 1004
+#define IDC_MODELTAB_TOGGLE3DVIEW 1005
+#define IDC_MODELTAB_SHOWALL 1006
+#define IDC_MODELTAB_HIDEALL 1007
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CMDLViewerModelTab : public CTabWindow
+{
+public:
+ typedef CTabWindow BaseClass;
+
+ CMDLViewerModelTab( mxWindow *parent, int x, int y, int w, int h, int id = 0, int style = 0 ) :
+ CTabWindow( parent, x, y, w, h, id, style )
+ {
+ SetInverted( true );
+ }
+
+ virtual void ShowRightClickMenu( int mx, int my )
+ {
+ mxPopupMenu *pop = new mxPopupMenu();
+ Assert( pop );
+
+ char const *current = "";
+ char const *filename = "";
+ int idx = getSelectedIndex();
+ if ( idx >= 0 )
+ {
+ current = models->GetModelName( idx );
+ filename = models->GetModelFileName( idx );
+ }
+
+ if ( models->Count() < MAX_FP_MODELS )
+ {
+ pop->add( "Load Model...", IDC_MODELTAB_LOAD );
+ }
+ if ( idx >= 0 )
+ {
+ pop->add( va( "Close '%s'", current ), IDC_MODELTAB_CLOSE );
+ }
+ if ( models->Count() > 0 )
+ {
+ pop->add( "Close All", IDC_MODELTAB_CLOSEALL );
+ }
+ if ( idx >= 0 )
+ {
+ pop->addSeparator();
+ pop->add( va( "Center %s's face", current ), IDC_MODELTAB_CENTERONFACE );
+
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( scene )
+ {
+ // See if there is already an actor with this model associated
+ int c = scene->GetNumActors();
+ bool hasassoc = false;
+ for ( int i = 0; i < c; i++ )
+ {
+ CChoreoActor *a = scene->GetActor( i );
+ Assert( a );
+
+ if ( stricmp( a->GetFacePoserModelName(), filename ) )
+ continue;
+ hasassoc = true;
+ break;
+ }
+
+ if ( hasassoc )
+ {
+ pop->add( va( "Change associated actor for %s", current ), IDC_MODELTAB_ASSOCIATEACTOR );
+ }
+ else
+ {
+ pop->add( va( "Associate actor to %s", current ), IDC_MODELTAB_ASSOCIATEACTOR );
+ }
+ }
+
+ pop->addSeparator();
+
+ bool visible = models->IsModelShownIn3DView( idx );
+ if ( visible )
+ {
+ pop->add( va( "Remove %s from 3D View", current ), IDC_MODELTAB_TOGGLE3DVIEW );
+ }
+ else
+ {
+ pop->add( va( "Show %s in 3D View", current ), IDC_MODELTAB_TOGGLE3DVIEW );
+ }
+ }
+ if ( models->Count() > 0 )
+ {
+ pop->addSeparator();
+ pop->add( "Show All", IDC_MODELTAB_SHOWALL );
+ pop->add( "Hide All", IDC_MODELTAB_HIDEALL );
+ }
+
+ // Convert click position
+ POINT pt;
+ pt.x = mx;
+ pt.y = my;
+
+ // Convert coordinate space
+ pop->popup( this, pt.x, pt.y );
+ }
+
+ virtual int handleEvent( mxEvent *event )
+ {
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ iret = 0;
+ break;
+ case IDC_MODELTAB_SHOWALL:
+ case IDC_MODELTAB_HIDEALL:
+ {
+ bool show = ( event->action == IDC_MODELTAB_SHOWALL ) ? true : false;
+ int c = models->Count();
+ for ( int i = 0; i < c ; i++ )
+ {
+ models->ShowModelIn3DView( i, show );
+ }
+ }
+ break;
+ case IDC_MODELTAB_LOAD:
+ {
+ if ( ! CommandLine()->FindParm( "-NoSteamDialog" ) )
+ {
+ g_MDLViewer->LoadModel_Steam();
+ }
+ else
+ {
+ char modelfile[ 512 ];
+ if ( FacePoser_ShowOpenFileNameDialog( modelfile, sizeof( modelfile ), "models", "*.mdl" ) )
+ {
+ g_MDLViewer->LoadModelFile( modelfile );
+ }
+ }
+ }
+ break;
+ case IDC_MODELTAB_CLOSE:
+ {
+ int idx = getSelectedIndex();
+ if ( idx >= 0 )
+ {
+ models->FreeModel( idx );
+ }
+ }
+ break;
+ case IDC_MODELTAB_CLOSEALL:
+ {
+ models->CloseAllModels();
+ }
+ break;
+ case IDC_MODELTAB_CENTERONFACE:
+ {
+ g_pControlPanel->CenterOnFace();
+ }
+ break;
+ case IDC_MODELTAB_TOGGLE3DVIEW:
+ {
+ int idx = getSelectedIndex();
+ if ( idx >= 0 )
+ {
+ bool visible = models->IsModelShownIn3DView( idx );
+ models->ShowModelIn3DView( idx, !visible );
+ }
+ }
+ break;
+ case IDC_MODELTAB_ASSOCIATEACTOR:
+ {
+ int idx = getSelectedIndex();
+ if ( idx >= 0 )
+ {
+ char const *modelname = models->GetModelFileName( idx );
+
+ CChoreoScene *scene = g_pChoreoView->GetScene();
+ if ( scene )
+ {
+ CChoiceParams params;
+ strcpy( params.m_szDialogTitle, "Associate Actor" );
+
+ params.m_bPositionDialog = false;
+ params.m_nLeft = 0;
+ params.m_nTop = 0;
+ strcpy( params.m_szPrompt, "Choose actor:" );
+
+ params.m_Choices.RemoveAll();
+
+ params.m_nSelected = -1;
+ int oldsel = -1;
+
+ int c = scene->GetNumActors();
+ ChoiceText text;
+ for ( int i = 0; i < c; i++ )
+ {
+ CChoreoActor *a = scene->GetActor( i );
+ Assert( a );
+
+
+ strcpy( text.choice, a->GetName() );
+
+ if ( !stricmp( a->GetFacePoserModelName(), modelname ) )
+ {
+ params.m_nSelected = i;
+ oldsel = -1;
+ }
+
+ params.m_Choices.AddToTail( text );
+ }
+
+ if ( ChoiceProperties( &params ) &&
+ params.m_nSelected != oldsel )
+ {
+
+ // Chose something new...
+ CChoreoActor *a = scene->GetActor( params.m_nSelected );
+
+ g_pChoreoView->AssociateModelToActor( a, idx );
+ }
+ }
+ }
+
+ }
+ }
+ }
+ break;
+ }
+ if ( iret )
+ return iret;
+ return BaseClass::handleEvent( event );
+ }
+
+
+ void HandleModelSelect( void )
+ {
+ int idx = getSelectedIndex();
+ if ( idx < 0 )
+ return;
+
+ // FIXME: Do any necessary window resetting here!!!
+ g_pControlPanel->ChangeModel( models->GetModelFileName( idx ) );
+ }
+
+ void Init( void )
+ {
+ removeAll();
+
+ int c = models->Count();
+ int i;
+ for ( i = 0; i < c ; i++ )
+ {
+ char const *name = models->GetModelName( i );
+
+ // Strip it down to the base name
+ char cleanname[ 256 ];
+ Q_FileBase( name, cleanname, sizeof( cleanname ) );
+
+ add( cleanname );
+ }
+ }
+};
+
+#define IDC_TOOL_TOGGLEVISIBILITY 1000
+#define IDC_TOOL_TOGGLELOCK 1001
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CMDLViewerWindowTab : public CTabWindow
+{
+public:
+ typedef CTabWindow BaseClass;
+
+ CMDLViewerWindowTab( mxWindow *parent, int x, int y, int w, int h, int id = 0, int style = 0 ) :
+ CTabWindow( parent, x, y, w, h, id, style )
+ {
+ SetInverted( true );
+
+ m_nLastSelected = -1;
+ m_flLastSelectedTime = -1;
+ }
+
+ virtual void ShowRightClickMenu( int mx, int my )
+ {
+ IFacePoserToolWindow *tool = GetSelectedTool();
+ if ( !tool )
+ return;
+
+ mxWindow *toolw = tool->GetMxWindow();
+ if ( !toolw )
+ return;
+
+ mxPopupMenu *pop = new mxPopupMenu();
+ Assert( pop );
+
+ bool isVisible = toolw->isVisible();
+ bool isLocked = tool->IsLocked();
+
+ pop->add( isVisible ? "Hide" : "Show", IDC_TOOL_TOGGLEVISIBILITY );
+ pop->add( isLocked ? "Unlock" : "Lock", IDC_TOOL_TOGGLELOCK );
+
+ // Convert click position
+ POINT pt;
+ pt.x = mx;
+ pt.y = my;
+
+ /*
+ ClientToScreen( (HWND)getHandle(), &pt );
+ ScreenToClient( (HWND)g_MDLViewer->getHandle(), &pt );
+ */
+
+ // Convert coordinate space
+ pop->popup( this, pt.x, pt.y );
+ }
+
+ virtual int handleEvent( mxEvent *event )
+ {
+ int iret = 0;
+ switch ( event->event )
+ {
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ iret = 0;
+ break;
+ case IDC_TOOL_TOGGLEVISIBILITY:
+ {
+ IFacePoserToolWindow *tool = GetSelectedTool();
+ if ( tool )
+ {
+ mxWindow *toolw = tool->GetMxWindow();
+ if ( toolw )
+ {
+ toolw->setVisible( !toolw->isVisible() );
+ g_MDLViewer->UpdateWindowMenu();
+ }
+ }
+ }
+ break;
+ case IDC_TOOL_TOGGLELOCK:
+ {
+ IFacePoserToolWindow *tool = GetSelectedTool();
+ if ( tool )
+ {
+ tool->ToggleLockedState();
+ }
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if ( iret )
+ return iret;
+ return BaseClass::handleEvent( event );
+ }
+
+ void Init( void )
+ {
+ int c = IFacePoserToolWindow::GetToolCount();
+ int i;
+ for ( i = 0; i < c ; i++ )
+ {
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
+ add( tool->GetDisplayNameRoot() );
+ }
+ }
+
+#define WINDOW_DOUBLECLICK_TIME 0.4
+
+ void HandleWindowSelect( void )
+ {
+ extern double realtime;
+ IFacePoserToolWindow *tool = GetSelectedTool();
+ if ( !tool )
+ return;
+
+ bool doubleclicked = false;
+
+ double curtime = realtime;
+ int clickedItem = getSelectedIndex();
+
+ if ( clickedItem == m_nLastSelected )
+ {
+ if ( curtime < m_flLastSelectedTime + WINDOW_DOUBLECLICK_TIME )
+ {
+ doubleclicked = true;
+ }
+ }
+
+ m_flLastSelectedTime = curtime;
+ m_nLastSelected = clickedItem;
+
+ mxWindow *toolw = tool->GetMxWindow();
+ if ( !toolw )
+ return;
+
+ if ( doubleclicked )
+ {
+ toolw->setVisible( !toolw->isVisible() );
+ m_flLastSelectedTime = -1;
+ }
+
+ if ( !toolw->isVisible() )
+ {
+ return;
+ }
+
+ // Move window to front
+ HWND wnd = (HWND)tool->GetMxWindow()->getHandle();
+ SetFocus( wnd );
+ SetWindowPos( wnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
+ }
+
+private:
+
+ IFacePoserToolWindow *GetSelectedTool()
+ {
+ int idx = getSelectedIndex();
+ int c = IFacePoserToolWindow::GetToolCount();
+
+ if ( idx < 0 || idx >= c )
+ return NULL;
+
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( idx );
+ return tool;
+ }
+
+ // HACKY double click handler
+ int m_nLastSelected;
+ double m_flLastSelectedTime;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: The workspace is the parent of all of the tool windows
+//-----------------------------------------------------------------------------
+class CMDLViewerWorkspace : public mxWindow
+{
+public:
+ CMDLViewerWorkspace( mxWindow *parent, int x, int y, int w, int h, const char *label = 0, int style = 0)
+ : mxWindow( parent, x, y, w, h, label, style )
+ {
+ FacePoser_AddWindowStyle( this, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+ }
+
+ //-----------------------------------------------------------------------------
+ // Purpose:
+ // Output : Returns true on success, false on failure.
+ //-----------------------------------------------------------------------------
+ bool PaintBackground( void )
+ {
+ CChoreoWidgetDrawHelper drawHelper( this );
+ RECT rc;
+ drawHelper.GetClientRect( rc );
+ drawHelper.DrawFilledRect( GetSysColor( COLOR_APPWORKSPACE ), rc );
+ return false;
+ }
+};
+
+void MDLViewer::LoadPosition( void )
+{
+ bool visible;
+ bool locked;
+ bool zoomed;
+ int x, y, w, h;
+
+ FacePoser_LoadWindowPositions( "MDLViewer", visible, x, y, w, h, locked, zoomed );
+
+ if ( w == 0 || h == 0 )
+ {
+ zoomed = true;
+ visible = true;
+ }
+
+ setBounds( x, y, w, h );
+ if ( zoomed )
+ {
+ ShowWindow( (HWND)getHandle(), SW_SHOWMAXIMIZED );
+ }
+ else
+ {
+ setVisible( visible );
+ }
+}
+
+void MDLViewer::SavePosition( void )
+{
+ bool visible;
+ int xpos, ypos, width, height;
+
+ visible = isVisible();
+ xpos = x();
+ ypos = y();
+ width = w();
+ height = h();
+
+ // xpos and ypos are screen space
+ POINT pt;
+ pt.x = xpos;
+ pt.y = ypos;
+
+ // Convert from screen space to relative to client area of parent window so
+ // the setBounds == MoveWindow call will offset to the same location
+ if ( getParent() )
+ {
+ ScreenToClient( (HWND)getParent()->getHandle(), &pt );
+ xpos = (short)pt.x;
+ ypos = (short)pt.y;
+ }
+
+ bool zoomed = IsZoomed( (HWND)getHandle() ) ? true : false;
+
+ bool iconic = IsIconic( (HWND)getHandle() ) ? true : false;
+
+ // Don't reset values if it's minimized during shutdown
+ if ( iconic )
+ return;
+
+ FacePoser_SaveWindowPositions( "MDLViewer", visible, xpos, ypos, width, height, false, zoomed );
+}
+
+MDLViewer::MDLViewer () :
+ mxWindow (0, 0, 0, 0, 0, g_appTitle, mxWindow::Normal),
+ menuCloseCaptionLanguages(0),
+ m_bOldSoundScriptsDirty( -1 ),
+ m_bVCDSaved( false )
+{
+ int i;
+
+ g_MDLViewer = this;
+
+ FacePoser_MakeToolWindow( this, false );
+
+ workspace = new CMDLViewerWorkspace( this, 0, 0, 500, 500, "" );
+ windowtab = new CMDLViewerWindowTab( this, 0, 500, 500, 20, IDC_WINDOW_TAB );
+ modeltab = new CMDLViewerModelTab( this, 500, 500, 200, 20, IDC_MODEL_TAB );
+ gridsettings = new CMDLViewerGridSettings( this, 0, 500, 500, 20 );
+ modeltab->SetRightJustify( true );
+
+ g_pStatusWindow = new mxStatusWindow( workspace, 0, 0, 1024, 150, "" );
+ g_pStatusWindow->setVisible( true );
+
+ InitViewerSettings( "faceposer" );
+ g_viewerSettings.speechapiindex = SPEECH_API_LIPSINC;
+ g_viewerSettings.m_iEditAttachment = -1;
+
+ LoadViewerRootSettings( );
+
+ LoadPosition();
+ // ShowWindow( (HWND)getHandle(), SW_SHOWMAXIMIZED );
+
+ g_pStatusWindow->setBounds( 0, h2() - 150, w2(), 150 );
+
+ Con_Printf( "MDLViewer started\n" );
+
+ Con_Printf( "Creating menu bar\n" );
+
+ // create menu stuff
+ mb = new mxMenuBar (this);
+ menuFile = new mxMenu ();
+ menuOptions = new mxMenu ();
+ menuWindow = new mxMenu ();
+ menuHelp = new mxMenu ();
+ menuEdit = new mxMenu ();
+ menuExpressions = new mxMenu();
+ menuChoreography = new mxMenu();
+
+ mb->addMenu ("File", menuFile);
+ //mb->addMenu( "Edit", menuEdit );
+ mb->addMenu ("Options", menuOptions);
+ mb->addMenu ( "Expression", menuExpressions );
+ mb->addMenu ( "Choreography", menuChoreography );
+ mb->addMenu ("Window", menuWindow);
+ mb->addMenu ("Help", menuHelp);
+
+ mxMenu *menuRecentFiles = new mxMenu ();
+ menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES1);
+ menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES2);
+ menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES3);
+ menuRecentFiles->add ("(empty)", IDC_FILE_RECENTFILES4);
+
+ menuFile->add ("Load Model...", IDC_FILE_LOADMODEL);
+ menuFile->add( "Refresh\tF5", IDC_FILE_REFRESH );
+
+ menuFile->addSeparator();
+ menuFile->add ("Save Sound Changes...", IDC_FILE_SAVESOUNDSCRIPTCHANGES );
+ menuFile->add( "Rebuild scenes.image...", IDC_FILE_REBUILDSCENESIMAGE );
+
+ menuFile->addSeparator();
+
+ menuFile->add ("Load Background Texture...", IDC_FILE_LOADBACKGROUNDTEX);
+ menuFile->add ("Load Ground Texture...", IDC_FILE_LOADGROUNDTEX);
+ menuFile->addSeparator ();
+ menuFile->add ("Unload Ground Texture", IDC_FILE_UNLOADGROUNDTEX);
+ menuFile->addSeparator ();
+ menuFile->addMenu ("Recent Files", menuRecentFiles);
+ menuFile->addSeparator ();
+ menuFile->add ("Exit", IDC_FILE_EXIT);
+
+ menuFile->setEnabled(IDC_FILE_LOADBACKGROUNDTEX, false);
+ menuFile->setEnabled(IDC_FILE_LOADGROUNDTEX, false);
+ menuFile->setEnabled(IDC_FILE_UNLOADGROUNDTEX, false);
+ menuFile->setEnabled(IDC_FILE_SAVESOUNDSCRIPTCHANGES, false);
+
+ menuOptions->add ("Background Color...", IDC_OPTIONS_COLORBACKGROUND);
+ menuOptions->add ("Ground Color...", IDC_OPTIONS_COLORGROUND);
+ menuOptions->add ("Light Color...", IDC_OPTIONS_COLORLIGHT);
+
+ {
+ menuCloseCaptionLanguages = new mxMenu();
+
+ for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
+ {
+ int id = IDC_OPTIONS_LANGUAGESTART + i;
+ menuCloseCaptionLanguages->add( CSentence::NameForLanguage( i ), id );
+ }
+
+ menuOptions->addSeparator();
+ menuOptions->addMenu( "CC Language", menuCloseCaptionLanguages );
+ }
+
+ menuOptions->addSeparator ();
+ menuOptions->add ("Center View", IDC_OPTIONS_CENTERVIEW);
+ menuOptions->add ("Center on Face", IDC_OPTIONS_CENTERONFACE );
+#ifdef WIN32
+ menuOptions->addSeparator ();
+ menuOptions->add ("Make Screenshot...", IDC_OPTIONS_MAKESCREENSHOT);
+ //menuOptions->add ("Dump Model Info", IDC_OPTIONS_DUMP);
+ menuOptions->addSeparator ();
+ menuOptions->add ("Clear model sounds.", IDC_OPTIONS_CLEARMODELSOUNDS );
+
+#endif
+
+ menuExpressions->add( "New...", IDC_EXPRESSIONS_NEW );
+ menuExpressions->addSeparator ();
+ menuExpressions->add( "Load...", IDC_EXPRESSIONS_LOAD );
+ menuExpressions->add( "Save", IDC_EXPRESSIONS_SAVE );
+ menuExpressions->addSeparator ();
+ menuExpressions->add( "Export to VFE", IDC_EXPRESSIONS_EXPORT );
+ menuExpressions->addSeparator ();
+ menuExpressions->add( "Close class", IDC_EXPRESSIONS_CLOSE );
+ menuExpressions->add( "Close all classes", IDC_EXPRESSIONS_CLOSEALL );
+ menuExpressions->addSeparator();
+ menuExpressions->add( "Recreate all bitmaps", IDC_EXPRESSIONS_REDOBITMAPS );
+
+ menuChoreography->add( "New...", IDC_CHOREOSCENE_NEW );
+ menuChoreography->addSeparator();
+ menuChoreography->add( "Load...", IDC_CHOREOSCENE_LOAD );
+ menuChoreography->add( "Save", IDC_CHOREOSCENE_SAVE );
+ menuChoreography->add( "Save As...", IDC_CHOREOSCENE_SAVEAS );
+ menuChoreography->addSeparator();
+ menuChoreography->add( "Close", IDC_CHOREOSCENE_CLOSE );
+ menuChoreography->addSeparator();
+ menuChoreography->add( "Add Actor...", IDC_CHOREOSCENE_ADDACTOR );
+ menuChoreography->addSeparator();
+ menuChoreography->add( "Load Next", IDC_CHOREOSCENE_LOADNEXT );
+
+#ifdef WIN32
+ menuHelp->add ("Goto Homepage...", IDC_HELP_GOTOHOMEPAGE);
+ menuHelp->addSeparator ();
+#endif
+ menuHelp->add ("About...", IDC_HELP_ABOUT);
+
+ // create the Material System window
+ Con_Printf( "Creating 3D View\n" );
+ g_pMatSysWindow = new MatSysWindow (workspace, 0, 0, 100, 100, "", mxWindow::Normal);
+
+ Con_Printf( "Creating Close Caption tool" );
+ g_pCloseCaptionTool = new CloseCaptionTool( workspace );
+
+ Con_Printf( "Creating control panel\n" );
+ g_pControlPanel = new ControlPanel (workspace);
+
+ Con_Printf( "Creating phoneme editor\n" );
+ g_pPhonemeEditor = new PhonemeEditor( workspace );
+
+ Con_Printf( "Creating expression tool\n" );
+ g_pExpressionTool = new ExpressionTool( workspace );
+
+ Con_Printf( "Creating gesture tool\n" );
+ g_pGestureTool = new GestureTool( workspace );
+
+ Con_Printf( "Creating ramp tool\n" );
+ g_pRampTool = new RampTool( workspace );
+
+ Con_Printf( "Creating scene ramp tool\n" );
+ g_pSceneRampTool = new SceneRampTool( workspace );
+
+ Con_Printf( "Creating expression tray\n" );
+ g_pExpressionTrayTool = new mxExpressionTray( workspace, IDC_EXPRESSIONTRAY );
+
+ Con_Printf( "Creating animation browser\n" );
+ g_pAnimationBrowserTool = new AnimationBrowser( workspace, IDC_ANIMATIONBROWSER );
+
+ Con_Printf( "Creating flex slider window\n" );
+ g_pFlexPanel = new FlexPanel( workspace );
+
+ Con_Printf( "Creating wave browser\n" );
+ g_pWaveBrowser = new CWaveBrowser( workspace );
+
+ Con_Printf( "Creating VCD browser\n" );
+ g_pVCDBrowser = new CVCDBrowser( workspace );
+
+ Con_Printf( "Creating choreography view\n" );
+ g_pChoreoView = new CChoreoView( workspace, 200, 200, 400, 300, 0 );
+ // Choreo scene file drives main window title name
+ g_pChoreoView->SetUseForMainWindowTitle( true );
+#if 0
+ new TestWindow( workspace, 100, 100, 256, 256 );
+#endif
+
+ Con_Printf( "IFacePoserToolWindow::Init\n" );
+
+ IFacePoserToolWindow::InitTools();
+
+ Con_Printf( "windowtab->Init\n" );
+
+ windowtab->Init();
+
+ Con_Printf( "loadRecentFiles\n" );
+
+ loadRecentFiles ();
+ initRecentFiles ();
+
+ Con_Printf( "RestoreThumbnailSize\n" );
+
+ g_pExpressionTrayTool->RestoreThumbnailSize();
+ g_pAnimationBrowserTool->RestoreThumbnailSize();
+
+ Con_Printf( "Add Tool Windows\n" );
+
+ int c = IFacePoserToolWindow::GetToolCount();
+ for ( i = 0; i < c ; i++ )
+ {
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
+ menuWindow->add( tool->GetToolName(), IDC_WINDOW_FIRSTTOOL + i );
+ }
+
+ menuWindow->addSeparator();
+ menuWindow->add( "Cascade", IDC_WINDOW_CASCADE );
+ menuWindow->addSeparator();
+ menuWindow->add( "Tile", IDC_WINDOW_TILE );
+ menuWindow->add( "Tile Horizontally", IDC_WINDOW_TILE_HORIZ );
+ menuWindow->add( "Tile Vertically", IDC_WINDOW_TILE_VERT );
+ menuWindow->addSeparator();
+ menuWindow->add( "Hide All", IDC_WINDOW_HIDEALL );
+ menuWindow->add( "Show All", IDC_WINDOW_SHOWALL );
+
+ Con_Printf( "UpdateWindowMenu\n" );
+
+ UpdateWindowMenu();
+ // Check the default item
+ UpdateLanguageMenu( g_viewerSettings.cclanguageid );
+
+ m_nCurrentFrame = 0;
+
+ Con_Printf( "gridsettings->Init()\n" );
+
+ gridsettings->Init();
+
+ Con_Printf( "LoadWindowPositions\n" );
+
+ LoadWindowPositions();
+
+ Con_Printf( "Model viewer created\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void MDLViewer::UpdateWindowMenu( void )
+{
+ int c = IFacePoserToolWindow::GetToolCount();
+ for ( int i = 0; i < c ; i++ )
+ {
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
+ menuWindow->setChecked( IDC_WINDOW_FIRSTTOOL + i, tool->GetMxWindow()->isVisible() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : currentLanguageId -
+//-----------------------------------------------------------------------------
+void MDLViewer::UpdateLanguageMenu( int currentLanguageId )
+{
+ if ( !menuCloseCaptionLanguages )
+ return;
+
+ for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
+ {
+ int id = IDC_OPTIONS_LANGUAGESTART + i;
+ menuCloseCaptionLanguages->setChecked( id, i == currentLanguageId ? true : false );
+ }
+}
+
+void MDLViewer::OnDelete()
+{
+ saveRecentFiles ();
+ SaveViewerRootSettings( );
+
+#ifdef WIN32
+ DeleteFile ("hlmv.cfg");
+ DeleteFile ("midump.txt");
+#endif
+
+ IFacePoserToolWindow::ShutdownTools();
+
+ g_MDLViewer = NULL;
+}
+
+MDLViewer::~MDLViewer ()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void MDLViewer::InitModelTab( void )
+{
+ modeltab->Init();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void MDLViewer::InitGridSettings( void )
+{
+ gridsettings->Init();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int MDLViewer::GetActiveModelTab( void )
+{
+ return modeltab->getSelectedIndex();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : modelindex -
+//-----------------------------------------------------------------------------
+void MDLViewer::SetActiveModelTab( int modelindex )
+{
+ modeltab->select( modelindex );
+ modeltab->HandleModelSelect();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reloads the currently loaded model file.
+//-----------------------------------------------------------------------------
+void MDLViewer::Refresh( void )
+{
+ Con_ColorPrintf( RGB( 0, 125, 255 ), "Refreshing...\n" );
+
+ bool reinit_soundemitter = true;
+
+ // Save any changed sound script files
+ int c = soundemitter->GetNumSoundScripts();
+ for ( int i = 0; i < c; i++ )
+ {
+ if ( !soundemitter->IsSoundScriptDirty( i ) )
+ continue;
+
+ char const *scriptname = soundemitter->GetSoundScriptName( i );
+ if ( !scriptname )
+ continue;
+
+ if ( !filesystem->FileExists( scriptname ) ||
+ !filesystem->IsFileWritable( scriptname ) )
+ {
+ continue;
+ }
+
+ int retval = mxMessageBox( NULL, va( "Save changes to sound script '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval != 0 )
+ {
+ reinit_soundemitter = false;
+ continue;
+ }
+
+ if ( retval == 0 )
+ {
+ soundemitter->SaveChangesToSoundScript( i );
+ Con_ColorPrintf( RGB( 50, 255, 100 ), " saving changes to script file '%s'\n", scriptname );
+ }
+ }
+
+ // kill the soundemitter system
+ if ( reinit_soundemitter )
+ {
+ soundemitter->Shutdown();
+ }
+
+
+ Con_ColorPrintf( RGB( 50, 255, 100 ), " reloading textures\n" );
+ g_pMaterialSystem->ReloadTextures();
+
+ models->ReleaseModels();
+
+ Con_ColorPrintf( RGB( 50, 255, 100 ), " reloading models\n" );
+ models->RestoreModels();
+
+ // restart the soundemitter system
+ if ( reinit_soundemitter )
+ {
+ Con_ColorPrintf( RGB( 50, 255, 100 ), " reloading sound emitter system\n" );
+ soundemitter->Init();
+ }
+ else
+ {
+ Con_ColorPrintf( RGB( 250, 50, 50 ), " NOT reloading sound emitter system\n" );
+ }
+
+ Con_ColorPrintf( RGB( 0, 125, 255 ), "done.\n" );
+}
+
+void MDLViewer::OnFileLoaded( char const *pszFile )
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ {
+ if (!Q_stricmp( recentFiles[i], pszFile ))
+ break;
+ }
+
+ // swap existing recent file
+ if (i < 8)
+ {
+ char tmp[256];
+ strcpy (tmp, recentFiles[0]);
+ strcpy (recentFiles[0], recentFiles[i]);
+ strcpy (recentFiles[i], tmp);
+ }
+
+ // insert recent file
+ else
+ {
+ for (i = 7; i > 0; i--)
+ strcpy (recentFiles[i], recentFiles[i - 1]);
+
+ strcpy( recentFiles[0], pszFile );
+ }
+
+ initRecentFiles ();
+
+ if ( g_pVCDBrowser )
+ {
+ g_pVCDBrowser->SetCurrent( pszFile );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads the file and updates the MRU list.
+// Input : pszFile - File to load.
+//-----------------------------------------------------------------------------
+void MDLViewer::LoadModelFile( const char *pszFile )
+{
+ models->LoadModel( pszFile );
+
+ OnFileLoaded( pszFile );
+
+ g_pControlPanel->CenterOnFace();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *wnd -
+// x -
+// y -
+// Output : static bool
+//-----------------------------------------------------------------------------
+static bool WindowContainsPoint( mxWindow *wnd, int x, int y )
+{
+ POINT pt;
+ pt.x = (short)x;
+ pt.y = (short)y;
+
+ HWND window = (HWND)wnd->getHandle();
+ if ( !window )
+ return false;
+
+ ScreenToClient( window, &pt );
+
+ if ( pt.x < 0 )
+ return false;
+ if ( pt.y < 0 )
+ return false;
+ if ( pt.x > wnd->w() )
+ return false;
+ if ( pt.y > wnd->h() )
+ return false;
+
+ return true;
+}
+
+
+void MDLViewer::LoadModel_Steam()
+{
+ if ( !g_FSDialogFactory )
+ return;
+
+ IFileSystemOpenDialog *pDlg;
+ pDlg = (IFileSystemOpenDialog*)g_FSDialogFactory( FILESYSTEMOPENDIALOG_VERSION, NULL );
+ if ( !pDlg )
+ {
+ char str[512];
+ Q_snprintf( str, sizeof( str ), "Can't create %s interface.", FILESYSTEMOPENDIALOG_VERSION );
+ ::MessageBox( NULL, str, "Error", MB_OK );
+ return;
+ }
+ pDlg->Init( g_Factory, NULL );
+ pDlg->AddFileMask( "*.jpg" );
+ pDlg->AddFileMask( "*.mdl" );
+ pDlg->SetInitialDir( "models", "game" );
+ pDlg->SetFilterMdlAndJpgFiles( true );
+
+ if (pDlg->DoModal() == IDOK)
+ {
+ char filename[MAX_PATH];
+ pDlg->GetFilename( filename, sizeof( filename ) );
+ LoadModelFile( filename );
+ }
+
+ pDlg->Release();
+}
+
+
+
+int MDLViewer::handleEvent (mxEvent *event)
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ int iret = 0;
+
+ switch (event->event)
+ {
+ case mxEvent::Size:
+ {
+ int width = w2();
+ int height = h2();
+
+ windowtab->SetRowHeight( WINDOW_TAB_OFFSET - 2 );
+ modeltab->SetRowHeight( WINDOW_TAB_OFFSET - 2 );
+
+ int gridsettingswide = 100;
+ int gridstart = width - gridsettingswide - 5;
+
+ int modelwide = gridstart / 3;
+ int windowwide = gridstart - modelwide;
+
+ int rowheight = max( windowtab->GetBestHeight( windowwide ), modeltab->GetBestHeight( modelwide ) );
+
+ workspace->setBounds( 0, 0, width, height - rowheight );
+
+ gridsettings->setBounds( gridstart, height - rowheight + 1, gridsettingswide, WINDOW_TAB_OFFSET - 2 );
+
+ windowtab->setBounds( 0, height - rowheight, windowwide, rowheight );
+ modeltab->setBounds( windowwide, height - rowheight, modelwide, rowheight );
+
+ iret = 1;
+ }
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch (event->action)
+ {
+ case IDC_WINDOW_TAB:
+ {
+ windowtab->HandleWindowSelect();
+ }
+ break;
+ case IDC_MODEL_TAB:
+ {
+ modeltab->HandleModelSelect();
+ }
+ break;
+
+ case IDC_FILE_LOADMODEL:
+ {
+ if ( ! CommandLine()->FindParm( "-NoSteamDialog" ) )
+ {
+ g_MDLViewer->LoadModel_Steam();
+ }
+ else
+ {
+ char modelfile[ 512 ];
+ if ( FacePoser_ShowOpenFileNameDialog( modelfile, sizeof( modelfile ), "models", "*.mdl" ) )
+ {
+ LoadModelFile( modelfile );
+ }
+ }
+ }
+ break;
+
+ case IDC_FILE_REFRESH:
+ {
+ Refresh();
+ break;
+ }
+
+ case IDC_FILE_SAVESOUNDSCRIPTCHANGES:
+ {
+ OnSaveSoundScriptChanges();
+ }
+ break;
+ case IDC_FILE_REBUILDSCENESIMAGE:
+ {
+ OnRebuildScenesImage();
+ }
+ break;
+
+ case IDC_FILE_LOADBACKGROUNDTEX:
+ case IDC_FILE_LOADGROUNDTEX:
+ {
+ const char *ptr = mxGetOpenFileName (this, 0, "*.*");
+ if (ptr)
+ {
+ if (0 /* g_pMatSysWindow->loadTexture (ptr, event->action - IDC_FILE_LOADBACKGROUNDTEX) */)
+ {
+ if (event->action == IDC_FILE_LOADBACKGROUNDTEX)
+ g_pControlPanel->setShowBackground (true);
+ else
+ g_pControlPanel->setShowGround (true);
+
+ }
+ else
+ mxMessageBox (this, "Error loading texture.", g_appTitle, MX_MB_OK | MX_MB_ERROR);
+ }
+ }
+ break;
+
+ case IDC_FILE_UNLOADGROUNDTEX:
+ {
+ // g_pMatSysWindow->loadTexture (0, 1);
+ g_pControlPanel->setShowGround (false);
+ }
+ break;
+
+ case IDC_FILE_RECENTFILES1:
+ case IDC_FILE_RECENTFILES2:
+ case IDC_FILE_RECENTFILES3:
+ case IDC_FILE_RECENTFILES4:
+ case IDC_FILE_RECENTFILES5:
+ case IDC_FILE_RECENTFILES6:
+ case IDC_FILE_RECENTFILES7:
+ case IDC_FILE_RECENTFILES8:
+ {
+ int i = event->action - IDC_FILE_RECENTFILES1;
+
+ if ( recentFiles[ i ] && recentFiles[ i ][ 0 ] )
+ {
+ char ext[ 4 ];
+ Q_ExtractFileExtension( recentFiles[ i ], ext, sizeof( ext ) );
+ bool valid = false;
+ if ( !Q_stricmp( ext, "mdl" ) )
+ {
+ // Check extension
+ LoadModelFile( recentFiles[ i ] );
+ valid = true;
+ }
+ else if ( !Q_stricmp( ext, "vcd" ) )
+ {
+ g_pChoreoView->LoadSceneFromFile( recentFiles[ i ] );
+ valid = true;
+ }
+
+ if ( valid )
+ {
+ char tmp[256];
+ strcpy (tmp, recentFiles[0]);
+ strcpy (recentFiles[0], recentFiles[i]);
+ strcpy (recentFiles[i], tmp);
+
+ initRecentFiles ();
+ }
+ }
+
+ redraw ();
+ }
+ break;
+
+ case IDC_FILE_EXIT:
+ {
+ redraw ();
+ mx::quit ();
+ }
+ break;
+
+ case IDC_OPTIONS_COLORBACKGROUND:
+ case IDC_OPTIONS_COLORGROUND:
+ case IDC_OPTIONS_COLORLIGHT:
+ {
+ float *cols[3] = { g_viewerSettings.bgColor, g_viewerSettings.gColor, g_viewerSettings.lColor };
+ float *col = cols[event->action - IDC_OPTIONS_COLORBACKGROUND];
+ int r = (int) (col[0] * 255.0f);
+ int g = (int) (col[1] * 255.0f);
+ int b = (int) (col[2] * 255.0f);
+ if (mxChooseColor (this, &r, &g, &b))
+ {
+ col[0] = (float) r / 255.0f;
+ col[1] = (float) g / 255.0f;
+ col[2] = (float) b / 255.0f;
+ }
+ }
+ break;
+
+ case IDC_OPTIONS_CENTERVIEW:
+ g_pControlPanel->centerView ();
+ break;
+
+ case IDC_OPTIONS_CENTERONFACE:
+ g_pControlPanel->CenterOnFace();
+ break;
+
+ case IDC_OPTIONS_CLEARMODELSOUNDS:
+ {
+ sound->StopAll();
+ Con_ColorPrintf( RGB( 0, 100, 255 ), "Resetting model sound channels\n" );
+ }
+ break;
+
+ case IDC_OPTIONS_MAKESCREENSHOT:
+ {
+ char *ptr = (char *) mxGetSaveFileName (this, "", "*.tga");
+ if (ptr)
+ {
+ char fn[ 512 ];
+ Q_strncpy( fn, ptr, sizeof( fn ) );
+ Q_SetExtension( fn, ".tga", sizeof( fn ) );
+ g_pMatSysWindow->TakeScreenShot( fn );
+ }
+ }
+ break;
+
+ case IDC_OPTIONS_DUMP:
+ g_pControlPanel->dumpModelInfo ();
+ break;
+
+#ifdef WIN32
+ case IDC_HELP_GOTOHOMEPAGE:
+ ShellExecute (0, "open", "http://developer.valvesoftware.com/wiki/Category:Choreography", 0, 0, SW_SHOW);
+ break;
+#endif
+
+ case IDC_HELP_ABOUT:
+ mxMessageBox (this,
+ "v1.0 Copyright � 1996-2007, Valve Corporation. All rights reserved.\r\nBuild Date: " __DATE__ "",
+ "Valve Face Poser",
+ MX_MB_OK | MX_MB_INFORMATION);
+ break;
+
+ case IDC_EXPRESSIONS_REDOBITMAPS:
+ {
+ CExpClass *active = expressions->GetActiveClass();
+ if ( active )
+ {
+ g_pProgressDialog->Start( "Rebuild Bitmaps", "", true );
+
+ g_pMatSysWindow->EnableStickySnapshotMode( );
+ for ( int i = 0; i < active->GetNumExpressions() ; i++ )
+ {
+ CExpression *exp = active->GetExpression( i );
+ if ( !exp )
+ continue;
+
+ g_pProgressDialog->UpdateText( exp->name );
+ g_pProgressDialog->Update( (float)i / (float)active->GetNumExpressions() );
+ if ( g_pProgressDialog->IsCancelled() )
+ {
+ Msg( "Cancelled\n" );
+ break;
+ }
+
+ exp->CreateNewBitmap( models->GetActiveModelIndex() );
+
+ if ( ! ( i % 5 ) )
+ {
+ g_pExpressionTrayTool->redraw();
+ }
+ }
+ g_pMatSysWindow->DisableStickySnapshotMode( );
+
+ g_pProgressDialog->Finish();
+
+ active->SelectExpression( 0 );
+ }
+ }
+ break;
+ case IDC_EXPRESSIONS_NEW:
+ {
+ char classfile[ 512 ];
+ if ( FacePoser_ShowSaveFileNameDialog( classfile, sizeof( classfile ), "expressions", "*.txt" ) )
+ {
+ Q_DefaultExtension( classfile, ".txt", sizeof( classfile ) );
+ expressions->CreateNewClass( classfile );
+ }
+ }
+ break;
+ case IDC_EXPRESSIONS_LOAD:
+ {
+ char classfile[ 512 ];
+ if ( FacePoser_ShowOpenFileNameDialog( classfile, sizeof( classfile ), "expressions", "*.txt" ) )
+ {
+ expressions->LoadClass( classfile );
+ }
+ }
+ break;
+
+ case IDC_EXPRESSIONS_SAVE:
+ {
+ CExpClass *active = expressions->GetActiveClass();
+ if ( active )
+ {
+ active->Save();
+ active->Export();
+ }
+ }
+ break;
+ case IDC_EXPRESSIONS_EXPORT:
+ {
+ CExpClass *active = expressions->GetActiveClass();
+ if ( active )
+ {
+ active->Export();
+ }
+ }
+ break;
+ case IDC_EXPRESSIONS_CLOSE:
+ g_pControlPanel->Close();
+ break;
+ case IDC_EXPRESSIONS_CLOSEALL:
+ g_pControlPanel->Closeall();
+ break;
+ case IDC_CHOREOSCENE_NEW:
+ g_pChoreoView->New();
+ break;
+ case IDC_CHOREOSCENE_LOAD:
+ g_pChoreoView->Load();
+ break;
+ case IDC_CHOREOSCENE_LOADNEXT:
+ g_pChoreoView->LoadNext();
+ break;
+ case IDC_CHOREOSCENE_SAVE:
+ g_pChoreoView->Save();
+ break;
+ case IDC_CHOREOSCENE_SAVEAS:
+ g_pChoreoView->SaveAs();
+ break;
+ case IDC_CHOREOSCENE_CLOSE:
+ g_pChoreoView->Close();
+ break;
+ case IDC_CHOREOSCENE_ADDACTOR:
+ g_pChoreoView->NewActor();
+ break;
+ case IDC_WINDOW_TILE:
+ {
+ OnTile();
+ }
+ break;
+ case IDC_WINDOW_TILE_HORIZ:
+ {
+ OnTileHorizontally();
+ }
+ break;
+ case IDC_WINDOW_TILE_VERT:
+ {
+ OnTileVertically();
+ }
+ break;
+ case IDC_WINDOW_CASCADE:
+ {
+ OnCascade();
+ }
+ break;
+ case IDC_WINDOW_HIDEALL:
+ {
+ OnHideAll();
+ }
+ break;
+ case IDC_WINDOW_SHOWALL:
+ {
+ OnShowAll();
+ }
+ break;
+ default:
+ {
+ iret = 0;
+ int tool_number = event->action - IDC_WINDOW_FIRSTTOOL;
+ int max_tools = IDC_WINDOW_LASTTOOL - IDC_WINDOW_FIRSTTOOL;
+
+ if ( tool_number >= 0 &&
+ tool_number <= max_tools &&
+ tool_number < IFacePoserToolWindow::GetToolCount() )
+ {
+ iret = 1;
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( tool_number );
+ if ( tool )
+ {
+ mxWindow *toolw = tool->GetMxWindow();
+
+ bool wasvisible = toolw->isVisible();
+ toolw->setVisible( !wasvisible );
+
+ g_MDLViewer->UpdateWindowMenu();
+
+ }
+ }
+
+ int lang_number = event->action - IDC_OPTIONS_LANGUAGESTART;
+ if ( lang_number >= 0 &&
+ lang_number < CC_NUM_LANGUAGES )
+ {
+ iret = 1;
+ SetCloseCaptionLanguageId( lang_number );
+ }
+ }
+ break;
+ } //switch (event->action)
+ } // mxEvent::Action
+ break;
+ case KeyDown:
+ {
+ //g_pMatSysWindow->handleEvent(event);
+ // Send it to the active tool
+ IFacePoserToolWindow *active = IFacePoserToolWindow::GetActiveTool();
+ if ( active )
+ {
+ mxWindow *w = active->GetMxWindow();
+ if ( w )
+ {
+ w->handleEvent( event );
+ }
+ }
+ else
+ {
+ g_pMatSysWindow->handleEvent(event);
+ }
+ iret = 1;
+ }
+ break;
+ case mxEvent::Activate:
+ {
+ if (event->action)
+ {
+ mx::setIdleWindow( g_pMatSysWindow );
+ // Force reload of localization data
+ SetCloseCaptionLanguageId( GetCloseCaptionLanguageId(), true );
+ }
+ else
+ {
+ mx::setIdleWindow( 0 );
+ }
+ iret = 1;
+ }
+ break;
+ } // event->event
+
+ return iret;
+}
+
+void MDLViewer::SaveWindowPositions( void )
+{
+ // Save the model viewer position
+ SavePosition();
+
+ int c = IFacePoserToolWindow::GetToolCount();
+ for ( int i = 0; i < c; i++ )
+ {
+ IFacePoserToolWindow *w = IFacePoserToolWindow::GetTool( i );
+ w->SavePosition();
+ }
+}
+
+void MDLViewer::LoadWindowPositions( void )
+{
+ // NOTE: Don't do this here, we do the mdlviewer position earlier in startup
+ // LoadPosition();
+
+ int w = this->w();
+ int h = this->h();
+
+ g_viewerSettings.width = w;
+ g_viewerSettings.height = h;
+
+ int c = IFacePoserToolWindow::GetToolCount();
+ for ( int i = 0; i < c; i++ )
+ {
+ IFacePoserToolWindow *w = IFacePoserToolWindow::GetTool( i );
+ w->LoadPosition();
+ }
+}
+
+void
+MDLViewer::redraw ()
+{
+}
+
+int MDLViewer::GetCurrentFrame( void )
+{
+ return m_nCurrentFrame;
+}
+
+void MDLViewer::Think( float dt )
+{
+ ++m_nCurrentFrame;
+
+ // Iterate across tools
+ IFacePoserToolWindow::ToolThink( dt );
+
+ sound->Update( dt );
+
+ bool soundscriptsdirty = AreSoundScriptsDirty();
+ if ( soundscriptsdirty != m_bOldSoundScriptsDirty )
+ {
+ // Update the menu item when this changes
+ menuFile->setEnabled(IDC_FILE_SAVESOUNDSCRIPTCHANGES, soundscriptsdirty );
+ }
+
+ m_bOldSoundScriptsDirty = soundscriptsdirty;
+}
+
+static int CountVisibleTools( void )
+{
+ int i;
+ int c = IFacePoserToolWindow::GetToolCount();
+ int viscount = 0;
+
+ for ( i = 0; i < c; i++ )
+ {
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
+ mxWindow *w = tool->GetMxWindow();
+ if ( !w->isVisible() )
+ continue;
+
+ viscount++;
+ }
+
+ return viscount;
+}
+
+void MDLViewer::OnCascade()
+{
+ int i;
+ int c = IFacePoserToolWindow::GetToolCount();
+ int viscount = CountVisibleTools();
+
+ int x = 0, y = 0;
+
+ int offset = 20;
+
+ int wide = workspace->w2() - viscount * offset;
+ int tall = ( workspace->h2() - viscount * offset ) / 2;
+
+ for ( i = 0; i < c; i++ )
+ {
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
+ mxWindow *w = tool->GetMxWindow();
+ if ( !w->isVisible() )
+ continue;
+
+ w->setBounds( x, y, wide, tall );
+ x += offset;
+ y += offset;
+ }
+}
+
+void MDLViewer::OnTile()
+{
+ int c = CountVisibleTools();
+
+ int rows = (int)sqrt( ( float )c );
+ rows = clamp( rows, 1, rows );
+
+ int cols = 1;
+ while ( rows * cols < c )
+ {
+ cols++;
+ }
+
+ DoTile( rows, cols );
+}
+
+void MDLViewer::OnTileHorizontally()
+{
+ int c = CountVisibleTools();
+
+ DoTile( c, 1 );
+}
+
+void MDLViewer::OnTileVertically()
+{
+ int c = CountVisibleTools();
+
+ DoTile( 1, c );
+}
+
+void MDLViewer::OnHideAll()
+{
+ int c = IFacePoserToolWindow::GetToolCount();
+ for ( int i = 0; i < c; i++ )
+ {
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
+ mxWindow *w = tool->GetMxWindow();
+
+ w->setVisible( false );
+ }
+
+ UpdateWindowMenu();
+}
+
+void MDLViewer::OnShowAll()
+{
+ int c = IFacePoserToolWindow::GetToolCount();
+ for ( int i = 0; i < c; i++ )
+ {
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( i );
+ mxWindow *w = tool->GetMxWindow();
+
+ w->setVisible( true );
+ }
+
+ UpdateWindowMenu();
+}
+
+void MDLViewer::DoTile( int x, int y )
+{
+ int c = IFacePoserToolWindow::GetToolCount();
+
+ if ( x < 1 )
+ x = 1;
+ if ( y < 1 )
+ y = 1;
+
+ int wide = workspace->w2() / y;
+ int tall = workspace->h2() / x;
+
+ int obj = 0;
+
+ for ( int row = 0 ; row < x ; row++ )
+ {
+ for ( int col = 0; col < y; col++ )
+ {
+ bool found = false;
+ while ( 1 )
+ {
+ if ( obj >= c )
+ break;
+
+ IFacePoserToolWindow *tool = IFacePoserToolWindow::GetTool( obj++ );
+ mxWindow *w = tool->GetMxWindow();
+ if ( w->isVisible() )
+ {
+ w->setBounds( col * wide, row * tall, wide, tall );
+
+ found = true;
+ break;
+ }
+ }
+
+ if ( !found )
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Not used by faceposer
+// Output : int
+//-----------------------------------------------------------------------------
+int MDLViewer::GetCurrentHitboxSet(void)
+{
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool MDLViewer::PaintBackground( void )
+{
+ CChoreoWidgetDrawHelper drawHelper( this );
+
+ RECT rc;
+ drawHelper.GetClientRect( rc );
+
+ drawHelper.DrawFilledRect( COLOR_CHOREO_BACKGROUND, rc );
+ return false;
+}
+
+void MDLViewer::OnRebuildScenesImage()
+{
+ g_pProgressDialog->Start( "Rebuilding scenes.image", "", false );
+
+ CUtlBuffer targetBuffer;
+
+ bool bLittleEndian = true;
+
+ const char *pFilename = bLittleEndian ? "scenes/scenes.image" : "scenes/scenes.360.image";
+
+ CP4AutoEditAddFile checkout( CFmtStr( "%s%s", gamedir, pFilename ) );
+
+ bool bSuccess = g_pSceneImage->CreateSceneImageFile( targetBuffer, gamedir, bLittleEndian, false, this );
+ if ( bSuccess )
+ {
+ scriptlib->WriteBufferToFile( pFilename, targetBuffer, WRITE_TO_DISK_ALWAYS );
+ }
+
+ g_pProgressDialog->Finish();
+ m_bVCDSaved = false;
+}
+
+void MDLViewer::UpdateStatus( char const *pchSceneName, bool bQuiet, int nIndex, int nCount )
+{
+ g_pProgressDialog->UpdateText( pchSceneName );
+ g_pProgressDialog->Update( (float)nIndex / (float)nCount );
+}
+
+void MDLViewer::OnVCDSaved()
+{
+ m_bVCDSaved = true;
+}
+
+SpewRetval_t HLFacePoserSpewFunc( SpewType_t spewType, char const *pMsg )
+{
+ g_bInError = true;
+
+ switch (spewType)
+ {
+ case SPEW_ERROR:
+ ::MessageBox(NULL, pMsg, "FATAL ERROR", MB_OK);
+ g_bInError = false;
+ return SPEW_ABORT;
+
+ case SPEW_LOG:
+ g_bInError = false;
+ return SPEW_CONTINUE;
+
+ case SPEW_WARNING:
+ Con_ErrorPrintf( pMsg );
+ g_bInError = false;
+ return SPEW_CONTINUE;
+
+ default:
+ Con_Printf(pMsg);
+ g_bInError = false;
+#ifdef _DEBUG
+ return spewType == SPEW_ASSERT ? SPEW_DEBUGGER : SPEW_CONTINUE;
+#else
+ return SPEW_CONTINUE;
+#endif
+ }
+}
+
+void MDLViewer::OnSaveSoundScriptChanges()
+{
+ if ( !AreSoundScriptsDirty() )
+ {
+ return;
+ }
+
+// Save any changed sound script files
+ int c = soundemitter->GetNumSoundScripts();
+ for ( int i = 0; i < c; i++ )
+ {
+ if ( !soundemitter->IsSoundScriptDirty( i ) )
+ continue;
+
+ char const *scriptname = soundemitter->GetSoundScriptName( i );
+ if ( !scriptname )
+ continue;
+
+ if ( !filesystem->FileExists( scriptname ) )
+ {
+ continue;
+ }
+
+ if ( !filesystem->IsFileWritable( scriptname ) )
+ {
+ mxMessageBox( NULL, va( "Can't save changes to sound script '%s', file is READ-ONLY?", scriptname ), g_appTitle, MX_MB_OK );
+ continue;
+ }
+
+ int retval = mxMessageBox( NULL, va( "Save changes to sound script '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval == 2 )
+ {
+ return;
+ }
+
+ if ( retval == 0 )
+ {
+ soundemitter->SaveChangesToSoundScript( i );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// The application object
+//-----------------------------------------------------------------------------
+class CHLFacePoserApp : public CTier3SteamApp
+{
+ typedef CTier3SteamApp BaseClass;
+
+public:
+ // Methods of IApplication
+ virtual bool Create();
+ virtual bool PreInit();
+ virtual int Main();
+ virtual void PostShutdown();
+ virtual void Destroy();
+
+private:
+ // Sets up the search paths
+ bool SetupSearchPaths();
+};
+
+
+//-----------------------------------------------------------------------------
+// Create all singleton systems
+//-----------------------------------------------------------------------------
+bool CHLFacePoserApp::Create()
+{
+ // Save some memory so engine/hammer isn't so painful
+ CommandLine()->AppendParm( "-disallowhwmorph", NULL );
+
+ SpewOutputFunc( HLFacePoserSpewFunc );
+
+ AppSystemInfo_t appSystems[] =
+ {
+ { "inputsystem.dll", INPUTSYSTEM_INTERFACE_VERSION },
+ { "materialsystem.dll", MATERIAL_SYSTEM_INTERFACE_VERSION },
+ { "studiorender.dll", STUDIO_RENDER_INTERFACE_VERSION },
+ { "vphysics.dll", VPHYSICS_INTERFACE_VERSION },
+ { "datacache.dll", DATACACHE_INTERFACE_VERSION },
+ { "datacache.dll", MDLCACHE_INTERFACE_VERSION },
+ { "datacache.dll", STUDIO_DATA_CACHE_INTERFACE_VERSION },
+ { "vguimatsurface.dll", VGUI_SURFACE_INTERFACE_VERSION },
+ { "vgui2.dll", VGUI_IVGUI_INTERFACE_VERSION },
+ { "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
+ { "", "" } // Required to terminate the list
+ };
+
+ if ( !AddSystems( appSystems ) )
+ return false;
+
+ // Add the P4 module separately so that if it is absent (say in the SDK) then the other system will initialize properly
+ AppModule_t p4Module = LoadModule( "p4lib.dll" );
+ if ( p4Module != APP_MODULE_INVALID )
+ {
+ AddSystem( p4Module, P4_INTERFACE_VERSION );
+ }
+
+ g_Factory = GetFactory();
+
+ IMaterialSystem* pMaterialSystem = (IMaterialSystem*)FindSystem( MATERIAL_SYSTEM_INTERFACE_VERSION );
+ if ( !pMaterialSystem )
+ {
+ Warning( "Material System interface could not be found!\n" );
+ return false;
+ }
+
+ const char *pShaderDLL = CommandLine()->ParmValue("-shaderdll");
+ if(!pShaderDLL)
+ {
+ pShaderDLL = "shaderapidx9.dll";
+ }
+ pMaterialSystem->SetShaderAPI( pShaderDLL );
+
+ return true;
+}
+
+
+void CHLFacePoserApp::Destroy()
+{
+}
+
+
+const char *GetGameDirectory()
+{
+ // TODO: get rid of this and ONLY use the filesystem, so hlfaceposer works nicely for
+ // mods that get the base game resources from the Steam filesystem.
+ return gamedir;
+}
+
+char const *GetGameDirectorySimple()
+{
+ return gamedirsimple;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the game path
+//-----------------------------------------------------------------------------
+bool CHLFacePoserApp::SetupSearchPaths()
+{
+ // Add paths...
+ if ( !BaseClass::SetupSearchPaths( NULL, false, true ) )
+ return false;
+
+ // Set gamedir.
+ Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), GetGameInfoPath() );
+
+ Q_FileBase( gamedir, gamedirsimple, sizeof( gamedirsimple ) );
+
+ Q_AppendSlash( gamedir, sizeof( gamedir ) );
+
+ workspacefiles->Init( GetGameDirectorySimple() );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CHLFacePoserApp::PreInit( )
+{
+ if ( !BaseClass::PreInit() )
+ return false;
+
+ g_pFileSystem = filesystem = g_pFullFileSystem;
+ g_pStudioDataCache = (IStudioDataCache*)FindSystem( STUDIO_DATA_CACHE_INTERFACE_VERSION );
+ physcollision = (IPhysicsCollision *)FindSystem( VPHYSICS_COLLISION_INTERFACE_VERSION );
+ physprop = (IPhysicsSurfaceProps *)FindSystem( VPHYSICS_SURFACEPROPS_INTERFACE_VERSION );
+ g_pLocalize = (vgui::ILocalize *)FindSystem(VGUI_LOCALIZE_INTERFACE_VERSION );
+ soundemitter = (ISoundEmitterSystemBase*)FindSystem(SOUNDEMITTERSYSTEM_INTERFACE_VERSION);
+
+ if ( !soundemitter || !g_pLocalize || !filesystem || !physprop || !physcollision ||
+ !g_pMaterialSystem || !g_pStudioRender || !g_pMDLCache || !g_pDataCache )
+ {
+ Error("Unable to load required library interface!\n");
+ }
+
+ MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
+ filesystem->SetWarningFunc( Warning );
+
+ // Add paths...
+ if ( !SetupSearchPaths() )
+ return false;
+
+ // Get the adapter from the command line....
+ const char *pAdapterString;
+ int nAdapter = 0;
+ if (CommandLine()->CheckParm( "-adapter", &pAdapterString ))
+ {
+ nAdapter = atoi( pAdapterString );
+ }
+
+ int adapterFlags = MATERIAL_INIT_ALLOCATE_FULLSCREEN_TEXTURE;
+ if ( CommandLine()->CheckParm( "-ref" ) )
+ {
+ adapterFlags |= MATERIAL_INIT_REFERENCE_RASTERIZER;
+ }
+
+ g_pMaterialSystem->SetAdapter( nAdapter, adapterFlags );
+
+ LoadFileSystemDialogModule();
+
+ return true;
+}
+
+void CHLFacePoserApp::PostShutdown()
+{
+ UnloadFileSystemDialogModule();
+
+ g_pFileSystem = filesystem = NULL;
+ g_pStudioDataCache = NULL;
+ physcollision = NULL;
+ physprop = NULL;
+
+ BaseClass::PostShutdown();
+
+ g_Factory = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// main application
+//-----------------------------------------------------------------------------
+int CHLFacePoserApp::Main()
+{
+ // Do Perforce Stuff
+ g_p4factory->SetDummyMode( false );
+ if ( CommandLine()->FindParm( "-nop4" ) || !p4 )
+ {
+ g_p4factory->SetDummyMode( true );
+ }
+
+ g_p4factory->SetOpenFileChangeList( "FacePoser Auto Checkout" );
+
+ soundemitter->ModInit();
+ g_pMaterialSystem->ModInit();
+
+ g_pDataCache->SetSize( 64 * 1024 * 1024 );
+
+ // Always start with english
+ g_pLocalize->AddFile( "resource/closecaption_english.txt", "GAME", true );
+
+ sound->Init();
+
+ IFacePoserToolWindow::EnableToolRedraw( false );
+
+ g_MDLViewer = new MDLViewer ();
+ g_MDLViewer->setMenuBar (g_MDLViewer->getMenuBar ());
+
+ FaceposerVGui()->Init( (HWND)g_MDLViewer->getHandle() );
+
+ // Force reload of close captioning data file!!!
+ SetCloseCaptionLanguageId( g_viewerSettings.cclanguageid, true );
+
+ g_pStudioModel->Init();
+
+ int i;
+ bool modelloaded = false;
+ for ( i = 1; i < CommandLine()->ParmCount(); i++ )
+ {
+ if ( Q_stristr (CommandLine()->GetParm( i ), ".mdl") )
+ {
+ modelloaded = true;
+ g_MDLViewer->LoadModelFile( CommandLine()->GetParm( i ) );
+ break;
+ }
+ }
+
+ models->LoadModelList();
+ g_pPhonemeEditor->ValidateSpeechAPIIndex();
+
+ if ( models->Count() == 0 )
+ {
+ g_pFlexPanel->initFlexes( );
+ }
+
+ // Load expressions from last time
+ int files = workspacefiles->GetNumStoredFiles( IWorkspaceFiles::EXPRESSION );
+ for ( i = 0; i < files; i++ )
+ {
+ expressions->LoadClass( workspacefiles->GetStoredFile( IWorkspaceFiles::EXPRESSION, i ) );
+ }
+
+ IFacePoserToolWindow::EnableToolRedraw( true );
+
+ int nRetVal = mx::run ();
+
+ if (g_pStudioModel)
+ {
+ g_pStudioModel->Shutdown();
+ g_pStudioModel = NULL;
+ }
+
+ g_pMaterialSystem->ModShutdown();
+ soundemitter->ModShutdown();
+ g_pMaterialSystem->ModShutdown();
+
+ FaceposerVGui()->Shutdown();
+
+ return nRetVal;
+}
+
+static bool CHLFacePoserApp_SuggestGameInfoDirFn( CFSSteamSetupInfo const *pFsSteamSetupInfo, char *pchPathBuffer, int nBufferLength, bool *pbBubbleDirectories )
+{
+ if ( pbBubbleDirectories )
+ *pbBubbleDirectories = true;
+
+ for ( int i = 1; i < CommandLine()->ParmCount(); i++ )
+ {
+ if ( Q_stristr( CommandLine()->GetParm( i ), ".mdl" ) )
+ {
+ Q_MakeAbsolutePath( pchPathBuffer, nBufferLength, CommandLine()->GetParm( i ) );
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int main (int argc, char *argv[])
+{
+ CommandLine()->CreateCmdLine( argc, argv );
+ CoInitialize(NULL);
+
+ // make sure, we start in the right directory
+ char szName[256];
+ strcpy (szName, mx::getApplicationPath() );
+ mx::init (argc, argv);
+
+ char workingdir[ 256 ];
+ workingdir[0] = 0;
+ Q_getwd( workingdir, sizeof( workingdir ) );
+
+ // Set game info directory suggestion callback
+ SetSuggestGameInfoDirFn( CHLFacePoserApp_SuggestGameInfoDirFn );
+
+ CHLFacePoserApp hlFacePoserApp;
+ CSteamApplication steamApplication( &hlFacePoserApp );
+ int nRetVal = steamApplication.Run();
+
+ CoUninitialize();
+
+ return nRetVal;
+}
+