diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/hlfaceposer/mdlviewer.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'utils/hlfaceposer/mdlviewer.cpp')
| -rw-r--r-- | utils/hlfaceposer/mdlviewer.cpp | 2752 |
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( ¶ms, 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( ¶ms ) ) + { + 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( ¶ms ) && + 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; +} + |