1
This commit is contained in:
275
sfmobjects/exportfacialanimation.cpp
Normal file
275
sfmobjects/exportfacialanimation.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// A class representing session state for the SFM
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "sfmobjects/exportfacialanimation.h"
|
||||
#include "movieobjects/dmeclip.h"
|
||||
#include "movieobjects/dmeanimationset.h"
|
||||
#include "movieobjects/dmegamemodel.h"
|
||||
#include "movieobjects/dmetrackgroup.h"
|
||||
#include "movieobjects/dmetrack.h"
|
||||
#include "movieobjects/dmesound.h"
|
||||
#include "movieobjects/dmelog.h"
|
||||
#include "movieobjects/dmechannel.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Contains export information
|
||||
//-----------------------------------------------------------------------------
|
||||
struct ExportInfo_t
|
||||
{
|
||||
CDmeFilmClip *m_pMovie;
|
||||
CDmeFilmClip *m_pShot;
|
||||
CDmeAnimationSet *m_pAnimationSet;
|
||||
DmeTime_t m_tExportStart;
|
||||
DmeTime_t m_tExportEnd;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used to transform channel data into export time
|
||||
//-----------------------------------------------------------------------------
|
||||
static void ComputeExportChannelScaleBias( double *pScale, DmeTime_t *pBias, ExportInfo_t &info, CDmeChannel *pChannel )
|
||||
{
|
||||
DmeClipStack_t channelToGlobal;
|
||||
if ( pChannel->BuildClipStack( &channelToGlobal, info.m_pMovie, info.m_pShot ) )
|
||||
{
|
||||
DmeTime_t tOffset = CDmeClip::FromChildMediaTime( channelToGlobal, DMETIME_ZERO, false );
|
||||
DmeTime_t tScale = CDmeClip::FromChildMediaTime( channelToGlobal, DmeTime_t( 1.0f ), false );
|
||||
*pBias = tOffset - info.m_pShot->GetStartTime();
|
||||
*pScale = ( tScale - tOffset ).GetSeconds();
|
||||
}
|
||||
}
|
||||
|
||||
static void GetExportTimeRange( DmeTime_t *pExportStart, DmeTime_t *pExportEnd, CDmeFilmClip *pShot )
|
||||
{
|
||||
*pExportStart = DMETIME_ZERO;
|
||||
*pExportEnd = pShot->GetDuration();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Adds a log layer to the list of logs for export
|
||||
//-----------------------------------------------------------------------------
|
||||
static void AddLogLayerForExport( ExportInfo_t &info, CDmElement *pRoot, const char *pControlName, CDmeChannel *pChannel )
|
||||
{
|
||||
CDmeLog *pLog = pChannel->GetLog();
|
||||
if ( !pLog || pLog->GetNumLayers() == 0 )
|
||||
return;
|
||||
|
||||
CDmrElementArray<> animations( pRoot, "animations" );
|
||||
|
||||
DmeTime_t tBias;
|
||||
double flScale;
|
||||
ComputeExportChannelScaleBias( &flScale, &tBias, info, pChannel );
|
||||
|
||||
// Only export the base layer
|
||||
CDmeLogLayer* pLogLayer = pLog->GetLayer( 0 )->Copy();
|
||||
pLogLayer->SetName( pControlName );
|
||||
pLogLayer->ScaleBiasKeyTimes( flScale, tBias );
|
||||
|
||||
// Forcibly add keys @ the start + end time
|
||||
DmeTime_t tStartTime = ( info.m_tExportStart - tBias ) / flScale;
|
||||
DmeTime_t tEndTime = ( info.m_tExportEnd - tBias ) / flScale;
|
||||
pLogLayer->InsertKeyFromLayer( info.m_tExportStart, pLog->GetLayer(0), tStartTime );
|
||||
pLogLayer->InsertKeyFromLayer( info.m_tExportEnd, pLog->GetLayer(0), tEndTime );
|
||||
|
||||
pLogLayer->RemoveKeysOutsideRange( info.m_tExportStart, info.m_tExportEnd );
|
||||
animations.AddToTail( pLogLayer );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports animations
|
||||
//-----------------------------------------------------------------------------
|
||||
static void ExportAnimations( ExportInfo_t &info, CDmElement *pRoot )
|
||||
{
|
||||
CDmrElementArray<> animations( pRoot, "animations", true );
|
||||
|
||||
// Build a list of all controls
|
||||
const CDmaElementArray< CDmElement > &controls = info.m_pAnimationSet->GetControls();
|
||||
int nControlCount = controls.Count();
|
||||
for ( int i = 0; i < nControlCount; ++i )
|
||||
{
|
||||
CDmElement *pControl = controls[i];
|
||||
if ( !pControl || pControl->GetValue<bool>( "transform" ) )
|
||||
continue;
|
||||
bool bIsStereo = pControl->GetValue<bool>( "combo" );
|
||||
if ( bIsStereo )
|
||||
{
|
||||
CDmeChannel *pValueChannel = pControl->GetValueElement<CDmeChannel>( "valuechannel" );
|
||||
CDmeChannel *pBalanceChannel = pControl->GetValueElement<CDmeChannel>( "balancechannel" );
|
||||
|
||||
CDmeLog *pValueLog = pValueChannel->GetLog();
|
||||
CDmeLog *pBalanceLog = pBalanceChannel->GetLog();
|
||||
if ( pValueLog && pBalanceLog && pValueLog->GetNumLayers() != 0 && pBalanceLog->GetNumLayers() != 0 )
|
||||
{
|
||||
DmeTime_t tValueBias, tBalanceBias;
|
||||
double flValueScale, flBalanceScale;
|
||||
ComputeExportChannelScaleBias( &flValueScale, &tValueBias, info, pValueChannel );
|
||||
ComputeExportChannelScaleBias( &flBalanceScale, &tBalanceBias, info, pBalanceChannel );
|
||||
|
||||
// Make copy to maintain log layer types
|
||||
CDmeLogLayer *pValueLogLayer = pValueLog->GetLayer( 0 )->Copy();
|
||||
CDmeLogLayer *pBalanceLogLayer = pBalanceLog->GetLayer( 0 )->Copy();
|
||||
pValueLogLayer->ScaleBiasKeyTimes( flValueScale, tValueBias );
|
||||
pBalanceLogLayer->ScaleBiasKeyTimes( flBalanceScale, tBalanceBias );
|
||||
|
||||
// Forcibly insert keys @ start + end times.
|
||||
DmeTime_t tStartTime = ( info.m_tExportStart - tValueBias ) / flValueScale;
|
||||
DmeTime_t tEndTime = ( info.m_tExportEnd - tValueBias ) / flValueScale;
|
||||
pValueLogLayer->InsertKeyFromLayer( info.m_tExportStart, pValueLog->GetLayer(0), tStartTime );
|
||||
pValueLogLayer->InsertKeyFromLayer( info.m_tExportEnd, pValueLog->GetLayer(0), tEndTime );
|
||||
|
||||
tStartTime = ( info.m_tExportStart - tBalanceBias ) / flBalanceScale;
|
||||
tEndTime = ( info.m_tExportEnd - tBalanceBias ) / flBalanceScale;
|
||||
pBalanceLogLayer->InsertKeyFromLayer( info.m_tExportStart, pBalanceLog->GetLayer(0), tStartTime );
|
||||
pBalanceLogLayer->InsertKeyFromLayer( info.m_tExportEnd, pBalanceLog->GetLayer(0), tEndTime );
|
||||
|
||||
pValueLogLayer->RemoveKeysOutsideRange( info.m_tExportStart, info.m_tExportEnd );
|
||||
pBalanceLogLayer->RemoveKeysOutsideRange( info.m_tExportStart, info.m_tExportEnd );
|
||||
|
||||
char pControlName[512];
|
||||
Q_snprintf( pControlName, sizeof(pControlName), "value_%s", pControl->GetName() );
|
||||
pValueLogLayer->SetName( pControlName );
|
||||
animations.AddToTail( pValueLogLayer );
|
||||
|
||||
Q_snprintf( pControlName, sizeof(pControlName), "balance_%s", pControl->GetName() );
|
||||
pBalanceLogLayer->SetName( pControlName );
|
||||
animations.AddToTail( pBalanceLogLayer );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CDmeChannel *pChannel = pControl->GetValueElement<CDmeChannel>( "channel" );
|
||||
AddLogLayerForExport( info, pRoot, pControl->GetName(), pChannel );
|
||||
}
|
||||
|
||||
if ( pControl->GetValue<bool>( "multi" ) )
|
||||
{
|
||||
char pControlName[512];
|
||||
Q_snprintf( pControlName, sizeof(pControlName), "multi_%s", pControl->GetName() );
|
||||
CDmeChannel *pMultiChannel = pControl->GetValueElement<CDmeChannel>( "multilevelchannel" );
|
||||
AddLogLayerForExport( info, pRoot, pControlName, pMultiChannel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helper to export sounds
|
||||
//-----------------------------------------------------------------------------
|
||||
static void ExportSounds( ExportInfo_t &info, CDmElement *pRoot, CDmeClip *pClip, DmeTime_t tOffset )
|
||||
{
|
||||
CDmrElementArray<> sounds( pRoot, "sounds", true );
|
||||
|
||||
DmeClipStack_t soundToGlobal;
|
||||
int gc = pClip->GetTrackGroupCount();
|
||||
for ( int i = 0; i < gc; ++i )
|
||||
{
|
||||
CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeSoundClip, pTrackGroup, pTrack, pSoundClip )
|
||||
|
||||
const char *pGameSoundName = pSoundClip->m_Sound->m_GameSoundName;
|
||||
if ( !pGameSoundName || !pGameSoundName[0] )
|
||||
continue;
|
||||
|
||||
if ( pSoundClip->IsMute() )
|
||||
continue;
|
||||
|
||||
if ( !pSoundClip->BuildClipStack( &soundToGlobal, info.m_pMovie, pClip ) )
|
||||
continue;
|
||||
|
||||
DmeTime_t tStart = CDmeClip::FromChildMediaTime( soundToGlobal, DMETIME_ZERO, false );
|
||||
DmeTime_t tEnd = CDmeClip::FromChildMediaTime( soundToGlobal, pSoundClip->GetDuration(), false );
|
||||
tStart -= tOffset;
|
||||
tEnd -= tOffset;
|
||||
if ( tStart >= info.m_tExportEnd || tEnd <= info.m_tExportStart )
|
||||
continue;
|
||||
|
||||
const char *pName = pSoundClip->GetName();
|
||||
CDmElement *pSoundEvent = CreateElement<CDmElement>( pName );
|
||||
pSoundEvent->SetValue( "start", tStart.GetTenthsOfMS() );
|
||||
pSoundEvent->SetValue( "end", tEnd.GetTenthsOfMS() );
|
||||
pSoundEvent->SetValue( "gamesound", pGameSoundName );
|
||||
sounds.AddToTail( pSoundEvent );
|
||||
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_END()
|
||||
}
|
||||
}
|
||||
|
||||
static void ExportSounds_R( ExportInfo_t &info, CDmElement *pRoot, CDmeClip *pClip, DmeTime_t tOffset )
|
||||
{
|
||||
ExportSounds( info, pRoot, pClip, tOffset );
|
||||
|
||||
// Recurse
|
||||
DmeClipStack_t childToGlobal;
|
||||
int gc = pClip->GetTrackGroupCount();
|
||||
for ( int i = 0; i < gc; ++i )
|
||||
{
|
||||
CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
|
||||
DMETRACKGROUP_FOREACH_CLIP_START( pTrackGroup, pTrack, pChild )
|
||||
|
||||
if ( !pChild->BuildClipStack( &childToGlobal, info.m_pMovie, pClip ) )
|
||||
continue;
|
||||
|
||||
DmeTime_t tStart = CDmeClip::FromChildMediaTime( childToGlobal, DMETIME_ZERO, false );
|
||||
DmeTime_t tEnd = CDmeClip::FromChildMediaTime( childToGlobal, pChild->GetDuration(), false );
|
||||
tStart -= tOffset;
|
||||
tEnd -= tOffset;
|
||||
if ( tStart >= info.m_tExportEnd || tEnd <= info.m_tExportStart )
|
||||
continue;
|
||||
|
||||
ExportSounds_R( info, pRoot, pChild, tOffset );
|
||||
|
||||
DMETRACKGROUP_FOREACH_CLIP_END()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports sounds, default implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
static void ExportSounds( ExportInfo_t &info, CDmElement *pRoot )
|
||||
{
|
||||
DmeTime_t tOffset = info.m_pShot->GetStartTime();
|
||||
ExportSounds( info, pRoot, info.m_pMovie, tOffset );
|
||||
ExportSounds_R( info, pRoot, info.m_pShot, tOffset );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Exports an .fac file
|
||||
//-----------------------------------------------------------------------------
|
||||
bool ExportFacialAnimation( const char *pFileName, CDmeFilmClip *pMovie, CDmeFilmClip *pShot, CDmeAnimationSet *pAnimationSet )
|
||||
{
|
||||
if ( !pMovie || !pShot || !pAnimationSet )
|
||||
return false;
|
||||
|
||||
const char *pFileFormat = "facial_animation";
|
||||
CDmElement *pRoot = CreateElement< CDmElement >( pAnimationSet->GetName() );
|
||||
|
||||
ExportInfo_t info;
|
||||
info.m_pMovie = pMovie;
|
||||
info.m_pShot = pShot;
|
||||
info.m_pAnimationSet = pAnimationSet;
|
||||
GetExportTimeRange( &info.m_tExportStart, &info.m_tExportEnd, pShot );
|
||||
|
||||
CDmeGameModel *pGameModel = pAnimationSet->GetValueElement<CDmeGameModel>( "gameModel" );
|
||||
if ( pGameModel )
|
||||
{
|
||||
pRoot->SetValue( "gamemodel", pGameModel->GetModelName() );
|
||||
}
|
||||
ExportAnimations( info, pRoot );
|
||||
ExportSounds( info, pRoot );
|
||||
|
||||
pRoot->SetFileId( DMFILEID_INVALID, TD_DEEP );
|
||||
const char *pEncoding = "keyvalues2_flat";
|
||||
bool bOk = g_pDataModel->SaveToFile( pFileName, NULL, pEncoding, pFileFormat, pRoot );
|
||||
DestroyElement( pRoot, TD_DEEP );
|
||||
return bOk;
|
||||
}
|
||||
|
||||
|
951
sfmobjects/flexcontrolbuilder.cpp
Normal file
951
sfmobjects/flexcontrolbuilder.cpp
Normal file
@ -0,0 +1,951 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// A class used to build flex animation controls for an animation set
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "sfmobjects/flexcontrolbuilder.h"
|
||||
#include "studio.h"
|
||||
#include "movieobjects/dmeanimationset.h"
|
||||
#include "movieobjects/dmeclip.h"
|
||||
#include "movieobjects/dmetrackgroup.h"
|
||||
#include "movieobjects/dmetrack.h"
|
||||
#include "movieobjects/dmegamemodel.h"
|
||||
#include "movieobjects/dmechannel.h"
|
||||
#include "movieobjects/dmebalancetostereocalculatoroperator.h"
|
||||
#include "tier1/utlsymbol.h"
|
||||
|
||||
|
||||
// Names of attributes in controls we attach channels to
|
||||
#define CONTROL_CHANNEL_ATTRIBUTE_COUNT 4
|
||||
static const char *s_pChannelControls[CONTROL_CHANNEL_ATTRIBUTE_COUNT] =
|
||||
{
|
||||
"channel", "valuechannel", "balancechannel", "multilevelchannel"
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Flex controller
|
||||
//-----------------------------------------------------------------------------
|
||||
class CDefaultGlobalFlexController : public IGlobalFlexController
|
||||
{
|
||||
public:
|
||||
CDefaultGlobalFlexController() : m_SymbolTable( 0, 32, true ) {}
|
||||
|
||||
virtual int FindGlobalFlexController( const char *name )
|
||||
{
|
||||
return m_SymbolTable.AddString( name );
|
||||
}
|
||||
|
||||
virtual const char *GetGlobalFlexControllerName( int idx )
|
||||
{
|
||||
return m_SymbolTable.String( (CUtlSymbol)idx );
|
||||
}
|
||||
|
||||
private:
|
||||
CUtlSymbolTable m_SymbolTable;
|
||||
};
|
||||
|
||||
static CDefaultGlobalFlexController s_GlobalFlexController;
|
||||
extern IGlobalFlexController *g_pGlobalFlexController;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This builds a list of the desired flex controllers we need to have controls for
|
||||
// by the time we're all done with this enormous process.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::BuildDesiredFlexControlList( CDmeGameModel *pGameModel )
|
||||
{
|
||||
CStudioHdr cHdr( pGameModel->GetStudioHdr() );
|
||||
LocalFlexController_t nCount = cHdr.numflexcontrollers();
|
||||
|
||||
m_FlexControllerInfo.EnsureCapacity( nCount );
|
||||
for ( LocalFlexController_t i = LocalFlexController_t(0); i < nCount; ++i )
|
||||
{
|
||||
int j = m_FlexControllerInfo.AddToTail();
|
||||
|
||||
FlexControllerInfo_t& info = m_FlexControllerInfo[j];
|
||||
mstudioflexcontroller_t *pFlex = cHdr.pFlexcontroller( i );
|
||||
Q_strncpy( info.m_pFlexControlName, pFlex->pszName(), sizeof( info.m_pFlexControlName ) );
|
||||
info.m_nGlobalIndex = g_pGlobalFlexController->FindGlobalFlexController( pFlex->pszName() );
|
||||
info.m_flDefaultValue = 0.0f;
|
||||
if ( pFlex->max != pFlex->min )
|
||||
{
|
||||
// FIXME: Is this the correct default value?
|
||||
info.m_flDefaultValue = ( 0.0f - pFlex->min ) / ( pFlex->max - pFlex->min );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This builds a list of the desired input controls we need to have controls for
|
||||
// by the time we're all done with this enormous process.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::BuildDesiredControlList( CDmeGameModel *pGameModel )
|
||||
{
|
||||
int nCount = m_FlexControllerInfo.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
int j = m_ControlInfo.AddToTail();
|
||||
ControlInfo_t &controlInfo = m_ControlInfo[j];
|
||||
memset( &controlInfo, 0, sizeof(ControlInfo_t) );
|
||||
|
||||
FlexControllerInfo_t& info = m_FlexControllerInfo[i];
|
||||
const char *pFlexName = info.m_pFlexControlName;
|
||||
|
||||
// Deal with stereo/mono controls
|
||||
if ( !Q_strnicmp( "right_", pFlexName, 6 ) && ( i < nCount - 1 ) )
|
||||
{
|
||||
FlexControllerInfo_t& leftInfo = m_FlexControllerInfo[i+1];
|
||||
Assert( !Q_strnicmp( "left_", leftInfo.m_pFlexControlName, 5 ) );
|
||||
|
||||
controlInfo.m_bIsStereo = true;
|
||||
controlInfo.m_pControllerIndex[ OUTPUT_RIGHT ] = i;
|
||||
controlInfo.m_pControllerIndex[ OUTPUT_LEFT ] = i+1;
|
||||
Q_strncpy( controlInfo.m_pControlName, pFlexName + 6, sizeof(controlInfo.m_pControlName) );
|
||||
|
||||
// Convert default values into value/balance
|
||||
LeftRightToValueBalance( &controlInfo.m_pDefaultValue[ CONTROL_VALUE ],
|
||||
&controlInfo.m_pDefaultValue[ CONTROL_BALANCE ],
|
||||
leftInfo.m_flDefaultValue, info.m_flDefaultValue );
|
||||
|
||||
// Skip the 'left_' flex control
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
controlInfo.m_bIsStereo = false;
|
||||
controlInfo.m_pControllerIndex[ OUTPUT_MONO ] = i;
|
||||
controlInfo.m_pControllerIndex[ OUTPUT_LEFT ] = -1;
|
||||
Q_strncpy( controlInfo.m_pControlName, pFlexName, sizeof(controlInfo.m_pControlName) );
|
||||
controlInfo.m_pDefaultValue[ CONTROL_VALUE ] = info.m_flDefaultValue;
|
||||
controlInfo.m_pDefaultValue[ CONTROL_BALANCE ] = 0.5f;
|
||||
}
|
||||
|
||||
// Deal with multi controls
|
||||
controlInfo.m_bIsMulti = ( i+1 < nCount ) && !Q_strnicmp( "multi_", m_FlexControllerInfo[ i+1 ].m_pFlexControlName, 6 );
|
||||
if ( controlInfo.m_bIsMulti )
|
||||
{
|
||||
FlexControllerInfo_t& multiInfo = m_FlexControllerInfo[i+1];
|
||||
|
||||
controlInfo.m_pControllerIndex[ OUTPUT_MULTILEVEL ] = i+1;
|
||||
controlInfo.m_pDefaultValue[ CONTROL_MULTILEVEL ] = multiInfo.m_flDefaultValue;
|
||||
|
||||
// Skip the 'multi_' flex control
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
controlInfo.m_pControllerIndex[ OUTPUT_MULTILEVEL ] = -1;
|
||||
controlInfo.m_pDefaultValue[ CONTROL_MULTILEVEL ] = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds a desired flex controller index in the m_FlexControllerInfo array
|
||||
//-----------------------------------------------------------------------------
|
||||
int CFlexControlBuilder::FindDesiredFlexController( const char *pFlexControllerName ) const
|
||||
{
|
||||
int nCount = m_FlexControllerInfo.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
if ( !Q_stricmp( pFlexControllerName, m_FlexControllerInfo[i].m_pFlexControlName ) )
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Removes a channel from the channels clip referring to it.
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::RemoveChannelFromClips( CDmeChannel *pChannel )
|
||||
{
|
||||
// First, try to grab the channels referring to this op
|
||||
CUtlVector< CDmeChannelsClip* > channelsClips;
|
||||
FindAncestorsReferencingElement( pChannel, channelsClips );
|
||||
int nChannelsClips = channelsClips.Count();
|
||||
for ( int i = 0; i < nChannelsClips; ++i )
|
||||
{
|
||||
channelsClips[ i ]->RemoveChannel( pChannel );
|
||||
}
|
||||
|
||||
// Next, remove the channel from values controls it may be attached to
|
||||
for ( int i = 0; i < CONTROL_CHANNEL_ATTRIBUTE_COUNT; ++i )
|
||||
{
|
||||
UtlSymId_t symChannelControl = g_pDataModel->GetSymbol( s_pChannelControls[i] );
|
||||
CDmElement *pControl = FindReferringElement< CDmElement >( pChannel, symChannelControl );
|
||||
if ( pControl )
|
||||
{
|
||||
pControl->RemoveAttribute( s_pChannelControls[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Removes a stereo operator from the animation set referring to it
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::RemoveStereoOpFromSet( CDmeBalanceToStereoCalculatorOperator *pSteroOp )
|
||||
{
|
||||
// First, try to grab the channel referring to this op
|
||||
const static UtlSymId_t symOperators = g_pDataModel->GetSymbol( "operators" );
|
||||
CDmeAnimationSet *pAnimationSet = FindReferringElement< CDmeAnimationSet >( pSteroOp, symOperators );
|
||||
if ( pAnimationSet )
|
||||
{
|
||||
pAnimationSet->RemoveOperator( pSteroOp );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Blows away the various elements trying to control a flex controller op
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::CleanupExistingFlexController( CDmeGameModel *pGameModel, CDmeGlobalFlexControllerOperator *pOp )
|
||||
{
|
||||
CDmeBalanceToStereoCalculatorOperator *pStereoOp;
|
||||
|
||||
// First, try to grab the channel referring to this op
|
||||
const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
|
||||
CDmeChannel *pChannel = FindReferringElement< CDmeChannel >( pOp, symToElement );
|
||||
if ( !pChannel )
|
||||
goto destroyOp;
|
||||
|
||||
// Sometimes a stereo op will be read from by this channel
|
||||
pStereoOp = CastElement< CDmeBalanceToStereoCalculatorOperator >( pChannel->GetFromElement() );
|
||||
RemoveChannelFromClips( pChannel );
|
||||
DestroyElement( pChannel );
|
||||
if ( !pStereoOp )
|
||||
goto destroyOp;
|
||||
|
||||
RemoveStereoOpFromSet( pStereoOp );
|
||||
|
||||
// If we have a stereo op, then blow away all channels targetting that stereo op
|
||||
DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( pStereoOp->GetHandle() );
|
||||
DmAttributeReferenceIterator_t next;
|
||||
for ( ; i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; i = next )
|
||||
{
|
||||
next = g_pDataModel->NextAttributeReferencingElement( i );
|
||||
|
||||
CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
|
||||
pChannel = CastElement<CDmeChannel>( pAttribute->GetOwner() );
|
||||
if ( pChannel && pAttribute->GetNameSymbol() == symToElement )
|
||||
{
|
||||
RemoveChannelFromClips( pChannel );
|
||||
DestroyElement( pChannel );
|
||||
}
|
||||
}
|
||||
|
||||
DestroyElement( pStereoOp );
|
||||
|
||||
destroyOp:
|
||||
pGameModel->RemoveGlobalFlexController( pOp );
|
||||
DestroyElement( pOp );
|
||||
}
|
||||
|
||||
bool RemoveChannelIfUnused( CDmeChannel *pChannel, CDmeChannelsClip *pChannelsClip )
|
||||
{
|
||||
if ( !pChannel )
|
||||
return false;
|
||||
if ( pChannel->GetToElement() != NULL )
|
||||
return false;
|
||||
|
||||
pChannelsClip->RemoveChannel( pChannel );
|
||||
DestroyElement( pChannel );
|
||||
return true;
|
||||
}
|
||||
|
||||
// finds controls whose channels don't point to anything anymore, and deletes both the channels and the control
|
||||
void CFlexControlBuilder::RemoveUnusedControlsAndChannels( CDmeAnimationSet *pAnimationSet, CDmeChannelsClip *pChannelsClip )
|
||||
{
|
||||
CDmrElementArray<> controls = pAnimationSet->GetControls();
|
||||
int nControls = controls.Count();
|
||||
for ( int i = nControls - 1; i >= 0 ; --i )
|
||||
{
|
||||
CDmElement *pControl = controls[ i ];
|
||||
if ( pControl )
|
||||
{
|
||||
bool bRemoved = RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "channel" ), pChannelsClip );
|
||||
bRemoved = bRemoved || RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "valuechannel" ), pChannelsClip );
|
||||
bRemoved = bRemoved || RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "balancechannel" ), pChannelsClip );
|
||||
bRemoved = bRemoved || RemoveChannelIfUnused( pControl->GetValueElement< CDmeChannel >( "multilevelchannel" ), pChannelsClip );
|
||||
|
||||
if ( !bRemoved )
|
||||
continue;
|
||||
|
||||
DestroyElement( pControl );
|
||||
}
|
||||
|
||||
controls.Remove( i );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// This removes existing controls on the animationset that aren't in the desired state
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::RemoveUnusedExistingFlexControllers( CDmeGameModel *pGameModel )
|
||||
{
|
||||
// These are the current flex controllers
|
||||
// NOTE: Name of these controllers should match the names of the flex controllers
|
||||
int nCount = pGameModel->NumGlobalFlexControllers();
|
||||
for ( int i = nCount; --i >= 0; )
|
||||
{
|
||||
CDmeGlobalFlexControllerOperator *pOp = pGameModel->GetGlobalFlexController( i );
|
||||
Assert( pOp );
|
||||
if ( pOp && FindDesiredFlexController( pOp->GetName() ) < 0 )
|
||||
{
|
||||
Msg( "removing flex controller %s\n", pOp->GetName() );
|
||||
|
||||
CleanupExistingFlexController( pGameModel, pOp );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns an existing mono log
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::GetExistingMonoLog( ExistingLogInfo_t *pExistingLog,
|
||||
CDmeFilmClip *pClip, CDmeGlobalFlexControllerOperator *pMonoOp )
|
||||
{
|
||||
pExistingLog->m_pLog = NULL;
|
||||
|
||||
const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
|
||||
CDmeChannel *pMonoChannel = FindReferringElement< CDmeChannel >( pMonoOp, symToElement );
|
||||
if ( !pMonoChannel )
|
||||
return;
|
||||
|
||||
// First, try to grab the channel referring to this op
|
||||
CDmeFloatLog *pLog = CastElement< CDmeFloatLog >( pMonoChannel->GetLog() );
|
||||
if ( !pLog )
|
||||
return;
|
||||
|
||||
if ( ComputeChannelTimeTransform( &pExistingLog->m_GlobalOffset, &pExistingLog->m_flGlobalScale, pClip, pMonoChannel ) )
|
||||
{
|
||||
pExistingLog->m_pLog = pLog;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds a channels clip containing a particular channel
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmeChannelsClip* CFlexControlBuilder::FindChannelsClipContainingChannel( CDmeFilmClip *pClip, CDmeChannel *pSearch )
|
||||
{
|
||||
int gc = pClip->GetTrackGroupCount();
|
||||
for ( int i = 0; i < gc; ++i )
|
||||
{
|
||||
CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeChannelsClip, pTrackGroup, pTrack, pChannelsClip )
|
||||
|
||||
int nChannels = pChannelsClip->m_Channels.Count();
|
||||
for ( int j = 0; j < nChannels; ++j )
|
||||
{
|
||||
CDmeChannel *pChannel = pChannelsClip->m_Channels[ j ];
|
||||
if ( pChannel == pSearch )
|
||||
return pChannelsClip;
|
||||
}
|
||||
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_END()
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Computes a global offset and scale to convert from log time to global time
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::ComputeChannelTimeTransform( DmeTime_t *pOffset, double *pScale, CDmeChannelsClip *pChannelsClip )
|
||||
{
|
||||
// Determine the global time of the start + end of the log
|
||||
DmeClipStack_t srcStack;
|
||||
pChannelsClip->BuildClipStack( &srcStack, m_pMovie, NULL );
|
||||
|
||||
*pOffset = CDmeClip::FromChildMediaTime( srcStack, DMETIME_ZERO, false );
|
||||
DmeTime_t duration = CDmeClip::FromChildMediaTime( srcStack, DmeTime_t( 10000 ), false );
|
||||
duration -= *pOffset;
|
||||
*pScale = duration.GetSeconds();
|
||||
}
|
||||
|
||||
bool CFlexControlBuilder::ComputeChannelTimeTransform( DmeTime_t *pOffset, double *pScale, CDmeFilmClip* pClip, CDmeChannel* pChannel )
|
||||
{
|
||||
CDmeChannelsClip *pChannelsClip = FindChannelsClipContainingChannel( pClip, pChannel );
|
||||
if ( !pChannelsClip )
|
||||
return false;
|
||||
|
||||
ComputeChannelTimeTransform( pOffset, pScale, pChannelsClip );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns an existing value/balance log
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::GetExistingVBLog( ExistingLogInfo_t *pLogs, CDmeFilmClip *pClip, CDmeBalanceToStereoCalculatorOperator *pStereoOp )
|
||||
{
|
||||
// Stereo operators always have value/balance logs attached
|
||||
DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( pStereoOp->GetHandle() );
|
||||
for ( ; i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; i = g_pDataModel->NextAttributeReferencingElement( i ) )
|
||||
{
|
||||
CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
|
||||
CDmeChannel *pChannel = CastElement< CDmeChannel >( pAttribute->GetOwner() );
|
||||
const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
|
||||
if ( !pChannel || pAttribute->GetNameSymbol() != symToElement )
|
||||
continue;
|
||||
|
||||
const char *pToAttributeName = pChannel->GetToAttribute()->GetName();
|
||||
int nLogIndex = -1;
|
||||
if ( !Q_stricmp( pToAttributeName, "value" ) )
|
||||
{
|
||||
nLogIndex = CONTROL_VALUE;
|
||||
}
|
||||
else if ( !Q_stricmp( pToAttributeName, "balance" ) )
|
||||
{
|
||||
nLogIndex = CONTROL_BALANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CDmeFloatLog *pLog = CastElement< CDmeFloatLog >( pChannel->GetLog() );
|
||||
if ( !pLog )
|
||||
continue;
|
||||
|
||||
// Compute a scale and offset transforming log time into global time
|
||||
if ( !ComputeChannelTimeTransform( &pLogs[nLogIndex].m_GlobalOffset, &pLogs[nLogIndex].m_flGlobalScale, pClip, pChannel ) )
|
||||
continue;
|
||||
|
||||
// Detach the
|
||||
pLogs[nLogIndex].m_pLog = pLog;
|
||||
pChannel->SetLog( NULL ); // Detach
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void AddKeyToLogs( CDmeTypedLog< float > *valueLog, CDmeTypedLog< float > *balanceLog, const DmeTime_t& keyTime, float lval, float rval )
|
||||
{
|
||||
// Convert left right into value, balance
|
||||
float value, balance;
|
||||
LeftRightToValueBalance( &value, &balance, lval, rval );
|
||||
|
||||
// Msg( "%.5f setting l/r %f %f to value %f balance %f\n",
|
||||
// keyTime.GetSeconds(), lval, rval, value, balance );
|
||||
|
||||
valueLog->SetKey( keyTime, value );
|
||||
balanceLog->SetKey( keyTime, balance );
|
||||
}
|
||||
|
||||
static void ConvertLRToVBLog( CDmeFloatLog *pValueLog, CDmeFloatLog *pBalanceLog, CDmeFloatLog *pLeftLog, CDmeFloatLog *pRightLog, DmeTime_t rightOffset, double flRightScale )
|
||||
{
|
||||
int lc = pLeftLog->GetKeyCount();
|
||||
int rc = pRightLog->GetKeyCount();
|
||||
|
||||
int nLeft = 0, nRight = 0;
|
||||
while ( nLeft < lc || nRight < rc )
|
||||
{
|
||||
bool bUseLeft = ( nLeft < lc );
|
||||
bool bUseRight = ( nRight < rc );
|
||||
|
||||
DmeTime_t leftKeyTime = bUseLeft ? pLeftLog->GetKeyTime( nLeft ) : DMETIME_MAXTIME;
|
||||
DmeTime_t rightKeyTime = bUseRight ? pRightLog->GetKeyTime( nRight ) : DMETIME_MAXTIME;
|
||||
|
||||
// Transform rightKeyTime into leftKeyTime space
|
||||
if ( bUseRight )
|
||||
{
|
||||
rightKeyTime.SetSeconds( rightKeyTime.GetSeconds() * flRightScale );
|
||||
rightKeyTime += rightOffset;
|
||||
}
|
||||
|
||||
if ( leftKeyTime == rightKeyTime )
|
||||
{
|
||||
float lval = pLeftLog->GetKeyValue( nLeft++ );
|
||||
float rval = pRightLog->GetKeyValue( nRight++ );
|
||||
AddKeyToLogs( pValueLog, pBalanceLog, leftKeyTime, lval, rval );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( leftKeyTime < rightKeyTime )
|
||||
{
|
||||
// pull a value from the right log at the leftKeyTime
|
||||
// and advance to the next sample on the left side
|
||||
float lval = pLeftLog->GetKeyValue( nLeft++ );
|
||||
float rval = pRightLog->GetValue( leftKeyTime );
|
||||
AddKeyToLogs( pValueLog, pBalanceLog, leftKeyTime, lval, rval );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Pull a value from the left log at the rightKeyTime
|
||||
// and advance to the next sample on the right side
|
||||
float lval = pLeftLog->GetValue( rightKeyTime );
|
||||
float rval = pRightLog->GetKeyValue( nRight++ );
|
||||
AddKeyToLogs( pValueLog, pBalanceLog, rightKeyTime, lval, rval );
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Converts an existing value/balance log
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::ConvertExistingLRLogs( ExistingLogInfo_t *pLogs,
|
||||
CDmeFilmClip *pClip, CDmeChannel *pLeftChannel, CDmeChannel *pRightChannel )
|
||||
{
|
||||
CDmeFloatLog *pRightLog = CastElement< CDmeFloatLog >( pRightChannel->GetLog() );
|
||||
CDmeFloatLog *pLeftLog = CastElement< CDmeFloatLog >( pLeftChannel->GetLog() );
|
||||
if ( !pRightLog || !pLeftLog )
|
||||
return;
|
||||
|
||||
// Compute a scale + offset to transform the right log to get it in the same space as the left log
|
||||
DmeTime_t leftOffset, rightOffset;
|
||||
double flLeftScale, flRightScale;
|
||||
if ( !ComputeChannelTimeTransform( &leftOffset, &flLeftScale, pClip, pLeftChannel ) )
|
||||
return;
|
||||
if ( !ComputeChannelTimeTransform( &rightOffset, &flRightScale, pClip, pRightChannel ) )
|
||||
return;
|
||||
|
||||
flRightScale = ( flRightScale != 0.0f ) ? flLeftScale / flRightScale : 1.0;
|
||||
rightOffset = leftOffset - DmeTime_t( rightOffset.GetSeconds() * flRightScale );
|
||||
|
||||
pLogs[CONTROL_VALUE].m_pLog = CreateElement< CDmeFloatLog >( "value" );
|
||||
pLogs[CONTROL_VALUE].m_GlobalOffset = leftOffset;
|
||||
pLogs[CONTROL_VALUE].m_flGlobalScale = flLeftScale;
|
||||
|
||||
pLogs[CONTROL_BALANCE].m_pLog = CreateElement< CDmeFloatLog >( "balance" );
|
||||
pLogs[CONTROL_BALANCE].m_GlobalOffset = leftOffset; // NOTE: This is correct! All logs are transformed into left channel time
|
||||
pLogs[CONTROL_BALANCE].m_flGlobalScale = flLeftScale;
|
||||
|
||||
ConvertLRToVBLog( pLogs[CONTROL_VALUE].m_pLog, pLogs[CONTROL_BALANCE].m_pLog,
|
||||
pLeftLog, pRightLog, rightOffset, flRightScale );
|
||||
|
||||
// DestroyElement( pLeftLog );
|
||||
// DestroyElement( pRightLog );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Returns an existing stereo log, performing conversion if necessary
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::GetExistingStereoLog( ExistingLogInfo_t *pLogs, CDmeFilmClip *pClip,
|
||||
CDmeGlobalFlexControllerOperator *pRightOp, CDmeGlobalFlexControllerOperator *pLeftOp )
|
||||
{
|
||||
pLogs[CONTROL_VALUE].m_pLog = NULL;
|
||||
pLogs[CONTROL_BALANCE].m_pLog = NULL;
|
||||
|
||||
// First, try to grab the channel referring to this op
|
||||
const static UtlSymId_t symToElement = g_pDataModel->GetSymbol( "toElement" );
|
||||
CDmeChannel *pChannel = FindReferringElement< CDmeChannel >( pRightOp, symToElement );
|
||||
if ( !pChannel )
|
||||
return;
|
||||
|
||||
// Sometimes a stereo op will be read from by this channel
|
||||
CDmeBalanceToStereoCalculatorOperator *pStereoOp = CastElement< CDmeBalanceToStereoCalculatorOperator >( pChannel->GetFromElement() );
|
||||
if ( pStereoOp )
|
||||
{
|
||||
GetExistingVBLog( pLogs, pClip, pStereoOp );
|
||||
return;
|
||||
}
|
||||
|
||||
// In this case, we recorded game data and we have left/right logs
|
||||
CDmeChannel *pLeftChannel = FindReferringElement< CDmeChannel >( pLeftOp, symToElement );
|
||||
if ( !pLeftChannel )
|
||||
return;
|
||||
ConvertExistingLRLogs( pLogs, pClip, pLeftChannel, pChannel );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fixup list of existing flex controller logs
|
||||
// - reattach flex controls that were removed from the gamemodel's list
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::FixupExistingFlexControlLogList( CDmeFilmClip *pCurrentClip, CDmeGameModel *pGameModel )
|
||||
{
|
||||
int nTrackGroups = pCurrentClip->GetTrackGroupCount();
|
||||
for ( int gi = 0; gi < nTrackGroups; ++gi )
|
||||
{
|
||||
CDmeTrackGroup *pTrackGroup = pCurrentClip->GetTrackGroup( gi );
|
||||
if ( !pTrackGroup )
|
||||
continue;
|
||||
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeChannelsClip, pTrackGroup, pTrack, pChannelsClip )
|
||||
int nChannels = pChannelsClip->m_Channels.Count();
|
||||
for ( int ci = 0; ci < nChannels; ++ci )
|
||||
{
|
||||
CDmeChannel *pChannel = pChannelsClip->m_Channels[ ci ];
|
||||
if ( !pChannel )
|
||||
continue;
|
||||
|
||||
CDmeGlobalFlexControllerOperator *pOp = CastElement< CDmeGlobalFlexControllerOperator >( pChannel->GetToElement() );
|
||||
if ( !pOp )
|
||||
continue;
|
||||
|
||||
if ( pOp->m_gameModel != pGameModel->GetHandle() )
|
||||
continue;
|
||||
|
||||
int nGlobalIndex = pOp->GetGlobalIndex();
|
||||
CDmeGlobalFlexControllerOperator *pFoundOp = pGameModel->FindGlobalFlexController( nGlobalIndex );
|
||||
if ( pFoundOp == pOp )
|
||||
continue;
|
||||
|
||||
if ( !pFoundOp )
|
||||
{
|
||||
Msg( "adding missing flex controller %d %s\n", nGlobalIndex, pOp->GetName() );
|
||||
pFoundOp = pGameModel->AddGlobalFlexController( pOp->GetName(), nGlobalIndex );
|
||||
}
|
||||
pChannel->SetOutput( pFoundOp, pChannel->GetToAttribute()->GetName() );
|
||||
if ( pChannel->GetFromElement() == pOp )
|
||||
{
|
||||
pChannel->SetInput( pFoundOp, pChannel->GetFromAttribute()->GetName() );
|
||||
}
|
||||
Msg( "removing duplicate flex controller %d %s\n", nGlobalIndex, pOp->GetName() );
|
||||
RemoveElementFromRefereringAttributes( pOp );
|
||||
DestroyElement( pOp );
|
||||
}
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_END();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Build list of existing flex controller logs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::BuildExistingFlexControlLogList( CDmeFilmClip *pCurrentClip, CDmeGameModel *pGameModel )
|
||||
{
|
||||
// These are the current flex controllers that also exist in the desired list
|
||||
// NOTE: Name of these controllers should match the names of the flex controllers
|
||||
int nCount = m_ControlInfo.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
ControlInfo_t &info = m_ControlInfo[i];
|
||||
|
||||
if ( info.m_bIsStereo )
|
||||
{
|
||||
int nRightFlex = info.m_pControllerIndex[ OUTPUT_RIGHT ];
|
||||
int nLeftFlex = info.m_pControllerIndex[ OUTPUT_LEFT ];
|
||||
FlexControllerInfo_t *pRightInfo = &m_FlexControllerInfo[nRightFlex];
|
||||
FlexControllerInfo_t *pLeftInfo = &m_FlexControllerInfo[nLeftFlex];
|
||||
|
||||
CDmeGlobalFlexControllerOperator *pRightOp = pGameModel->FindGlobalFlexController( pRightInfo->m_nGlobalIndex );
|
||||
CDmeGlobalFlexControllerOperator *pLeftOp = pGameModel->FindGlobalFlexController( pLeftInfo->m_nGlobalIndex );
|
||||
if ( pRightOp && pLeftOp )
|
||||
{
|
||||
Msg( "replacing stereo flex controllers %s and %s\n", pRightOp->GetName(), pRightOp->GetName() );
|
||||
|
||||
GetExistingStereoLog( info.m_pExistingLog, pCurrentClip, pRightOp, pLeftOp );
|
||||
CleanupExistingFlexController( pGameModel, pRightOp );
|
||||
CleanupExistingFlexController( pGameModel, pLeftOp );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nFlex = info.m_pControllerIndex[ OUTPUT_MONO ];
|
||||
FlexControllerInfo_t *pInfo = &m_FlexControllerInfo[nFlex];
|
||||
|
||||
CDmeGlobalFlexControllerOperator *pMonoOp = pGameModel->FindGlobalFlexController( pInfo->m_nGlobalIndex );
|
||||
if ( pMonoOp )
|
||||
{
|
||||
Msg( "replacing mono flex controller %s\n", pMonoOp->GetName() );
|
||||
|
||||
GetExistingMonoLog( &info.m_pExistingLog[CONTROL_VALUE], pCurrentClip, pMonoOp );
|
||||
CleanupExistingFlexController( pGameModel, pMonoOp );
|
||||
}
|
||||
}
|
||||
|
||||
if ( info.m_bIsMulti )
|
||||
{
|
||||
int nFlex = info.m_pControllerIndex[ OUTPUT_MULTILEVEL ];
|
||||
FlexControllerInfo_t *pMultiInfo = &m_FlexControllerInfo[ nFlex ];
|
||||
CDmeGlobalFlexControllerOperator *pMultiOp = pGameModel->FindGlobalFlexController( pMultiInfo->m_nGlobalIndex );
|
||||
if ( pMultiOp )
|
||||
{
|
||||
Msg( "replacing multi flex controller %s\n", pMultiOp->GetName() );
|
||||
|
||||
GetExistingMonoLog( &info.m_pExistingLog[CONTROL_MULTILEVEL], pCurrentClip, pMultiOp );
|
||||
CleanupExistingFlexController( pGameModel, pMultiOp );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a flex controller and a channel connecting it to a control
|
||||
//-----------------------------------------------------------------------------
|
||||
struct FlexOpInfo_t
|
||||
{
|
||||
const char *m_pControlAttributeName;
|
||||
const char *m_pControlLinkAttributeName;
|
||||
};
|
||||
|
||||
static FlexOpInfo_t s_pFlexOpInfo[2] =
|
||||
{
|
||||
{ "value", "" },
|
||||
{ "multilevel", "multilevel" },
|
||||
};
|
||||
|
||||
void CFlexControlBuilder::BuildFlexControllerOps( CDmeGameModel *pGameModel, CDmeChannelsClip *pChannelsClip, ControlInfo_t &info, ControlField_t field )
|
||||
{
|
||||
const FlexOpInfo_t& flexInfo = s_pFlexOpInfo[ ( field == CONTROL_VALUE ) ? 0 : 1 ];
|
||||
|
||||
// Get the global flex controller name and index
|
||||
const FlexControllerInfo_t& fcInfo = m_FlexControllerInfo[ info.m_pControllerIndex[field] ];
|
||||
|
||||
// Create operator which drives facial flex setting
|
||||
CDmeGlobalFlexControllerOperator *pFlexControllerOp = pGameModel->AddGlobalFlexController(
|
||||
fcInfo.m_pFlexControlName, fcInfo.m_nGlobalIndex );
|
||||
|
||||
// Create a channel which passes from the control value to the global flex controller
|
||||
char pName[ 256 ];
|
||||
Q_snprintf( pName, sizeof( pName ), "%s_flex_channel", fcInfo.m_pFlexControlName );
|
||||
info.m_ppControlChannel[field] = pChannelsClip->CreatePassThruConnection( pName,
|
||||
info.m_pControl, flexInfo.m_pControlAttributeName, pFlexControllerOp, "flexWeight" );
|
||||
|
||||
// NOTE: The animation set slider panel looks for these custom attributes
|
||||
Q_snprintf( pName, sizeof(pName), "%schannel", flexInfo.m_pControlLinkAttributeName );
|
||||
info.m_pControl->SetValue( pName, info.m_ppControlChannel[field] );
|
||||
|
||||
// Switch the channel into play mode by default
|
||||
info.m_ppControlChannel[field]->SetMode( CM_PLAY );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a flex controller and a channel connecting it to stereo controls
|
||||
//-----------------------------------------------------------------------------
|
||||
static const char *s_pStereoOutputPrefix[2] =
|
||||
{
|
||||
"right",
|
||||
"left",
|
||||
};
|
||||
|
||||
static const char *s_pStereoInputPrefix[2] =
|
||||
{
|
||||
"value",
|
||||
"balance",
|
||||
};
|
||||
|
||||
void CFlexControlBuilder::BuildStereoFlexControllerOps( CDmeAnimationSet *pAnimationSet,
|
||||
CDmeGameModel *pGameModel, CDmeChannelsClip *pChannelsClip, ControlInfo_t &info )
|
||||
{
|
||||
// Create an operator which converts value/balance to left/right
|
||||
CDmrElementArray< CDmeOperator > operators = pAnimationSet->GetOperators();
|
||||
CDmeBalanceToStereoCalculatorOperator *pStereoCalcOp =
|
||||
CreateElement< CDmeBalanceToStereoCalculatorOperator >( info.m_pControlName, pAnimationSet->GetFileId() );
|
||||
operators.AddToTail( pStereoCalcOp->GetHandle() );
|
||||
|
||||
pStereoCalcOp->SetValue< float >( "value", info.m_pDefaultValue[CONTROL_VALUE] );
|
||||
pStereoCalcOp->SetValue< float >( "balance", info.m_pDefaultValue[CONTROL_BALANCE] );
|
||||
|
||||
// Connect channels from animation set controls to balance operator to flex controller operators
|
||||
char pChannelName[ 256 ];
|
||||
char pResultName[ 256 ];
|
||||
for ( int i = 0; i < 2; ++i )
|
||||
{
|
||||
// Get the global flex controller name and index
|
||||
const FlexControllerInfo_t& fcInfo = m_FlexControllerInfo[ info.m_pControllerIndex[i] ];
|
||||
|
||||
// Create an operator which drives facial flex setting
|
||||
CDmeGlobalFlexControllerOperator *pFlexControllerOp = pGameModel->AddGlobalFlexController(
|
||||
fcInfo.m_pFlexControlName, fcInfo.m_nGlobalIndex );
|
||||
|
||||
// Now create a channel which connects the output of the stereo op to the flex controller op
|
||||
Q_snprintf( pResultName, sizeof( pResultName ), "result_%s", s_pStereoOutputPrefix[ i ] );
|
||||
Q_snprintf( pChannelName, sizeof( pChannelName ), "%s_flex_channel", fcInfo.m_pFlexControlName );
|
||||
pChannelsClip->CreatePassThruConnection( pChannelName, pStereoCalcOp,
|
||||
pResultName, pFlexControllerOp, "flexWeight" );
|
||||
|
||||
// Create a channel which connects the control to the input of the stereo op
|
||||
Q_snprintf( pChannelName, sizeof( pChannelName ), "%s_%s_channel", info.m_pControlName, s_pStereoInputPrefix[ i ] );
|
||||
info.m_ppControlChannel[i] = pChannelsClip->CreatePassThruConnection( pChannelName,
|
||||
info.m_pControl, s_pStereoInputPrefix[ i ], pStereoCalcOp, s_pStereoInputPrefix[ i ] );
|
||||
|
||||
// NOTE: The animation set slider panel looks for these custom attributes
|
||||
Q_snprintf( pChannelName, sizeof(pChannelName), "%schannel", s_pStereoInputPrefix[ i ] );
|
||||
info.m_pControl->SetValue( pChannelName, info.m_ppControlChannel[i] );
|
||||
|
||||
// Switch the channel into play mode by default
|
||||
info.m_ppControlChannel[i]->SetMode( CM_PLAY );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Build the infrastructure of the ops that connect that control to the dmegamemodel
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::AttachControlsToGameModel( CDmeAnimationSet *pAnimationSet,
|
||||
CDmeGameModel *pGameModel, CDmeChannelsClip *pChannelsClip )
|
||||
{
|
||||
// Build the infrastructure of the ops that connect that control to the dmegamemodel
|
||||
int c = m_ControlInfo.Count();
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
ControlInfo_t &info = m_ControlInfo[i];
|
||||
if ( info.m_bIsStereo )
|
||||
{
|
||||
BuildStereoFlexControllerOps( pAnimationSet, pGameModel, pChannelsClip, info );
|
||||
}
|
||||
else
|
||||
{
|
||||
BuildFlexControllerOps( pGameModel, pChannelsClip, info, CONTROL_VALUE );
|
||||
}
|
||||
|
||||
if ( info.m_bIsMulti )
|
||||
{
|
||||
BuildFlexControllerOps( pGameModel, pChannelsClip, info, CONTROL_MULTILEVEL );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Initializes the fields of a flex control
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::InitializeFlexControl( ControlInfo_t &info )
|
||||
{
|
||||
CDmElement *pControl = info.m_pControl;
|
||||
|
||||
// Remove these, if they exist...
|
||||
for ( int i = 0; i < CONTROL_CHANNEL_ATTRIBUTE_COUNT; ++i )
|
||||
{
|
||||
pControl->RemoveAttribute( s_pChannelControls[i] );
|
||||
}
|
||||
|
||||
// Force these to always be up-to-date
|
||||
pControl->SetValue< bool >( "combo", info.m_bIsStereo );
|
||||
pControl->SetValue< bool >( "multi", info.m_bIsMulti );
|
||||
pControl->SetValue< float >( "defaultValue", info.m_pDefaultValue[CONTROL_VALUE] );
|
||||
pControl->SetValue< float >( "defaultBalance", info.m_pDefaultValue[CONTROL_BALANCE] );
|
||||
pControl->SetValue< float >( "defaultMultilevel", info.m_pDefaultValue[CONTROL_MULTILEVEL] );
|
||||
|
||||
// These can keep their value if they already exist
|
||||
pControl->InitValue< float >( "value", info.m_pDefaultValue[CONTROL_VALUE] );
|
||||
if ( info.m_bIsStereo )
|
||||
{
|
||||
pControl->InitValue< float >( "balance", info.m_pDefaultValue[CONTROL_BALANCE] );
|
||||
}
|
||||
else
|
||||
{
|
||||
pControl->RemoveAttribute( "balance" );
|
||||
}
|
||||
if ( info.m_bIsMulti )
|
||||
{
|
||||
pControl->InitValue< float >( "multilevel", info.m_pDefaultValue[CONTROL_MULTILEVEL] );
|
||||
}
|
||||
else
|
||||
{
|
||||
pControl->RemoveAttribute( "multilevel" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates all controls for flexes
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::CreateFlexControls( CDmeAnimationSet *pAnimationSet )
|
||||
{
|
||||
// Create a facial control for all input controls
|
||||
int c = m_ControlInfo.Count();
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
ControlInfo_t &info = m_ControlInfo[i];
|
||||
|
||||
// Check to see if the animation set already has the control
|
||||
info.m_pControl = pAnimationSet->FindOrAddControl( info.m_pControlName );
|
||||
|
||||
// Now initialize the fields of the flex control
|
||||
InitializeFlexControl( info );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attaches existing logs and sets default values for logs
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::SetupLogs( CDmeChannelsClip *pChannelsClip, bool bUseExistingLogs )
|
||||
{
|
||||
DmeTime_t targetOffset;
|
||||
double flTargetScale;
|
||||
ComputeChannelTimeTransform( &targetOffset, &flTargetScale, pChannelsClip );
|
||||
double flOOTargetScale = ( flTargetScale != 0.0 ) ? 1.0 / flTargetScale : 1.0;
|
||||
|
||||
// Build the infrastructure of the ops that connect that control to the dmegamemodel
|
||||
int c = m_ControlInfo.Count();
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
ControlInfo_t &info = m_ControlInfo[i];
|
||||
for ( int j = 0; j < CONTROL_FIELD_COUNT; ++j )
|
||||
{
|
||||
// Can happen for non-multi or non-stereo controls
|
||||
if ( !info.m_ppControlChannel[j] )
|
||||
continue;
|
||||
|
||||
// Replace the existing log if we need to
|
||||
CDmeFloatLog *pFloatLog = CastElement< CDmeFloatLog >( info.m_ppControlChannel[j]->GetLog() );
|
||||
if ( bUseExistingLogs && info.m_pExistingLog[j].m_pLog )
|
||||
{
|
||||
info.m_ppControlChannel[j]->SetLog( info.m_pExistingLog[j].m_pLog );
|
||||
DestroyElement( pFloatLog );
|
||||
pFloatLog = info.m_pExistingLog[j].m_pLog;
|
||||
|
||||
// Apply transform to get the log into the space of the current channel
|
||||
double flTotalScale = info.m_pExistingLog[j].m_flGlobalScale * flOOTargetScale;
|
||||
DmeTime_t totalOffset = info.m_pExistingLog[j].m_GlobalOffset - targetOffset;
|
||||
totalOffset.SetSeconds( totalOffset.GetSeconds() * flOOTargetScale );
|
||||
pFloatLog->ScaleBiasKeyTimes( flTotalScale, totalOffset );
|
||||
}
|
||||
|
||||
// Set the default value for this log
|
||||
pFloatLog->SetDefaultValue( info.m_pDefaultValue[j] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main entry point for creating flex animation set controls
|
||||
//-----------------------------------------------------------------------------
|
||||
void CFlexControlBuilder::CreateAnimationSetControls( CDmeFilmClip *pMovie, CDmeAnimationSet *pAnimationSet,
|
||||
CDmeGameModel *pGameModel, CDmeFilmClip *pSourceClip, CDmeChannelsClip *pDestClip, bool bUseExistingLogs )
|
||||
{
|
||||
m_pMovie = pMovie;
|
||||
|
||||
FixupExistingFlexControlLogList( pSourceClip, pGameModel );
|
||||
|
||||
// First, look at the current mdl and determine what are its low-level flexcontrollers
|
||||
// [these are the outputs eventually driven by the animation set controls]
|
||||
BuildDesiredFlexControlList( pGameModel );
|
||||
|
||||
// Next, based on the list of low-level flexcontrollers, determine a high-level set of input controls
|
||||
BuildDesiredControlList( pGameModel );
|
||||
|
||||
// Next look at what the animation set currently thinks are the input controls + low-level flexcontrollers
|
||||
// and remove the unused ones
|
||||
RemoveUnusedExistingFlexControllers( pGameModel );
|
||||
|
||||
RemoveUnusedControlsAndChannels( pAnimationSet, pDestClip );
|
||||
|
||||
if ( bUseExistingLogs )
|
||||
{
|
||||
// Look at the current input controls + low-level flexcontrollers
|
||||
// and grab logs that drive them so we can apply them to the new controls
|
||||
BuildExistingFlexControlLogList( pSourceClip, pGameModel );
|
||||
}
|
||||
|
||||
// Create the input controls we decided we needed in BuildDesiredControlList
|
||||
CreateFlexControls( pAnimationSet );
|
||||
|
||||
// Build channels + control logis attaching the input controls to the low level flex controls
|
||||
AttachControlsToGameModel( pAnimationSet, pGameModel, pDestClip );
|
||||
|
||||
// Attach existing logs to the new input controls created in CreateFlexControls
|
||||
SetupLogs( pDestClip, bUseExistingLogs );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Initialize default global flex controller
|
||||
//-----------------------------------------------------------------------------
|
||||
void SetupDefaultFlexController()
|
||||
{
|
||||
g_pGlobalFlexController = &s_GlobalFlexController;
|
||||
}
|
891
sfmobjects/sfmanimationsetutils.cpp
Normal file
891
sfmobjects/sfmanimationsetutils.cpp
Normal file
@ -0,0 +1,891 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// NOTE: This is a cut-and-paste hack job to get animation set construction
|
||||
// working from a commandline tool. It came from tools/ifm/createsfmanimation.cpp
|
||||
// This file needs to die almost immediately + be replaced with a better solution
|
||||
// that can be used both by the sfm + sfmgen.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "sfmobjects/sfmanimationsetutils.h"
|
||||
#include "movieobjects/dmechannel.h"
|
||||
#include "movieobjects/dmeclip.h"
|
||||
#include "movieobjects/dmetrackgroup.h"
|
||||
#include "movieobjects/dmetrack.h"
|
||||
#include "movieobjects/dmecamera.h"
|
||||
#include "movieobjects/dmetimeselection.h"
|
||||
#include "movieobjects/dmeanimationset.h"
|
||||
#include "movieobjects/dmegamemodel.h"
|
||||
#include "sfmobjects/flexcontrolbuilder.h"
|
||||
#include "tier3/tier3.h"
|
||||
#include "bone_setup.h"
|
||||
#include "vstdlib/random.h"
|
||||
#include "tier1/KeyValues.h"
|
||||
#include "filesystem.h"
|
||||
#include "movieobjects/timeutils.h"
|
||||
|
||||
|
||||
#define ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE "cfg/SFM_DefaultAnimationGroups.txt"
|
||||
#define STANDARD_CHANNEL_TRACK_GROUP "channelTrackGroup"
|
||||
#define STANDARD_ANIMATIONSET_CHANNELS_TRACK "animSetEditorChannels"
|
||||
#define CLIP_PREROLL_TIME DmeTime_t( 5.0f )
|
||||
#define CLIP_POSTROLL_TIME DmeTime_t( 5.0f )
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates channels clip for the animation set
|
||||
//-----------------------------------------------------------------------------
|
||||
static CDmeChannelsClip* CreateChannelsClip( CDmeAnimationSet *pAnimationSet, CDmeFilmClip *pOwnerClip )
|
||||
{
|
||||
CDmeTrackGroup *pTrackGroup = pOwnerClip->FindOrAddTrackGroup( "channelTrackGroup" );
|
||||
if ( !pTrackGroup )
|
||||
{
|
||||
Assert( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CDmeTrack *pAnimSetEditorTrack = pTrackGroup->FindOrAddTrack( "animSetEditorChannels", DMECLIP_CHANNEL );
|
||||
Assert( pAnimSetEditorTrack );
|
||||
|
||||
CDmeChannelsClip *pChannelsClip = CreateElement< CDmeChannelsClip >( pAnimationSet->GetName(), pAnimationSet->GetFileId() );
|
||||
pAnimSetEditorTrack->AddClip( pChannelsClip );
|
||||
|
||||
DmeTime_t childMediaTime = pOwnerClip->GetStartInChildMediaTime();
|
||||
pChannelsClip->SetStartTime( childMediaTime - CLIP_PREROLL_TIME );
|
||||
DmeTime_t childMediaDuration = pOwnerClip->ToChildMediaDuration( pOwnerClip->GetDuration() );
|
||||
pChannelsClip->SetDuration( childMediaDuration + CLIP_PREROLL_TIME + CLIP_POSTROLL_TIME );
|
||||
return pChannelsClip;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a constant valued log
|
||||
//-----------------------------------------------------------------------------
|
||||
template < class T >
|
||||
CDmeChannel *CreateConstantValuedLog( CDmeChannelsClip *channelsClip, const char *basename, const char *pName, CDmElement *pToElement, const char *pToAttr, const T &value )
|
||||
{
|
||||
char name[ 256 ];
|
||||
Q_snprintf( name, sizeof( name ), "%s_%s channel", basename, pName );
|
||||
|
||||
CDmeChannel *pChannel = CreateElement< CDmeChannel >( name, channelsClip->GetFileId() );
|
||||
pChannel->SetMode( CM_PLAY );
|
||||
pChannel->CreateLog( CDmAttributeInfo< T >::AttributeType() );
|
||||
pChannel->SetOutput( pToElement, pToAttr );
|
||||
pChannel->GetLog()->SetValueThreshold( 0.0f );
|
||||
|
||||
((CDmeTypedLog< T > *)pChannel->GetLog())->InsertKey( DmeTime_t( 0 ), value );
|
||||
|
||||
channelsClip->m_Channels.AddToTail( pChannel );
|
||||
|
||||
return pChannel;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Create channels for transform data
|
||||
//-----------------------------------------------------------------------------
|
||||
static void CreateTransformChannels( CDmeTransform *pTransform, const char *pBaseName, int bi, CDmeChannelsClip *pChannelsClip )
|
||||
{
|
||||
char name[ 256 ];
|
||||
|
||||
// create, connect and cache bonePos channel
|
||||
Q_snprintf( name, sizeof( name ), "%s_bonePos channel %d", pBaseName, bi );
|
||||
CDmeChannel *pPosChannel = CreateElement< CDmeChannel >( name, pChannelsClip->GetFileId() );
|
||||
pPosChannel->SetMode( CM_PLAY );
|
||||
pPosChannel->CreateLog( AT_VECTOR3 );
|
||||
pPosChannel->SetOutput( pTransform, "position" );
|
||||
pPosChannel->GetLog()->SetValueThreshold( 0.0f );
|
||||
pChannelsClip->m_Channels.AddToTail( pPosChannel );
|
||||
|
||||
// create, connect and cache boneRot channel
|
||||
Q_snprintf( name, sizeof( name ), "%s_boneRot channel %d", pBaseName, bi );
|
||||
CDmeChannel *pRotChannel = CreateElement< CDmeChannel >( name, pChannelsClip->GetFileId() );
|
||||
pRotChannel->SetMode( CM_PLAY );
|
||||
pRotChannel->CreateLog( AT_QUATERNION );
|
||||
pRotChannel->SetOutput( pTransform, "orientation" );
|
||||
pRotChannel->GetLog()->SetValueThreshold( 0.0f );
|
||||
pChannelsClip->m_Channels.AddToTail( pRotChannel );
|
||||
}
|
||||
|
||||
static void CreateAnimationLogs( CDmeChannelsClip *channelsClip, CDmeGameModel *pModel, studiohdr_t *pStudioHdr, const char *basename, int sequence, float flStartTime, float flDuration, float flTimeStep = 0.015f )
|
||||
{
|
||||
Assert( pModel );
|
||||
Assert( pStudioHdr );
|
||||
|
||||
CStudioHdr hdr( pStudioHdr, g_pMDLCache );
|
||||
|
||||
if ( sequence >= hdr.GetNumSeq() )
|
||||
{
|
||||
sequence = 0;
|
||||
}
|
||||
|
||||
int numbones = hdr.numbones();
|
||||
|
||||
// make room for bones
|
||||
CUtlVector< CDmeDag* > dags;
|
||||
CUtlVector< CDmeChannel * > poschannels;
|
||||
CUtlVector< CDmeChannel * > rotchannels;
|
||||
|
||||
dags.EnsureCapacity( numbones );
|
||||
poschannels.EnsureCapacity( numbones );
|
||||
rotchannels.EnsureCapacity( numbones );
|
||||
|
||||
Vector pos[ MAXSTUDIOBONES ];
|
||||
Quaternion q[ MAXSTUDIOBONES ];
|
||||
|
||||
float poseparameter[ MAXSTUDIOPOSEPARAM ];
|
||||
for ( int pp = 0; pp < MAXSTUDIOPOSEPARAM; ++pp )
|
||||
{
|
||||
poseparameter[ pp ] = 0.0f;
|
||||
}
|
||||
|
||||
float flSequenceDuration = Studio_Duration( &hdr, sequence, poseparameter );
|
||||
mstudioseqdesc_t &seqdesc = hdr.pSeqdesc( sequence );
|
||||
|
||||
bool created = false;
|
||||
|
||||
for ( float t = flStartTime; t <= flStartTime + flDuration; t += flTimeStep )
|
||||
{
|
||||
int bi;
|
||||
|
||||
if ( t > flStartTime + flDuration )
|
||||
t = flStartTime + flDuration;
|
||||
|
||||
float flCycle = t / flSequenceDuration;
|
||||
|
||||
if ( seqdesc.flags & STUDIO_LOOPING )
|
||||
{
|
||||
flCycle = flCycle - (int)flCycle;
|
||||
if (flCycle < 0) flCycle += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
flCycle = max( 0.f, min( flCycle, 0.9999f ) );
|
||||
}
|
||||
|
||||
if ( !created )
|
||||
{
|
||||
created = true;
|
||||
|
||||
// create, connect and cache each bone's pos and rot channels
|
||||
for ( bi = 0; bi < numbones; ++bi )
|
||||
{
|
||||
int nCount = channelsClip->m_Channels.Count();
|
||||
|
||||
CDmeTransform *pTransform = pModel->GetBone( bi );
|
||||
CreateTransformChannels( pTransform, basename, bi, channelsClip );
|
||||
|
||||
CDmeChannel *pPosChannel = channelsClip->m_Channels[ nCount ];
|
||||
CDmeChannel *pRotChannel = channelsClip->m_Channels[ nCount+1 ];
|
||||
poschannels.AddToTail( pPosChannel );
|
||||
rotchannels.AddToTail( pRotChannel );
|
||||
}
|
||||
}
|
||||
|
||||
// Set up skeleton
|
||||
IBoneSetup boneSetup( &hdr, BONE_USED_BY_ANYTHING, poseparameter );
|
||||
boneSetup.InitPose( pos, q );
|
||||
boneSetup.AccumulatePose( pos, q, sequence, flCycle, 1.0f, t, NULL );
|
||||
|
||||
// Copy bones into recording logs
|
||||
for ( bi = 0 ; bi < numbones; ++bi )
|
||||
{
|
||||
((CDmeVector3Log *)poschannels[ bi ]->GetLog())->InsertKey( DmeTime_t( t ), pos[ bi ] );
|
||||
((CDmeQuaternionLog *)rotchannels[ bi ]->GetLog())->InsertKey( DmeTime_t( t ), q[ bi ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static CDmeChannelsClip *FindChannelsClipTargetingDmeGameModel( CDmeFilmClip *pClip, CDmeGameModel *pGameModel )
|
||||
{
|
||||
uint nBoneCount = pGameModel->NumBones();
|
||||
CDmeTransform *pGameModelTransform = pGameModel->GetTransform();
|
||||
|
||||
int gc = pClip->GetTrackGroupCount();
|
||||
for ( int i = 0; i < gc; ++i )
|
||||
{
|
||||
CDmeTrackGroup *pTrackGroup = pClip->GetTrackGroup( i );
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_START( CDmeChannelsClip, pTrackGroup, pTrack, pChannelsClip )
|
||||
|
||||
if ( FindChannelTargetingElement( pChannelsClip, pGameModel ) )
|
||||
return pChannelsClip;
|
||||
|
||||
if ( FindChannelTargetingElement( pChannelsClip, pGameModelTransform ) )
|
||||
return pChannelsClip;
|
||||
|
||||
for ( uint j = 0; j < nBoneCount; ++j )
|
||||
{
|
||||
if ( FindChannelTargetingElement( pChannelsClip, pGameModel->GetBone( j ) ) )
|
||||
return pChannelsClip;
|
||||
}
|
||||
|
||||
DMETRACKGROUP_FOREACH_CLIP_TYPE_END()
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void RetimeLogData( CDmeChannelsClip *pSrcChannelsClip, CDmeChannelsClip *pDstChannelsClip, CDmeLog *pLog )
|
||||
{
|
||||
float srcScale = pSrcChannelsClip->GetTimeScale();
|
||||
float dstScale = pDstChannelsClip->GetTimeScale();
|
||||
DmeTime_t srcStart = pSrcChannelsClip->GetStartTime();
|
||||
DmeTime_t dstStart = pDstChannelsClip->GetStartTime();
|
||||
DmeTime_t srcOffset = pSrcChannelsClip->GetTimeOffset();
|
||||
DmeTime_t dstOffset = pDstChannelsClip->GetTimeOffset();
|
||||
srcOffset -= srcStart;
|
||||
dstOffset -= dstStart;
|
||||
if ( srcScale != dstScale || srcOffset != dstOffset )
|
||||
{
|
||||
// for speed, I pulled out the math converting out of one timeframe into another:
|
||||
// t = (t/f0-o0+s0 -s1+o1)*f1
|
||||
// = t * f1/f0 + f1 * (o1-o0-s1+s0)
|
||||
float scale = dstScale / srcScale;
|
||||
DmeTime_t offset = dstScale * ( dstOffset - srcOffset );
|
||||
int nKeys = pLog->GetKeyCount();
|
||||
for ( int i = 0; i < nKeys; ++i )
|
||||
{
|
||||
DmeTime_t keyTime = pLog->GetKeyTime( i );
|
||||
keyTime = keyTime * scale + offset;
|
||||
pLog->SetKeyTime( i, keyTime );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Once bones have been setup and flex channels moved, the only things left should be:
|
||||
// a channel logging the model's "visibility" state
|
||||
// a channel logging the model's "sequence"
|
||||
// a channel loggint the model's "viewtarget" position
|
||||
//-----------------------------------------------------------------------------
|
||||
static void TransferRemainingChannels( CDmeFilmClip *shot, CDmeChannelsClip *destClip, CDmeChannelsClip *srcClip )
|
||||
{
|
||||
if ( srcClip == destClip )
|
||||
return;
|
||||
|
||||
int channelsCount = srcClip->m_Channels.Count();
|
||||
for ( int i = 0; i < channelsCount; ++i )
|
||||
{
|
||||
// Remove channel from channels clip
|
||||
CDmeChannel *channel = srcClip->m_Channels[ i ];
|
||||
Assert( channel );
|
||||
if ( !channel )
|
||||
continue;
|
||||
|
||||
Msg( "Transferring '%s'\n", channel->GetName() );
|
||||
|
||||
destClip->m_Channels.AddToTail( channel );
|
||||
channel->SetMode( CM_PLAY );
|
||||
|
||||
// Transfer the logs over to the
|
||||
CDmeLog *log = channel->GetLog();
|
||||
if ( log )
|
||||
{
|
||||
RetimeLogData( srcClip, destClip, log );
|
||||
}
|
||||
}
|
||||
|
||||
srcClip->m_Channels.RemoveAll();
|
||||
|
||||
// Now find the track which contains the srcClip and remove the srcClip from the track
|
||||
for ( DmAttributeReferenceIterator_t it = g_pDataModel->FirstAttributeReferencingElement( srcClip->GetHandle() );
|
||||
it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID;
|
||||
it = g_pDataModel->NextAttributeReferencingElement( it ) )
|
||||
{
|
||||
CDmAttribute *attr = g_pDataModel->GetAttribute( it );
|
||||
Assert( attr );
|
||||
CDmElement *element = attr->GetOwner();
|
||||
Assert( element );
|
||||
if ( !element )
|
||||
continue;
|
||||
|
||||
CDmeTrack *t = CastElement< CDmeTrack >( element );
|
||||
if ( !t )
|
||||
continue;
|
||||
|
||||
t->RemoveClip( srcClip );
|
||||
g_pDataModel->DestroyElement( srcClip->GetHandle() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void SetupBoneTransform( CDmeFilmClip *shot, CDmeChannelsClip *srcChannelsClip, CDmeChannelsClip *channelsClip,
|
||||
CDmElement *control, CDmeGameModel *gameModel, const char *basename, studiohdr_t *hdr, int bonenum, const char *boneName, bool bAttachToGameRecording )
|
||||
{
|
||||
const char *channelNames[] = { "position", "orientation" };
|
||||
const char *valueNames[] = { "valuePosition", "valueOrientation" };
|
||||
const char *suffix[] = { "Pos", "Rot" };
|
||||
|
||||
DmAttributeType_t channelTypes[] = { AT_VECTOR3, AT_QUATERNION };
|
||||
int i;
|
||||
|
||||
CDmeTransform *pBoneTxForm = gameModel->GetBone( bonenum );
|
||||
|
||||
for ( i = 0; i < 2 ; ++i )
|
||||
{
|
||||
char szName[ 512 ];
|
||||
Q_snprintf( szName, sizeof( szName ), "%s_bone%s %d", basename, suffix[ i ], bonenum );
|
||||
|
||||
CDmeChannel *pAttachChannel = NULL;
|
||||
if ( srcChannelsClip )
|
||||
{
|
||||
pAttachChannel = FindChannelTargetingElement( srcChannelsClip, pBoneTxForm, channelNames[ i ] );
|
||||
}
|
||||
|
||||
if ( !pAttachChannel )
|
||||
{
|
||||
// Create one
|
||||
pAttachChannel = CreateElement< CDmeChannel >( szName, channelsClip->GetFileId() );
|
||||
Assert( pAttachChannel );
|
||||
pAttachChannel->SetOutput( pBoneTxForm, channelNames[ i ], 0 );
|
||||
}
|
||||
|
||||
if ( !pAttachChannel )
|
||||
continue;
|
||||
|
||||
if ( bAttachToGameRecording && srcChannelsClip )
|
||||
{
|
||||
// Remove channel from channels clip
|
||||
int idx = srcChannelsClip->m_Channels.Find( pAttachChannel->GetHandle() );
|
||||
if ( idx != srcChannelsClip->m_Channels.InvalidIndex() )
|
||||
{
|
||||
srcChannelsClip->m_Channels.Remove( idx );
|
||||
}
|
||||
channelsClip->m_Channels.AddToTail( pAttachChannel );
|
||||
}
|
||||
|
||||
control->SetValue( channelNames[ i ], pAttachChannel );
|
||||
control->AddAttribute( valueNames[ i ], channelTypes[ i ] );
|
||||
|
||||
CDmeLog *pOriginalLog = pAttachChannel->GetLog();
|
||||
|
||||
pAttachChannel->SetMode( CM_PLAY );
|
||||
pAttachChannel->SetInput( control, valueNames[ i ] );
|
||||
|
||||
// Transfer the logs over to the
|
||||
if ( bAttachToGameRecording && pOriginalLog && srcChannelsClip )
|
||||
{
|
||||
CDmeLog *pNewLog = pAttachChannel->GetLog();
|
||||
if ( pNewLog != pOriginalLog )
|
||||
{
|
||||
pAttachChannel->SetLog( pOriginalLog );
|
||||
g_pDataModel->DestroyElement( pNewLog->GetHandle() );
|
||||
}
|
||||
|
||||
DmeTime_t tLogToGlobal[ 2 ];
|
||||
|
||||
Assert(0);
|
||||
// NOTE: Fix the next 2 lines to look like createsfmanimation.cpp
|
||||
DmeTime_t curtime = DMETIME_ZERO; //doc->GetTime();
|
||||
DmeTime_t cmt = DMETIME_ZERO; //doc->ToCurrentMediaTime( curtime, false );
|
||||
DmeTime_t channelscliptime = shot->ToChildMediaTime( cmt, false );
|
||||
|
||||
DmeTime_t logtime = channelsClip->ToChildMediaTime( channelscliptime, false );
|
||||
|
||||
tLogToGlobal[ 0 ] = curtime - logtime;
|
||||
|
||||
DmeTime_t attachlogtime = srcChannelsClip->ToChildMediaTime( channelscliptime, false );
|
||||
|
||||
tLogToGlobal[ 1 ] = curtime - attachlogtime;
|
||||
|
||||
DmeTime_t offset = tLogToGlobal[ 1 ] - tLogToGlobal[ 0 ];
|
||||
|
||||
if ( DMETIME_ZERO != offset )
|
||||
{
|
||||
int c = pOriginalLog->GetKeyCount();
|
||||
for ( int iLog = 0; iLog < c; ++iLog )
|
||||
{
|
||||
DmeTime_t keyTime = pOriginalLog->GetKeyTime( iLog );
|
||||
keyTime += offset;
|
||||
pOriginalLog->SetKeyTime( iLog, keyTime );
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( pOriginalLog )
|
||||
{
|
||||
pOriginalLog->ClearKeys();
|
||||
}
|
||||
|
||||
CDmeLog *log = pAttachChannel->GetLog();
|
||||
if ( !log )
|
||||
{
|
||||
log = pAttachChannel->CreateLog( channelTypes[ i ] );
|
||||
}
|
||||
|
||||
log->SetValueThreshold( 0.0f );
|
||||
if ( bAttachToGameRecording )
|
||||
{
|
||||
Vector pos;
|
||||
Quaternion rot;
|
||||
|
||||
matrix3x4_t matrix;
|
||||
pBoneTxForm->GetTransform( matrix );
|
||||
MatrixAngles( matrix, rot, pos );
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, pos );
|
||||
}
|
||||
else
|
||||
{
|
||||
((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, rot );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
CStudioHdr studiohdr( hdr, g_pMDLCache );
|
||||
|
||||
Vector pos[ MAXSTUDIOBONES ];
|
||||
Quaternion q[ MAXSTUDIOBONES ];
|
||||
float poseparameter[ MAXSTUDIOPOSEPARAM ];
|
||||
for ( int pp = 0; pp < MAXSTUDIOPOSEPARAM; ++pp )
|
||||
{
|
||||
poseparameter[ pp ] = 0.0f;
|
||||
}
|
||||
|
||||
// Set up skeleton
|
||||
IBoneSetup boneSetup( &studiohdr, BONE_USED_BY_ANYTHING, poseparameter );
|
||||
boneSetup.InitPose( pos, q );
|
||||
boneSetup.AccumulatePose( pos, q, 0, 0.0f, 1.0f, 0.0f, NULL );
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, pos[ bonenum ] );
|
||||
pBoneTxForm->SetPosition( pos[ bonenum ]);
|
||||
}
|
||||
else
|
||||
{
|
||||
((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, q[ bonenum ] );
|
||||
pBoneTxForm->SetOrientation( q[ bonenum ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets up the root transform
|
||||
//-----------------------------------------------------------------------------
|
||||
static void SetupRootTransform( CDmeFilmClip *shot, CDmeChannelsClip *srcChannelsClip,
|
||||
CDmeChannelsClip *channelsClip, CDmElement *control, CDmeGameModel *gameModel, const char *basename, bool bAttachToGameRecording )
|
||||
{
|
||||
char *channelNames[] = { "position", "orientation" };
|
||||
char *valueNames[] = { "valuePosition", "valueOrientation" };
|
||||
DmAttributeType_t channelTypes[] = { AT_VECTOR3, AT_QUATERNION };
|
||||
const char *suffix[] = { "Pos", "Rot" };
|
||||
DmAttributeType_t logType[] = { AT_VECTOR3, AT_QUATERNION };
|
||||
|
||||
int i;
|
||||
for ( i = 0; i < 2 ; ++i )
|
||||
{
|
||||
char szName[ 512 ];
|
||||
Q_snprintf( szName, sizeof( szName ), "%s_root%s channel", basename, suffix[ i ] );
|
||||
|
||||
CDmeChannel *pAttachChannel = NULL;
|
||||
if ( srcChannelsClip )
|
||||
{
|
||||
pAttachChannel = FindChannelTargetingElement( srcChannelsClip, gameModel->GetTransform(), channelNames[ i ] );
|
||||
}
|
||||
|
||||
if ( !pAttachChannel )
|
||||
{
|
||||
// Create one
|
||||
pAttachChannel = CreateElement< CDmeChannel >( szName, channelsClip->GetFileId() );
|
||||
Assert( pAttachChannel );
|
||||
pAttachChannel->SetOutput( gameModel->GetTransform(), channelNames[ i ], 0 );
|
||||
}
|
||||
|
||||
if ( bAttachToGameRecording && srcChannelsClip )
|
||||
{
|
||||
// Remove channel from channels clip
|
||||
int idx = srcChannelsClip->m_Channels.Find( pAttachChannel->GetHandle() );
|
||||
if ( idx != srcChannelsClip->m_Channels.InvalidIndex() )
|
||||
{
|
||||
srcChannelsClip->m_Channels.Remove( idx );
|
||||
}
|
||||
channelsClip->m_Channels.AddToTail( pAttachChannel );
|
||||
}
|
||||
|
||||
control->SetValue( channelNames[ i ], pAttachChannel );
|
||||
control->AddAttribute( valueNames[ i ], channelTypes[ i ] );
|
||||
|
||||
CDmeLog *pOriginalLog = pAttachChannel->GetLog();
|
||||
|
||||
pAttachChannel->SetMode( CM_PLAY );
|
||||
pAttachChannel->SetInput( control, valueNames[ i ] );
|
||||
|
||||
if ( bAttachToGameRecording && pOriginalLog && srcChannelsClip )
|
||||
{
|
||||
CDmeLog *pNewLog = pAttachChannel->GetLog();
|
||||
if ( pNewLog != pOriginalLog )
|
||||
{
|
||||
pAttachChannel->SetLog( pOriginalLog );
|
||||
g_pDataModel->DestroyElement( pNewLog->GetHandle() );
|
||||
}
|
||||
|
||||
RetimeLogData( srcChannelsClip, channelsClip, pOriginalLog );
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( !pOriginalLog );
|
||||
CDmeLog *log = pAttachChannel->GetLog();
|
||||
if ( !log )
|
||||
{
|
||||
log = pAttachChannel->CreateLog( logType[ i ] );
|
||||
}
|
||||
|
||||
log->SetValueThreshold( 0.0f );
|
||||
|
||||
Vector vecPos;
|
||||
Quaternion qOrientation;
|
||||
|
||||
matrix3x4_t txform;
|
||||
gameModel->GetTransform()->GetTransform( txform );
|
||||
|
||||
MatrixAngles( txform, qOrientation, vecPos );
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
((CDmeTypedLog< Vector > *)log)->SetKey( DMETIME_ZERO, vecPos );
|
||||
}
|
||||
else
|
||||
{
|
||||
((CDmeTypedLog< Quaternion > *)log)->SetKey( DMETIME_ZERO, qOrientation );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates preset groups for new animation sets
|
||||
//-----------------------------------------------------------------------------
|
||||
static bool ShouldRandomize( const char *name )
|
||||
{
|
||||
if ( !Q_stricmp( name, "eyes_updown" ) )
|
||||
return false;
|
||||
if ( !Q_stricmp( name, "eyes_rightleft" ) )
|
||||
return false;
|
||||
if ( !Q_stricmp( name, "lip_bite" ) )
|
||||
return false;
|
||||
if ( !Q_stricmp( name, "blink" ) )
|
||||
return false;
|
||||
if ( Q_stristr( name, "sneer" ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CreateProceduralPreset( CDmePresetGroup *pPresetGroup, const char *pPresetName, const CDmaElementArray< CDmElement > &controls, bool bIdentity, float flForceValue = 0.5f )
|
||||
{
|
||||
CDmePreset *pPreset = pPresetGroup->FindOrAddPreset( pPresetName );
|
||||
|
||||
int c = controls.Count();
|
||||
for ( int i = 0; i < c ; ++i )
|
||||
{
|
||||
CDmElement *pControl = controls[ i ];
|
||||
|
||||
// Setting values on transforms doesn't make sense right now
|
||||
if ( pControl->GetValue<bool>( "transform" ) )
|
||||
continue;
|
||||
|
||||
bool bIsCombo = pControl->GetValue< bool >( "combo" );
|
||||
bool bIsMulti = pControl->GetValue< bool >( "multi" );
|
||||
bool bRandomize = ShouldRandomize( pControl->GetName() );
|
||||
if ( !bIdentity && !bRandomize )
|
||||
continue;
|
||||
|
||||
CDmElement *pControlValue = pPreset->FindOrAddControlValue( pControl->GetName() );
|
||||
|
||||
if ( !bIdentity )
|
||||
{
|
||||
pControlValue->SetValue< float >( "value", RandomFloat( 0.0f, 1.0f ) );
|
||||
if ( bIsCombo )
|
||||
{
|
||||
pControlValue->SetValue< float >( "balance", RandomFloat( 0.25f, 0.75f ) );
|
||||
}
|
||||
if ( bIsMulti )
|
||||
{
|
||||
pControlValue->SetValue< float >( "multilevel", RandomFloat( 0.0f, 1.0f ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pControlValue->SetValue< float >( "value", flForceValue );
|
||||
if ( bIsCombo )
|
||||
{
|
||||
pControlValue->SetValue< float >( "balance", 0.5f );
|
||||
}
|
||||
if ( bIsMulti )
|
||||
{
|
||||
pControlValue->SetValue< float >( "multilevel", flForceValue );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates preset groups for new animation sets
|
||||
//-----------------------------------------------------------------------------
|
||||
static void CreatePresetGroups( CDmeAnimationSet *pAnimationSet, const char *pModelName )
|
||||
{
|
||||
CDmaElementArray< CDmElement > &controls = pAnimationSet->GetControls();
|
||||
|
||||
// Now create some presets
|
||||
CDmePresetGroup *pProceduralPresets = pAnimationSet->FindOrAddPresetGroup( "procedural" );
|
||||
pProceduralPresets->m_bIsReadOnly = true;
|
||||
pProceduralPresets->FindOrAddPreset( "Default" );
|
||||
CreateProceduralPreset( pProceduralPresets, "Zero", controls, true, 0.0f );
|
||||
CreateProceduralPreset( pProceduralPresets, "Half", controls, true, 0.5f );
|
||||
CreateProceduralPreset( pProceduralPresets, "One", controls, true, 1.0f );
|
||||
|
||||
// Add just one fake one for now
|
||||
CreateProceduralPreset( pProceduralPresets, "Random", controls, false );
|
||||
|
||||
// These are the truly procedural ones...
|
||||
pAnimationSet->EnsureProceduralPresets();
|
||||
|
||||
// Also load the model-specific presets
|
||||
g_pModelPresetGroupMgr->ApplyModelPresets( pModelName, pAnimationSet );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Destroys existing group mappings
|
||||
//-----------------------------------------------------------------------------
|
||||
static void RemoveExistingGroupMappings( CDmeAnimationSet *pAnimationSet )
|
||||
{
|
||||
CDmaElementArray<> &groups = pAnimationSet->GetSelectionGroups();
|
||||
int nCount = groups.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
CDmElement *pGroup = groups[i];
|
||||
groups.Set( i, NULL );
|
||||
DestroyElement( pGroup );
|
||||
}
|
||||
groups.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
void LoadDefaultGroupMappings( CUtlDict< CUtlString, int > &defaultGroupMapping, CUtlVector< CUtlString >& defaultGroupOrdering )
|
||||
{
|
||||
defaultGroupMapping.RemoveAll();
|
||||
defaultGroupOrdering.RemoveAll();
|
||||
|
||||
KeyValues *pGroupFile = new KeyValues( "groupFile" );
|
||||
if ( !pGroupFile )
|
||||
return;
|
||||
|
||||
if ( !pGroupFile->LoadFromFile( g_pFullFileSystem, ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE, "GAME" ) )
|
||||
{
|
||||
pGroupFile->deleteThis();
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill in defaults
|
||||
for ( KeyValues *sub = pGroupFile->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
|
||||
{
|
||||
const char *pGroupName = sub->GetName();
|
||||
if ( !pGroupName )
|
||||
{
|
||||
Warning( "%s is malformed\n", ANIMATION_SET_DEFAULT_GROUP_MAPPING_FILE );
|
||||
continue;
|
||||
}
|
||||
|
||||
int i = defaultGroupOrdering.AddToTail();
|
||||
defaultGroupOrdering[i] = pGroupName;
|
||||
|
||||
for ( KeyValues *pControl = sub->GetFirstSubKey(); pControl; pControl = pControl->GetNextKey() )
|
||||
{
|
||||
Assert( !Q_stricmp( pControl->GetName(), "control" ) );
|
||||
CUtlString controlName = pControl->GetString();
|
||||
defaultGroupMapping.Insert( controlName, pGroupName );
|
||||
}
|
||||
}
|
||||
|
||||
pGroupFile->deleteThis();
|
||||
}
|
||||
|
||||
CDmElement *FindOrAddDefaultGroupForControls( const char *pGroupName, CDmaElementArray< CDmElement > &groups, DmFileId_t fileid )
|
||||
{
|
||||
// Now see if this group exists in the array
|
||||
int c = groups.Count();
|
||||
for ( int i = 0; i < c; ++i )
|
||||
{
|
||||
CDmElement *pGroup = groups[ i ];
|
||||
if ( !Q_stricmp( pGroup->GetName(), pGroupName ) )
|
||||
return pGroup;
|
||||
}
|
||||
|
||||
CDmElement *pGroup = CreateElement< CDmElement >( pGroupName, fileid );
|
||||
pGroup->AddAttribute( "selectedControls", AT_STRING_ARRAY );
|
||||
groups.AddToTail( pGroup );
|
||||
return pGroup;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Build group mappings
|
||||
//-----------------------------------------------------------------------------
|
||||
static void BuildGroupMappings( CDmeAnimationSet *pAnimationSet )
|
||||
{
|
||||
RemoveExistingGroupMappings( pAnimationSet );
|
||||
|
||||
// Maps flex controls to first level "groups" by flex controller name
|
||||
CUtlDict< CUtlString, int > defaultGroupMapping;
|
||||
CUtlVector< CUtlString > defaultGroupOrdering;
|
||||
|
||||
LoadDefaultGroupMappings( defaultGroupMapping, defaultGroupOrdering );
|
||||
|
||||
// Create the default groups in order
|
||||
CDmaElementArray<> &groups = pAnimationSet->GetSelectionGroups();
|
||||
int nCount = defaultGroupOrdering.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
const char *pGroupName = (const char *)defaultGroupOrdering[ i ];
|
||||
if ( !Q_stricmp( pGroupName, "IGNORE" ) )
|
||||
continue;
|
||||
|
||||
CDmElement *pGroup = CreateElement< CDmElement >( pGroupName, pAnimationSet->GetFileId() );
|
||||
|
||||
// Fill in members
|
||||
pGroup->AddAttribute( "selectedControls", AT_STRING_ARRAY );
|
||||
groups.AddToTail( pGroup );
|
||||
}
|
||||
|
||||
// Populate the groups with the controls
|
||||
CDmaElementArray<> &controls = pAnimationSet->GetControls();
|
||||
nCount = controls.Count();
|
||||
for ( int i = 0; i < nCount; ++i )
|
||||
{
|
||||
const char *pGroupName = "Unknown";
|
||||
const char *pControlName = controls[ i ]->GetName();
|
||||
|
||||
// Find the default if there is one
|
||||
int idx = defaultGroupMapping.Find( pControlName );
|
||||
if ( idx != defaultGroupMapping.InvalidIndex() )
|
||||
{
|
||||
pGroupName = defaultGroupMapping[ idx ];
|
||||
}
|
||||
else if ( Q_stristr( pControlName, "root" ) || Q_stristr( pControlName, "Valve" ) )
|
||||
{
|
||||
pGroupName = "Root";
|
||||
}
|
||||
|
||||
if ( !Q_stricmp( pGroupName, "IGNORE" ) )
|
||||
continue;
|
||||
|
||||
CDmElement *pGroup = FindOrAddDefaultGroupForControls( pGroupName, groups, pAnimationSet->GetFileId() );
|
||||
|
||||
// Fill in members
|
||||
CDmrStringArray selectedControls( pGroup, "selectedControls" );
|
||||
Assert( selectedControls.IsValid() );
|
||||
if ( selectedControls.IsValid() )
|
||||
{
|
||||
selectedControls.AddToTail( pControlName );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddIllumPositionAttribute( CDmeGameModel *pGameModel )
|
||||
{
|
||||
studiohdr_t *pHdr = pGameModel->GetStudioHdr();
|
||||
if ( !pHdr )
|
||||
return;
|
||||
|
||||
if ( pHdr->IllumPositionAttachmentIndex() > 0 )
|
||||
return; // don't add attr if model already has illumposition attachment
|
||||
|
||||
CDmAttribute *pAttr = pGameModel->AddAttributeElement< CDmeDag >( "illumPositionDag" );
|
||||
Assert( pAttr );
|
||||
if ( !pAttr )
|
||||
return;
|
||||
|
||||
Assert( pGameModel->GetChildCount() > 0 );
|
||||
pAttr->SetValue( pGameModel->GetChild( 0 ) );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates an animation set
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmeAnimationSet *CreateAnimationSet( CDmeFilmClip *pMovie, CDmeFilmClip *pShot,
|
||||
CDmeGameModel *pGameModel, const char *pAnimationSetName, int nSequenceToUse, bool bAttachToGameRecording )
|
||||
{
|
||||
CDmeAnimationSet *pAnimationSet = CreateElement< CDmeAnimationSet >( pAnimationSetName, pMovie->GetFileId() );
|
||||
Assert( pAnimationSet );
|
||||
|
||||
studiohdr_t *hdr = pGameModel->GetStudioHdr();
|
||||
|
||||
// Associate this animation set with a specific game model
|
||||
// FIXME: Should the game model refer back to this set?
|
||||
pAnimationSet->SetValue( "gameModel", pGameModel );
|
||||
|
||||
CDmeChannelsClip* pChannelsClip = CreateChannelsClip( pAnimationSet, pShot );
|
||||
|
||||
// Does everything associated with building facial controls on a model
|
||||
CFlexControlBuilder builder;
|
||||
builder.CreateAnimationSetControls( pMovie, pAnimationSet, pGameModel, pShot, pChannelsClip, bAttachToGameRecording );
|
||||
|
||||
// Create animation data if there wasn't any already in the model
|
||||
if ( !bAttachToGameRecording )
|
||||
{
|
||||
CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "skin", pGameModel, "skin", (int)0 );
|
||||
CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "body", pGameModel, "body", (int)0 );
|
||||
CreateConstantValuedLog( pChannelsClip, pAnimationSetName, "sequence", pGameModel, "sequence", (int)0 );
|
||||
|
||||
CreateAnimationLogs( pChannelsClip, pGameModel, hdr, pAnimationSetName, nSequenceToUse, 0.0f, 1.0f, 0.05f );
|
||||
}
|
||||
|
||||
CDmeChannelsClip *srcChannelsClip = FindChannelsClipTargetingDmeGameModel( pShot, pGameModel );
|
||||
CDmaElementArray<> &controls = pAnimationSet->GetControls();
|
||||
|
||||
// First the root transform
|
||||
{
|
||||
const char *ctrlName = "rootTransform";
|
||||
|
||||
// Add the control to the controls group
|
||||
CDmElement *ctrl = CreateElement< CDmElement >( ctrlName, pMovie->GetFileId() );
|
||||
Assert( ctrl );
|
||||
ctrl->SetValue< bool >( "transform", true );
|
||||
controls.AddToTail( ctrl );
|
||||
SetupRootTransform( pShot, srcChannelsClip, pChannelsClip, ctrl, pGameModel, pAnimationSetName, bAttachToGameRecording );
|
||||
}
|
||||
|
||||
// Now add the bone transforms as well
|
||||
{
|
||||
int numbones = hdr->numbones;
|
||||
for ( int b = 0; b < numbones; ++b )
|
||||
{
|
||||
mstudiobone_t *bone = hdr->pBone( b );
|
||||
const char *name = bone->pszName();
|
||||
|
||||
// Add the control to the controls group
|
||||
CDmElement *ctrl = CreateElement< CDmElement >( name, pMovie->GetFileId() );
|
||||
Assert( ctrl );
|
||||
ctrl->SetValue< bool >( "transform", true );
|
||||
controls.AddToTail( ctrl );
|
||||
SetupBoneTransform( pShot, srcChannelsClip, pChannelsClip, ctrl, pGameModel, pAnimationSetName, hdr, b, name, bAttachToGameRecording );
|
||||
}
|
||||
}
|
||||
|
||||
// Now copy all remaining logs, and retime them, over to the animation set channels clip...
|
||||
if ( srcChannelsClip )
|
||||
{
|
||||
TransferRemainingChannels( pShot, pChannelsClip, srcChannelsClip );
|
||||
}
|
||||
|
||||
// Create default preset groups for the animation set
|
||||
CreatePresetGroups( pAnimationSet, pGameModel->GetModelName() );
|
||||
|
||||
// Builds the preset groups displayed in the upper left of the animation set panel
|
||||
BuildGroupMappings( pAnimationSet );
|
||||
|
||||
pShot->AddAnimationSet( pAnimationSet );
|
||||
|
||||
AddIllumPositionAttribute( pGameModel );
|
||||
|
||||
return pAnimationSet;
|
||||
}
|
42
sfmobjects/sfmobjects.vpc
Normal file
42
sfmobjects/sfmobjects.vpc
Normal file
@ -0,0 +1,42 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFMOBJECTS.VPC
|
||||
//
|
||||
// Project Script
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
$Macro SRCDIR ".."
|
||||
|
||||
$Include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
|
||||
|
||||
$Configuration
|
||||
{
|
||||
$Compiler
|
||||
{
|
||||
$PreprocessorDefinitions "$BASE;SFMOBJECTS_LIB"
|
||||
}
|
||||
}
|
||||
|
||||
$Project "sfmobjects"
|
||||
{
|
||||
$Folder "Header Files"
|
||||
{
|
||||
}
|
||||
|
||||
$Folder "Source Files"
|
||||
{
|
||||
$File "exportfacialanimation.cpp"
|
||||
$File "flexcontrolbuilder.cpp"
|
||||
$File "sfmsession.cpp"
|
||||
$File "sfmanimationsetutils.cpp"
|
||||
$File "sfmphonemeextractor.cpp"
|
||||
}
|
||||
|
||||
$Folder "Interface"
|
||||
{
|
||||
$File "$SRCDIR\public\sfmobjects\exportfacialanimation.h"
|
||||
$File "$SRCDIR\public\sfmobjects\flexcontrolbuilder.h"
|
||||
$File "$SRCDIR\public\sfmobjects\sfmanimationsetutils.h"
|
||||
$File "$SRCDIR\public\sfmobjects\sfmphonemeextractor.h"
|
||||
$File "$SRCDIR\public\sfmobjects\sfmsession.h"
|
||||
}
|
||||
}
|
1186
sfmobjects/sfmphonemeextractor.cpp
Normal file
1186
sfmobjects/sfmphonemeextractor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
285
sfmobjects/sfmsession.cpp
Normal file
285
sfmobjects/sfmsession.cpp
Normal file
@ -0,0 +1,285 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// A class representing session state for the SFM
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "sfmobjects/sfmsession.h"
|
||||
#include "studio.h"
|
||||
#include "movieobjects/dmechannel.h"
|
||||
#include "movieobjects/dmetrack.h"
|
||||
#include "movieobjects/dmeclip.h"
|
||||
#include "movieobjects/dmecamera.h"
|
||||
#include "movieobjects/dmetimeselection.h"
|
||||
#include "movieobjects/dmeanimationset.h"
|
||||
#include "movieobjects/dmegamemodel.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//-----------------------------------------------------------------------------
|
||||
CSFMSession::CSFMSession()
|
||||
{
|
||||
m_hRoot = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Sets the root
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSFMSession::SetRoot( CDmElement *pRoot )
|
||||
{
|
||||
m_hRoot = pRoot;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a new (empty) session
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSFMSession::Init()
|
||||
{
|
||||
m_hRoot = NULL;
|
||||
|
||||
// a movie currently consists of: (this is all just temporary until clips take over more completely)
|
||||
// a generic "root" node
|
||||
// movie - a clip node whose subclips are the movie sequence
|
||||
// cameras - an array of cameras used throughout the movie
|
||||
// clips - an array of clips used throughout the movie
|
||||
CDmElement *pRoot = CreateElement< CDmElement >( "session" );
|
||||
Assert( pRoot );
|
||||
if ( !pRoot )
|
||||
return;
|
||||
m_hRoot = pRoot;
|
||||
|
||||
// FIXME!
|
||||
pRoot->SetValue( "editorType", "ifm" );
|
||||
|
||||
CDmeFilmClip *pFilmClip = CreateElement<CDmeFilmClip>( "sequence" );
|
||||
Assert( pFilmClip != NULL );
|
||||
pFilmClip->SetDuration( DmeTime_t( 60.0f ) );
|
||||
|
||||
CDmeTrack *pTrack = pFilmClip->FindOrCreateFilmTrack();
|
||||
CDmeClip *pShot = CreateElement<CDmeFilmClip>( "shot" );
|
||||
pTrack->AddClip( pShot );
|
||||
pShot->SetDuration( DmeTime_t( 60.0f ) );
|
||||
|
||||
pRoot->SetValue( "activeClip", pFilmClip );
|
||||
|
||||
pRoot->AddAttributeElementArray< CDmElement >( "miscBin" );
|
||||
pRoot->AddAttributeElementArray< CDmeCamera >( "cameraBin" );
|
||||
CDmAttribute *pClipBin = pRoot->AddAttributeElementArray< CDmeClip >( "clipBin" );
|
||||
|
||||
// Don't allow duplicates in the clipBin
|
||||
pClipBin->AddFlag( FATTRIB_NODUPLICATES );
|
||||
|
||||
CDmrElementArray<> clipBin( pRoot, "clipBin" );
|
||||
clipBin.AddToTail( pFilmClip );
|
||||
|
||||
CreateSessionSettings();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Shuts down the session
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSFMSession::Shutdown()
|
||||
{
|
||||
if ( m_hRoot.Get() )
|
||||
{
|
||||
if ( m_hRoot->GetFileId() != DMFILEID_INVALID )
|
||||
{
|
||||
g_pDataModel->RemoveFileId( m_hRoot->GetFileId() );
|
||||
m_hRoot = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates session settings
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSFMSession::CreateSessionSettings()
|
||||
{
|
||||
if ( !m_hRoot.Get() )
|
||||
return;
|
||||
|
||||
m_hRoot->AddAttribute( "settings", AT_ELEMENT );
|
||||
|
||||
CDmElement *pSettings = m_hRoot->GetValueElement< CDmElement >( "settings" );
|
||||
if ( !pSettings )
|
||||
{
|
||||
pSettings = CreateElement< CDmElement >( "sessionSettings", m_hRoot->GetFileId() );
|
||||
m_hRoot->SetValue( "settings", pSettings );
|
||||
}
|
||||
|
||||
Assert( pSettings );
|
||||
|
||||
CDmeTimeSelection *ts = NULL;
|
||||
if ( !pSettings->HasAttribute( "timeSelection" ) )
|
||||
{
|
||||
ts = CreateElement< CDmeTimeSelection >( "timeSelection", m_hRoot->GetFileId() );
|
||||
pSettings->SetValue( "timeSelection", ts );
|
||||
}
|
||||
|
||||
pSettings->InitValue( "animationSetOverlayBackground", Color( 0, 0, 0, 192 ) );
|
||||
|
||||
if ( !pSettings->HasAttribute( "standardColors" ) )
|
||||
{
|
||||
CDmrArray<Color> colors( pSettings, "standardColors", true );
|
||||
colors.AddToTail( Color( 0, 0, 0, 128 ) );
|
||||
colors.AddToTail( Color( 194, 120, 0, 128 ) );
|
||||
colors.AddToTail( Color( 255, 0, 100, 128 ) );
|
||||
colors.AddToTail( Color( 200, 200, 255, 128 ) );
|
||||
colors.AddToTail( Color( 255, 255, 255, 128 ) );
|
||||
}
|
||||
|
||||
float flLegacyFrameRate = 24.0f;
|
||||
if ( pSettings->HasAttribute( "frameRate" ) )
|
||||
{
|
||||
flLegacyFrameRate = pSettings->GetValue<float>( "frameRate" );
|
||||
|
||||
// remove this from the base level settings area since we're going to add it in renderSettings
|
||||
pSettings->RemoveAttribute( "frameRate" );
|
||||
}
|
||||
|
||||
if ( !pSettings->HasAttribute( "proceduralPresets" ) )
|
||||
{
|
||||
CDmeProceduralPresetSettings *ps = CreateElement< CDmeProceduralPresetSettings >( "proceduralPresets", m_hRoot->GetFileId() );
|
||||
pSettings->SetValue( "proceduralPresets", ps );
|
||||
}
|
||||
|
||||
CreateRenderSettings( pSettings, flLegacyFrameRate );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates session render settings
|
||||
// JasonM - remove flLegacyFramerate param eventually (perhaps March 2007)
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSFMSession::CreateRenderSettings( CDmElement *pSettings, float flLegacyFramerate )
|
||||
{
|
||||
pSettings->AddAttribute( "renderSettings", AT_ELEMENT );
|
||||
|
||||
CDmElement *pRenderSettings = pSettings->GetValueElement< CDmElement >( "renderSettings" );
|
||||
if ( !pRenderSettings )
|
||||
{
|
||||
pRenderSettings = CreateElement< CDmElement >( "renderSettings", pSettings->GetFileId() );
|
||||
pSettings->SetValue( "renderSettings", pRenderSettings );
|
||||
}
|
||||
Assert( pRenderSettings );
|
||||
|
||||
pRenderSettings->InitValue( "frameRate", flLegacyFramerate ); // Default framerate
|
||||
pRenderSettings->InitValue( "lightAverage", 0 ); // Don't light average by default
|
||||
pRenderSettings->InitValue( "showFocalPlane", 0 ); // Don't show focal plane by default
|
||||
pRenderSettings->InitValue( "modelLod", 0 ); // Don't do model LOD by default
|
||||
|
||||
CreateProgressiveRefinementSettings( pRenderSettings );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates session progrssing refinement settings
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSFMSession::CreateProgressiveRefinementSettings( CDmElement *pRenderSettings )
|
||||
{
|
||||
// Do we already have Progressive refinement settings?
|
||||
CDmElement *pRefinementSettings = pRenderSettings->GetValueElement< CDmElement >( "ProgressiveRefinement" );
|
||||
if ( !pRefinementSettings )
|
||||
{
|
||||
pRefinementSettings = CreateElement< CDmElement >( "ProgressiveRefinementSettings", pRenderSettings->GetFileId() );
|
||||
pRenderSettings->SetValue( "ProgressiveRefinement", pRefinementSettings );
|
||||
}
|
||||
|
||||
// Set up defaults for progressive refinement settings...
|
||||
pRefinementSettings->InitValue( "on", true );
|
||||
pRefinementSettings->InitValue( "useDepthOfField", true );
|
||||
pRefinementSettings->InitValue( "overrideDepthOfFieldQuality", false );
|
||||
pRefinementSettings->InitValue( "overrideDepthOfFieldQualityValue", 1 );
|
||||
pRefinementSettings->InitValue( "useMotionBlur", true );
|
||||
pRefinementSettings->InitValue( "overrideMotionBlurQuality", false );
|
||||
pRefinementSettings->InitValue( "overrideMotionBlurQualityValue", 1 );
|
||||
pRefinementSettings->InitValue( "useAntialiasing", false );
|
||||
pRefinementSettings->InitValue( "overrideShutterSpeed", false );
|
||||
pRefinementSettings->InitValue( "overrideShutterSpeedValue", 1.0f / 48.0f );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a camera
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmeCamera *CSFMSession::CreateCamera( const DmeCameraParams_t& params )
|
||||
{
|
||||
CDmeCamera *pCamera = CreateElement< CDmeCamera >( params.name, m_hRoot->GetFileId() );
|
||||
|
||||
// Set parameters
|
||||
matrix3x4_t txform;
|
||||
AngleMatrix( params.angles, params.origin, txform );
|
||||
|
||||
CDmeTransform *pTransform = pCamera->GetTransform();
|
||||
if ( pTransform )
|
||||
{
|
||||
pTransform->SetTransform( txform );
|
||||
}
|
||||
|
||||
pCamera->SetFOVx( params.fov );
|
||||
return pCamera;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Finds or creates a scene
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmeDag *CSFMSession::FindOrCreateScene( CDmeFilmClip *pShot, const char *pSceneName )
|
||||
{
|
||||
CDmeDag *pScene = pShot->GetScene();
|
||||
if ( !pScene )
|
||||
{
|
||||
pScene = CreateElement< CDmeDag >( "scene", pShot->GetFileId() );
|
||||
pShot->SetScene( pScene );
|
||||
}
|
||||
Assert( pScene );
|
||||
|
||||
int c = pScene->GetChildCount();
|
||||
for ( int i = 0 ; i < c; ++i )
|
||||
{
|
||||
CDmeDag *pChild = pScene->GetChild( i );
|
||||
if ( pChild && !Q_stricmp( pChild->GetName(), pSceneName ) )
|
||||
return pChild;
|
||||
}
|
||||
|
||||
CDmeDag *pNewScene = CreateElement< CDmeDag >( pSceneName, pScene->GetFileId() );
|
||||
pScene->AddChild( pNewScene );
|
||||
|
||||
return pNewScene;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Creates a game model
|
||||
//-----------------------------------------------------------------------------
|
||||
CDmeGameModel *CSFMSession::CreateEditorGameModel( studiohdr_t *hdr, const Vector &vecOrigin, Quaternion &qOrientation )
|
||||
{
|
||||
char pBaseName[ 256 ];
|
||||
Q_FileBase( hdr->pszName(), pBaseName, sizeof( pBaseName ) );
|
||||
|
||||
char pGameModelName[ 256 ];
|
||||
Q_snprintf( pGameModelName, sizeof( pGameModelName ), "%s_GameModel", pBaseName );
|
||||
CDmeGameModel *pGameModel = CreateElement< CDmeGameModel >( pGameModelName, m_hRoot->GetFileId() );
|
||||
|
||||
char pRelativeModelsFileName[MAX_PATH];
|
||||
Q_ComposeFileName( "models", hdr->pszName(), pRelativeModelsFileName, sizeof(pRelativeModelsFileName) );
|
||||
pGameModel->SetValue( "modelName", pRelativeModelsFileName );
|
||||
|
||||
CDmeTransform *pTransform = pGameModel->GetTransform();
|
||||
if ( pTransform )
|
||||
{
|
||||
pTransform->SetPosition( vecOrigin );
|
||||
pTransform->SetOrientation( qOrientation );
|
||||
}
|
||||
|
||||
// create, connect and cache each bone's pos and rot channels
|
||||
pGameModel->AddBones( hdr, pBaseName, 0, hdr->numbones );
|
||||
return pGameModel;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user