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

2752 lines
64 KiB

//========= 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;
}