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/faceposer_models.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'utils/hlfaceposer/faceposer_models.cpp')
| -rw-r--r-- | utils/hlfaceposer/faceposer_models.cpp | 1142 |
1 files changed, 1142 insertions, 0 deletions
diff --git a/utils/hlfaceposer/faceposer_models.cpp b/utils/hlfaceposer/faceposer_models.cpp new file mode 100644 index 0000000..49ec500 --- /dev/null +++ b/utils/hlfaceposer/faceposer_models.cpp @@ -0,0 +1,1142 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "hlfaceposer.h" +#include "StudioModel.h" +#include "faceposer_models.h" +#include "filesystem.h" +#include "ifaceposerworkspace.h" +#include <mxtk/mx.h> +#include "mdlviewer.h" +#include "mxexpressiontray.h" +#include "ControlPanel.h" +#include "checksum_crc.h" +#include "ViewerSettings.h" +#include "matsyswin.h" +#include "KeyValues.h" +#include "utlbuffer.h" +#include "expression.h" +#include "ProgressDialog.h" +#include "tier1/UtlString.h" +#include "tier1/FmtStr.h" +#include "tier1/KeyValues.h" + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +void SetupModelFlexcontrollerLinks( StudioModel *model ); + +IFaceposerModels::CFacePoserModel::CFacePoserModel( char const *modelfile, StudioModel *model ) +{ + m_pModel = model; + m_szActorName[ 0 ] = 0; + m_szShortName[ 0 ] = 0; + strcpy( m_szModelFileName, modelfile ); + Q_FixSlashes( m_szModelFileName ); + + CStudioHdr *hdr = model->GetStudioHdr(); + if ( hdr ) + { + Q_StripExtension( hdr->pszName(), m_szShortName, sizeof( m_szShortName ) ); + } + + m_bVisibileIn3DView = false; + m_bFirstBitmapLoad = true; + + LoadBitmaps(); +} + +IFaceposerModels::CFacePoserModel::~CFacePoserModel() +{ + FreeBitmaps(); +} + +void IFaceposerModels::CFacePoserModel::LoadBitmaps() +{ + CStudioHdr *hdr = m_pModel ? m_pModel->GetStudioHdr() : NULL; + if ( hdr ) + { + for ( int i = 0 ;i < hdr->GetNumSeq(); i++ ) + { + mxbitmapdata_t *bm = new mxbitmapdata_t(); + + AnimBitmap *entry = new AnimBitmap(); + entry->needsload = true; + entry->bitmap = bm; + + // Need to load bitmap from disk image via crc, etc. + //Assert( 0 ); + + m_AnimationBitmaps.AddToTail( entry ); + } + } +} + +CRC32_t IFaceposerModels::CFacePoserModel::GetBitmapCRC( int sequence ) +{ + CStudioHdr *hdr = m_pModel ? m_pModel->GetStudioHdr() : NULL; + if ( !hdr ) + return (CRC32_t)-1; + + if ( sequence < 0 || sequence >= hdr->GetNumSeq() ) + return (CRC32_t)-1; + + mstudioseqdesc_t &seqdesc = hdr->pSeqdesc( sequence ); + + CRC32_t crc; + CRC32_Init( &crc ); + + // For sequences, we'll checsum a bit of data + + CRC32_ProcessBuffer( &crc, (void *)seqdesc.pszLabel(), Q_strlen( seqdesc.pszLabel() ) ); + CRC32_ProcessBuffer( &crc, (void *)seqdesc.pszActivityName(), Q_strlen( seqdesc.pszActivityName() ) ); + CRC32_ProcessBuffer( &crc, (void *)&seqdesc.flags, sizeof( seqdesc.flags ) ); + //CRC32_ProcessBuffer( &crc, (void *)&seqdesc.numevents, sizeof( seqdesc.numevents ) ); + CRC32_ProcessBuffer( &crc, (void *)&seqdesc.numblends, sizeof( seqdesc.numblends ) ); + CRC32_ProcessBuffer( &crc, (void *)seqdesc.groupsize, sizeof( seqdesc.groupsize ) ); + + KeyValues *seqKeyValues = new KeyValues(""); + if ( seqKeyValues->LoadFromBuffer( m_pModel->GetFileName( ), m_pModel->GetKeyValueText( sequence ) ) ) + { + // Yuck, but I need it in a contiguous block of memory... oh well... + CUtlBuffer buf; + seqKeyValues->RecursiveSaveToFile( buf, 0 ); + CRC32_ProcessBuffer( &crc, ( void * )buf.Base(), buf.TellPut() ); + } + + seqKeyValues->deleteThis(); + + CRC32_Final( &crc ); + + return crc; +} + +const char *IFaceposerModels::CFacePoserModel::GetBitmapChecksum( int sequence ) +{ + CRC32_t crc = GetBitmapCRC( sequence ); + + // Create string name out of binary data + static char filename[ 512 ]; + + char hex[ 16 ]; + Q_binarytohex( (byte *)&crc, sizeof( crc ), hex, sizeof( hex ) ); + + Q_snprintf( filename, sizeof( filename ), "%s", hex ); + return filename; +} + +const char *IFaceposerModels::CFacePoserModel::GetBitmapFilename( int sequence ) +{ + char *in, *out; + static char filename[ 256 ]; + filename[ 0 ] = 0; + + char modelName[512], modelNameTemp[512]; + Q_strncpy( modelNameTemp, GetShortModelName(), sizeof( modelNameTemp ) ); + + in = modelNameTemp; + out = modelName; + + while ( *in ) + { + if ( V_isalnum( *in ) || + *in == '_' || + *in == '\\' || + *in == '/' || + *in == '.' || + *in == ':' ) + { + *out++ = *in; + } + in++; + } + *out = 0; + + + Q_snprintf( filename, sizeof( filename ), "expressions/%s/animation/%s.bmp", modelName, GetBitmapChecksum( sequence ) ); + + Q_FixSlashes( filename ); + strlwr( filename ); + + CreatePath( filename ); + + return filename; +} + +void IFaceposerModels::CFacePoserModel::FreeBitmaps() +{ + while ( m_AnimationBitmaps.Count() > 0 ) + { + AnimBitmap *bm = m_AnimationBitmaps[ 0 ]; + delete bm->bitmap; + delete bm; + m_AnimationBitmaps.Remove( 0 ); + } +} + +void IFaceposerModels::CFacePoserModel::LoadBitmapForSequence( mxbitmapdata_t *bitmap, int sequence ) +{ + // See if it exists + char filename[ 512 ]; + Q_strncpy( filename, GetBitmapFilename( sequence ), sizeof( filename ) ); + + if ( !LoadBitmapFromFile( filename, *bitmap ) ) + { + CreateNewBitmap( filename, sequence, 256, false, NULL, bitmap ); + } +} + +static float FindPoseCycle( StudioModel *model, int sequence ) +{ + float cycle = 0.0f; + if ( !model->GetStudioHdr() ) + return cycle; + + KeyValues *seqKeyValues = new KeyValues(""); + if ( seqKeyValues->LoadFromBuffer( model->GetFileName( ), model->GetKeyValueText( sequence ) ) ) + { + // Do we have a build point section? + KeyValues *pkvAllFaceposer = seqKeyValues->FindKey("faceposer"); + if ( pkvAllFaceposer ) + { + int thumbnail_frame = pkvAllFaceposer->GetInt( "thumbnail_frame", 0 ); + if ( thumbnail_frame ) + { + // Convert frame to cycle if we have valid data + int maxFrame = model->GetNumFrames( sequence ) - 1; + + if ( maxFrame > 0 ) + { + cycle = thumbnail_frame / (float)maxFrame; + } + } + } + } + + seqKeyValues->deleteThis(); + + return cycle; +} + + +void EnableStickySnapshotMode( void ) +{ + g_pMatSysWindow->EnableStickySnapshotMode( ); +} + +void DisableStickySnapshotMode( void ) +{ + g_pMatSysWindow->DisableStickySnapshotMode( ); +} + + +void IFaceposerModels::CreateNewBitmap( int modelindex, char const *pchBitmapFilename, int sequence, int nSnapShotSize, bool bZoomInOnFace, CExpression *pExpression, mxbitmapdata_t *bitmap ) +{ + CFacePoserModel *m = m_Models[ modelindex ]; + if ( m ) + { + m->CreateNewBitmap( pchBitmapFilename, sequence, nSnapShotSize, bZoomInOnFace, pExpression, bitmap ); + } +} + +void IFaceposerModels::CFacePoserModel::CreateNewBitmap( char const *pchBitmapFilename, int sequence, int nSnapShotSize, bool bZoomInOnFace, CExpression *pExpression, mxbitmapdata_t *bitmap ) +{ + MatSysWindow *pWnd = g_pMatSysWindow; + if ( !pWnd ) + return; + + StudioModel *model = m_pModel; + if ( !model ) + return; + + CStudioHdr *hdr = model->GetStudioHdr(); + if ( !hdr ) + return; + if ( sequence < 0 || sequence >= hdr->GetNumSeq() ) + return; + + mstudioseqdesc_t &seqdesc = hdr->pSeqdesc( sequence ); + + Con_ColorPrintf( FILE_COLOR, "Creating bitmap %s for sequence '%s'\n", pchBitmapFilename, seqdesc.pszLabel() ); + + model->ClearOverlaysSequences(); + int iLayer = model->GetNewAnimationLayer(); + model->SetOverlaySequence( iLayer, sequence, 1.0 ); + model->SetOverlayRate( iLayer, FindPoseCycle( model, sequence ), 0.0 ); + + for (int i = 0; i < hdr->GetNumPoseParameters(); i++) + { + model->SetPoseParameter( i, 0.0 ); + } + + float flexValues[ GLOBAL_STUDIO_FLEX_CONTROL_COUNT ] = { 0 }; + + if ( pExpression ) + { + float *settings = pExpression->GetSettings(); + float *weights = pExpression->GetWeights(); + + // Save existing settings from model + for ( LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); ++i ) + { + int j = hdr->pFlexcontroller( i )->localToGlobal; + if ( j == -1 ) + continue; + flexValues[ i ] = model->GetFlexController( i ); + // Set Value from passed in settings + model->SetFlexController( i, settings[ j ] * weights[ j ] ); + } + } + + model->ClearLookTargets( ); + + QAngle oldrot, oldLight; + Vector oldtrans; + + VectorCopy( model->m_angles, oldrot ); + VectorCopy( model->m_origin, oldtrans ); + VectorCopy( g_viewerSettings.lightrot, oldLight ); + + model->m_angles.Init(); + model->m_origin.Init(); + g_viewerSettings.lightrot.Init(); + + g_viewerSettings.lightrot.y = -180; + + bool bSaveGround = g_viewerSettings.showGround; + g_viewerSettings.showGround = false; + + if ( bZoomInOnFace ) + { + Vector size; + VectorSubtract( hdr->hull_max(), hdr->hull_min(), size ); + + float eyeheight = hdr->hull_min().z + 0.9 * size.z; + // float width = ( size.x + size.y ) / 2.0f; + + model->m_origin.x = size.z * .6f; + + if ( hdr->GetNumAttachments() > 0 ) + { + for (int i = 0; i < hdr->GetNumAttachments(); i++) + { + const mstudioattachment_t &attachment = hdr->pAttachment( i ); + int iBone = hdr->GetAttachmentBone( i ); + + if ( Q_stricmp( attachment.pszName(), "eyes" ) ) + continue; + + mstudiobone_t *bone = hdr->pBone( iBone ); + if ( !bone ) + continue; + + matrix3x4_t boneToPose; + MatrixInvert( bone->poseToBone, boneToPose ); + + matrix3x4_t attachmentPoseToLocal; + ConcatTransforms( boneToPose, attachment.local, attachmentPoseToLocal ); + + Vector localSpaceEyePosition; + VectorITransform( vec3_origin, attachmentPoseToLocal, localSpaceEyePosition ); + + // Not sure why this must be negative? + eyeheight = -localSpaceEyePosition.z + hdr->hull_min().z; + break; + } + } + + KeyValues *seqKeyValues = new KeyValues(""); + if ( seqKeyValues->LoadFromBuffer( model->GetFileName( ), model->GetKeyValueText( sequence ) ) ) + { + // Do we have a build point section? + KeyValues *pkvAllFaceposer = seqKeyValues->FindKey("faceposer"); + if ( pkvAllFaceposer ) + { + float flEyeheight = pkvAllFaceposer->GetFloat( "eye_height", -9999.0f ); + if ( flEyeheight != -9999.0f ) + { + eyeheight = flEyeheight; + } + } + } + + model->m_origin.z += eyeheight; + } + else + { + Vector mins, maxs; + model->ExtractBbox(mins, maxs); + Vector size; + VectorSubtract( maxs, mins, size ); + + float maxdim = size.x; + if ( size.y > maxdim ) + maxdim = size.y; + if ( size.z > maxdim ) + maxdim = size.z; + + float midpoint = mins.z + 0.5 * size.z; + + model->m_origin.x = 3 * maxdim; + model->m_origin.z += midpoint; + } + + g_pMatSysWindow->PushSnapshotMode( nSnapShotSize ); + + // Snapshots are taken of the back buffer; + // we need to render to the back buffer but not move it to the front + pWnd->SuppressBufferSwap( true ); + pWnd->redraw(); + pWnd->SuppressBufferSwap( false ); + + // make it square, assumes w > h + char fullpath[ 512 ]; + Q_snprintf( fullpath, sizeof( fullpath ), "%s%s", GetGameDirectory(), pchBitmapFilename ); + pWnd->TakeSnapshotRect( fullpath, 0, 0, nSnapShotSize, nSnapShotSize ); + + g_pMatSysWindow->PopSnapshotMode( ); + + VectorCopy( oldrot, model->m_angles ); + VectorCopy( oldtrans, model->m_origin ); + VectorCopy( oldLight, g_viewerSettings.lightrot ); + + g_viewerSettings.showGround = bSaveGround; + + if ( pExpression ) + { + // Save existing settings from model + for ( LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); ++i ) + { + int j = hdr->pFlexcontroller( i )->localToGlobal; + if ( j == -1 ) + continue; + + model->SetFlexController( i, flexValues[ i ] ); + } + } + + model->ClearOverlaysSequences(); + + if ( bitmap->valid ) + { + DeleteObject( bitmap->image ); + bitmap->image = 0; + bitmap->valid = false; + } + + LoadBitmapFromFile( pchBitmapFilename, *bitmap ); +} + +mxbitmapdata_t *IFaceposerModels::CFacePoserModel::GetBitmapForSequence( int sequence ) +{ + static mxbitmapdata_t nullbitmap; + if ( sequence < 0 || sequence >= m_AnimationBitmaps.Count() ) + return &nullbitmap; + + /* + if ( m_bFirstBitmapLoad ) + { + m_bFirstBitmapLoad = false; + ReconcileAnimationBitmaps(); + } + */ + + AnimBitmap *slot = m_AnimationBitmaps[ sequence ]; + if ( slot->needsload ) + { + slot->needsload = false; + LoadBitmapForSequence( slot->bitmap, sequence ); + } + + return m_AnimationBitmaps[ sequence ]->bitmap; +} + +void IFaceposerModels::CFacePoserModel::BuildValidChecksums( CUtlRBTree< CRC32_t > &tree ) +{ + StudioModel *model = m_pModel; + if ( !model ) + return; + + CStudioHdr *hdr = model->GetStudioHdr(); + if ( !hdr ) + return; + + for ( int i = 0; i < hdr->GetNumSeq(); i++ ) + { + CRC32_t crc = GetBitmapCRC( i ); + tree.Insert( crc ); + } +} + +void IFaceposerModels::CFacePoserModel::ReconcileAnimationBitmaps() +{ + // iterate files in directory and see if each checksum is valid and if not delete the .bmp + char path[ 512 ]; + Q_snprintf( path, sizeof( path ), "expressions/%s/animation/*.bmp", GetShortModelName() ); + + FileFindHandle_t hFindFile; + + char const *fn = filesystem->FindFirstEx( path, "MOD", &hFindFile ); + + g_pProgressDialog->Start( CFmtStr( "%s - Reconcile Animation Thumbnails", GetShortModelName() ), "", true ); + + CUtlVector< CUtlString > workList; + + if ( fn ) + { + while ( fn ) + { + // Don't do anything with directories + if ( !filesystem->FindIsDirectory( hFindFile ) ) + { + CUtlString s = fn; + workList.AddToTail( s ); + } + + fn = filesystem->FindNext( hFindFile ); + } + + filesystem->FindClose( hFindFile ); + } + + CUtlRBTree< CRC32_t > tree( 0, 0, DefLessFunc( CRC32_t ) ); + BuildValidChecksums( tree ); + + for ( int i = 0 ; i < workList.Count(); ++i ) + { + char testname[ 256 ]; + Q_StripExtension( workList[ i ].String(), testname, sizeof( testname ) ); + + g_pProgressDialog->UpdateText( "%s", testname ); + g_pProgressDialog->Update( (float)i / (float)workList.Count() ); + + CRC32_t check; + Q_hextobinary( testname, Q_strlen( testname ), (byte *)&check, sizeof( check ) ); + + if ( tree.Find( check ) == tree.InvalidIndex() ) + { + Q_snprintf( testname, sizeof( testname ), "expressions/%s/animation/%s", GetShortModelName(), fn ); + + char fullpath[ 512 ]; + filesystem->RelativePathToFullPath( testname, "MOD", fullpath, sizeof( fullpath ) ); + // Delete it + Con_ErrorPrintf( "Removing unused bitmap file %s\n", + fullpath ); + + _unlink( fullpath ); + } + + if ( g_pProgressDialog->IsCancelled() ) + { + Msg( "Cancelled\n" ); + break; + } + } + + g_pProgressDialog->Finish(); +} + +void IFaceposerModels::CFacePoserModel::RecreateAllAnimationBitmaps() +{ + StudioModel *model = m_pModel; + if ( !model ) + return; + + CStudioHdr *hdr = model->GetStudioHdr(); + if ( !hdr ) + return; + + g_pProgressDialog->Start( CFmtStr( "%s - Animation Thumbnails", GetShortModelName() ), "", true ); + + for ( int i = 0; i < hdr->GetNumSeq(); ++i ) + { + const mstudioseqdesc_t &seq = hdr->pSeqdesc( i ); + + g_pProgressDialog->UpdateText( "%s", seq.pszLabel() ); + g_pProgressDialog->Update( (float)i / (float)hdr->GetNumSeq() ); + + RecreateAnimationBitmap( i, false ); + + if ( g_pProgressDialog->IsCancelled() ) + { + Msg( "Cancelling\n" ); + break; + } + } + + g_pProgressDialog->Finish(); + + ReconcileAnimationBitmaps(); +} + +void IFaceposerModels::CFacePoserModel::RecreateAnimationBitmap( int sequence, bool reconcile ) +{ + if ( sequence < 0 || sequence >= m_AnimationBitmaps.Count() ) + { + Assert( 0 ); + return; + } + AnimBitmap *slot = m_AnimationBitmaps[ sequence ]; + slot->needsload = true; + if ( slot->bitmap->valid ) + { + DeleteObject( slot->bitmap->image ); + slot->bitmap->image = 0; + slot->bitmap->valid = false; + } + + char filename[ 512 ]; + Q_snprintf( filename, sizeof( filename ), "%s", GetBitmapFilename( sequence ) ); + + if ( filesystem->FileExists( filename ) ) + { + char fullpath[ 512 ]; + filesystem->RelativePathToFullPath( filename, "MOD", fullpath, sizeof( fullpath ) ); + _unlink( fullpath ); + } + + // Force recreation + GetBitmapForSequence( sequence ); + + if ( reconcile ) + { + ReconcileAnimationBitmaps( ); + } +} + +void IFaceposerModels::CFacePoserModel::Release( void ) +{ + m_pModel->FreeModel( true ); +} + +void IFaceposerModels::CFacePoserModel::Restore( void ) +{ + StudioModel *save = g_pStudioModel; + + g_pStudioModel = m_pModel; + + if (m_pModel->LoadModel( m_pModel->GetFileName() ) ) + { + m_pModel->PostLoadModel( m_pModel->GetFileName() ); + m_pModel->SetSequence( m_pModel->LookupSequence( "idle_subtle" ) ); + } + + g_pStudioModel = save; + + SetupModelFlexcontrollerLinks( m_pModel ); +} + + +IFaceposerModels::IFaceposerModels() +{ + m_nLastRenderFrame = -1; + m_nForceModelIndex = -1; +} + +IFaceposerModels::~IFaceposerModels() +{ + while ( m_Models.Count() > 0 ) + { + delete m_Models[ 0 ]; + m_Models.Remove( 0 ); + } +} + +IFaceposerModels::CFacePoserModel *IFaceposerModels::GetEntry( int index ) +{ + if ( index < 0 || index >= Count() ) + return NULL; + + CFacePoserModel *m = m_Models[ index ]; + if ( !m ) + return NULL; + return m; +} + +int IFaceposerModels::Count( void ) const +{ + return m_Models.Count(); +} + +char const *IFaceposerModels::GetModelName( int index ) +{ + CFacePoserModel *entry = GetEntry( index ); + if ( !entry ) + return ""; + + return entry->GetShortModelName(); +} + +char const *IFaceposerModels::GetModelFileName( int index ) +{ + CFacePoserModel *entry = GetEntry( index ); + if ( !entry ) + return ""; + + return entry->GetModelFileName(); +} + +void IFaceposerModels::ForceActiveModelIndex( int index ) +{ + m_nForceModelIndex = index; +} + +void IFaceposerModels::UnForceActiveModelIndex() +{ + m_nForceModelIndex = -1; +} + +int IFaceposerModels::GetActiveModelIndex( void ) const +{ + if ( !g_MDLViewer ) + return 0; + + if ( m_nForceModelIndex != -1 ) + return m_nForceModelIndex; + + return g_MDLViewer->GetActiveModelTab(); +} + +char const *IFaceposerModels::GetActiveModelName( void ) +{ + if ( !g_MDLViewer ) + return NULL; + + return GetModelName( GetActiveModelIndex() ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : StudioModel +//----------------------------------------------------------------------------- +StudioModel *IFaceposerModels::GetActiveStudioModel( void ) +{ + StudioModel *mdl = GetStudioModel( GetActiveModelIndex() ); + if ( !mdl ) + return g_pStudioModel; + return mdl; +} + +int IFaceposerModels::FindModelByFilename( char const *filename ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + if ( !stricmp( m->GetModelFileName(), filename ) ) + return i; + } + + return -1; +} + +void SetupModelFlexcontrollerLinks( StudioModel *model ); + +int IFaceposerModels::LoadModel( char const *filename ) +{ + MDLCACHE_CRITICAL_SECTION_( g_pMDLCache ); + + int idx = FindModelByFilename( filename ); + if ( idx == -1 && Count() < MAX_FP_MODELS ) + { + StudioModel *model = new StudioModel(); + + StudioModel *save = g_pStudioModel; + g_pStudioModel = model; + if ( !model->LoadModel( filename ) ) + { + delete model; + g_pStudioModel = save; + return 0; // ?? ERROR + } + g_pStudioModel = save; + + model->SetSequence( model->LookupSequence( "idle_subtle" ) ); + int idx = model->GetSequence(); + model->SetSequence( idx ); + + SetupModelFlexcontrollerLinks( model ); + + if (!LoadViewerSettings( filename, model )) + { + InitViewerSettings( "faceposer" ); + } + model->ClearOverlaysSequences(); + + + CFacePoserModel *newEntry = new CFacePoserModel( filename, model ); + + idx = m_Models.AddToTail( newEntry ); + + g_MDLViewer->InitModelTab(); + + g_MDLViewer->SetActiveModelTab( idx ); + + //g_pControlPanel->CenterOnFace(); + } + return idx; +} + +void IFaceposerModels::FreeModel( int index ) +{ + CFacePoserModel *entry = GetEntry( index ); + if ( !entry ) + return; + + StudioModel *m = entry->GetModel(); + + SaveViewerSettings( m->GetFileName(), m ); + + m->FreeModel( false ); + delete m; + + delete entry; + m_Models.Remove( index ); + + g_MDLViewer->InitModelTab(); +} + +void IFaceposerModels::CloseAllModels( void ) +{ + int c = Count(); + for ( int i = c - 1; i >= 0; i-- ) + { + FreeModel( i ); + } +} + +StudioModel *IFaceposerModels::GetStudioModel( int index ) +{ + CFacePoserModel *m = GetEntry( index ); + if ( !m ) + return NULL; + + if ( !m->GetModel() ) + return NULL; + + return m->GetModel(); +} + +CStudioHdr *IFaceposerModels::GetStudioHeader( int index ) +{ + StudioModel *m = GetStudioModel( index ); + if ( !m ) + return NULL; + + CStudioHdr *hdr = m->GetStudioHdr(); + if ( !hdr ) + return NULL; + return hdr; +} + +int IFaceposerModels::GetModelIndexForActor( char const *actorname ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + if ( !stricmp( m->GetActorName(), actorname ) ) + return i; + } + + return 0; +} + +StudioModel *IFaceposerModels::GetModelForActor( char const *actorname ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + if ( !stricmp( m->GetActorName(), actorname ) ) + return m->GetModel(); + } + + return NULL; +} + +char const *IFaceposerModels::GetActorNameForModel( int modelindex ) +{ + CFacePoserModel *m = GetEntry( modelindex ); + if ( !m ) + return ""; + return m->GetActorName(); +} + +void IFaceposerModels::SetActorNameForModel( int modelindex, char const *actorname ) +{ + CFacePoserModel *m = GetEntry( modelindex ); + if ( !m ) + return; + + m->SetActorName( actorname ); +} + +void IFaceposerModels::SaveModelList( void ) +{ + workspacefiles->StartStoringFiles( IWorkspaceFiles::MODELDATA ); + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + workspacefiles->StoreFile( IWorkspaceFiles::MODELDATA, m->GetModelFileName() ); + } + workspacefiles->FinishStoringFiles( IWorkspaceFiles::MODELDATA ); +} + +void IFaceposerModels::LoadModelList( void ) +{ + int files = workspacefiles->GetNumStoredFiles( IWorkspaceFiles::MODELDATA ); + for ( int i = 0; i < files; i++ ) + { + char const *filename = workspacefiles->GetStoredFile( IWorkspaceFiles::MODELDATA, i ); + LoadModel( filename ); + } +} + +void IFaceposerModels::ReleaseModels( void ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + m->Release(); + } +} + +void IFaceposerModels::RestoreModels( void ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + m->Restore(); + } +} + + +/* +void IFaceposerModels::RefreshModels( void ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + m->Refresh(); + } +} +*/ + +int IFaceposerModels::CountVisibleModels( void ) +{ + int num = 0; + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + if ( m->GetVisibleIn3DView() ) + { + num++; + } + } + + return num; +} + +void IFaceposerModels::ShowModelIn3DView( int modelindex, bool show ) +{ + CFacePoserModel *m = GetEntry( modelindex ); + if ( !m ) + return; + + m->SetVisibleIn3DView( show ); +} + +bool IFaceposerModels::IsModelShownIn3DView( int modelindex ) +{ + CFacePoserModel *m = GetEntry( modelindex ); + if ( !m ) + return false; + + return m->GetVisibleIn3DView(); +} + +int IFaceposerModels::GetIndexForStudioModel( StudioModel *model ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + if ( m->GetModel() == model ) + return i; + } + return -1; +} + +void IFaceposerModels::CheckResetFlexes( void ) +{ + int current_render_frame = g_MDLViewer->GetCurrentFrame(); + if ( current_render_frame == m_nLastRenderFrame ) + return; + + m_nLastRenderFrame = current_render_frame; + + // the phoneme editor just adds to the face, so reset the controllers + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + StudioModel *model = m->GetModel(); + if ( !model ) + continue; + + CStudioHdr *hdr = model->GetStudioHdr(); + if ( !hdr ) + continue; + + for ( LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); i++ ) + { + model->SetFlexController( i, 0.0f ); + } + } +} + +void IFaceposerModels::ClearOverlaysSequences( void ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + StudioModel *model = m->GetModel(); + if ( !model ) + continue; + + model->ClearOverlaysSequences(); + } +} + +mxbitmapdata_t *IFaceposerModels::GetBitmapForSequence( int modelindex, int sequence ) +{ + static mxbitmapdata_t nullbitmap; + CFacePoserModel *m = GetEntry( modelindex ); + if ( !m ) + return &nullbitmap; + + return m->GetBitmapForSequence( sequence ); +} + +void IFaceposerModels::RecreateAllAnimationBitmaps( int modelindex ) +{ + CFacePoserModel *m = GetEntry( modelindex ); + if ( !m ) + return; + + m->RecreateAllAnimationBitmaps(); + +} + +void IFaceposerModels::RecreateAnimationBitmap( int modelindex, int sequence ) +{ + CFacePoserModel *m = GetEntry( modelindex ); + if ( !m ) + return; + + m->RecreateAnimationBitmap( sequence, true ); +} + +int IFaceposerModels::CountActiveSources() +{ + int count = 0; + + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + StudioModel *model = m->GetModel(); + if ( !model ) + continue; + + count += model->m_mouth.GetNumVoiceSources(); + } + + return count; +} + +void IFaceposerModels::ClearModelTargets( bool force /*=false*/ ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + StudioModel *mdl = m->GetModel(); + if ( !mdl ) + continue; + + mdl->ClearLookTargets(); + } +} + +void IFaceposerModels::SetSolveHeadTurn( int solve ) +{ + int c = Count(); + for ( int i = 0; i < c; i++ ) + { + CFacePoserModel *m = GetEntry( i ); + if ( !m ) + continue; + + StudioModel *mdl = m->GetModel(); + if ( !mdl ) + continue; + + mdl->SetSolveHeadTurn( solve ); + } +} + + +static IFaceposerModels g_ModelManager; +IFaceposerModels *models = &g_ModelManager; |