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.
 
 
 
 
 
 

1142 lines
25 KiB

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