You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
986 lines
27 KiB
986 lines
27 KiB
//====== Copyright © 1996-2004, Valve Corporation, All rights reserved. =======
|
|
//
|
|
// Dme version of a game model (MDL)
|
|
//
|
|
//=============================================================================
|
|
#include "movieobjects/dmegamemodel.h"
|
|
#include "movieobjects_interfaces.h"
|
|
#include "datamodel/dmelementfactoryhelper.h"
|
|
#include "studio.h"
|
|
#include "tier3/tier3.h"
|
|
#include "tier1/fmtstr.h"
|
|
#include "bone_setup.h"
|
|
|
|
#include "movieobjects/dmeoverlay.h" // FIXME: Why do I have to explicitly include dmeoverlay.h here?
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Expose this class to the scene database
|
|
//-----------------------------------------------------------------------------
|
|
IMPLEMENT_ELEMENT_FACTORY( DmeGlobalFlexControllerOperator, CDmeGlobalFlexControllerOperator );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGlobalFlexControllerOperator::OnConstruction()
|
|
{
|
|
m_flexWeight.Init( this, "flexWeight" );
|
|
m_gameModel.Init( this, "gameModel", FATTRIB_HAS_CALLBACK | FATTRIB_NEVERCOPY );
|
|
|
|
m_ToAttributeHandle = DMATTRIBUTE_HANDLE_INVALID;
|
|
|
|
m_nFlexControllerIndex = -1;
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::OnDestruction()
|
|
{
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::Resolve()
|
|
{
|
|
if ( m_nFlexControllerIndex < 0 )
|
|
{
|
|
m_nFlexControllerIndex = FindGlobalFlexControllerIndex();
|
|
}
|
|
if ( m_ToAttributeHandle == DMATTRIBUTE_HANDLE_INVALID )
|
|
{
|
|
SetupToAttribute();
|
|
}
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::OnAttributeChanged( CDmAttribute *pAttribute )
|
|
{
|
|
// Don't have the required interface...
|
|
if ( !g_pGlobalFlexController )
|
|
return;
|
|
|
|
if ( pAttribute == m_gameModel.GetAttribute() && m_gameModel.GetElement() )
|
|
{
|
|
m_nFlexControllerIndex = FindGlobalFlexControllerIndex();
|
|
|
|
SetupToAttribute();
|
|
}
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::Operate()
|
|
{
|
|
CDmAttribute *pToAttr = g_pDataModel->GetAttribute( m_ToAttributeHandle );
|
|
if ( !pToAttr )
|
|
return;
|
|
|
|
DmAttributeType_t type = m_flexWeight.GetAttribute()->GetType();
|
|
|
|
const void *pValue = m_flexWeight.GetAttribute()->GetValueUntyped();
|
|
if ( IsArrayType( pToAttr->GetType() ) )
|
|
{
|
|
if ( m_nFlexControllerIndex == -1 )
|
|
return;
|
|
|
|
CDmrGenericArray array( pToAttr );
|
|
array.Set( m_nFlexControllerIndex, type, pValue );
|
|
}
|
|
else
|
|
{
|
|
pToAttr->SetValue( type, pValue );
|
|
}
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::SetGameModel( CDmeGameModel *gameModel )
|
|
{
|
|
m_gameModel = gameModel;
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::SetWeight( float flWeight )
|
|
{
|
|
m_flexWeight = flWeight;
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::SetMapping( int globalIndex )
|
|
{
|
|
m_nFlexControllerIndex = globalIndex;
|
|
if ( m_gameModel.GetElement() )
|
|
{
|
|
if ( (uint)globalIndex >= m_gameModel->NumFlexWeights() )
|
|
{
|
|
m_gameModel->SetNumFlexWeights( (uint)( globalIndex + 1 ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
int CDmeGlobalFlexControllerOperator::GetGlobalIndex() const
|
|
{
|
|
return m_nFlexControllerIndex;
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::GetInputAttributes ( CUtlVector< CDmAttribute * > &attrs )
|
|
{
|
|
attrs.AddToTail( m_flexWeight.GetAttribute() );
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs )
|
|
{
|
|
CDmAttribute *toAttribute = g_pDataModel->GetAttribute( m_ToAttributeHandle );
|
|
if ( toAttribute )
|
|
{
|
|
attrs.AddToTail( toAttribute );
|
|
}
|
|
}
|
|
|
|
void CDmeGlobalFlexControllerOperator::SetupToAttribute()
|
|
{
|
|
CDmElement *pObject = m_gameModel.GetElement();
|
|
if ( pObject == NULL)
|
|
return;
|
|
|
|
CDmAttribute *pAttr = pObject->GetAttribute( "flexWeights" );
|
|
Assert( pAttr );
|
|
if ( !pAttr )
|
|
return;
|
|
|
|
m_ToAttributeHandle = pAttr->GetHandle();
|
|
return;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Connect up stuff by index
|
|
//-----------------------------------------------------------------------------
|
|
int CDmeGlobalFlexControllerOperator::FindGlobalFlexControllerIndex() const
|
|
{
|
|
int nGlobalFlexControllerIndex = -1;
|
|
MDLHandle_t h = m_gameModel->GetModelHandle();
|
|
if ( h != MDLHANDLE_INVALID )
|
|
{
|
|
studiohdr_t *hdr = g_pMDLCache->GetStudioHdr( h );
|
|
Assert( hdr );
|
|
if ( hdr )
|
|
{
|
|
int fc = hdr->numflexcontrollers;
|
|
for ( LocalFlexController_t i = LocalFlexController_t(0) ; i < fc; ++i )
|
|
{
|
|
mstudioflexcontroller_t *flex = hdr->pFlexcontroller( i );
|
|
if ( flex->localToGlobal == -1 && g_pGlobalFlexController )
|
|
{
|
|
flex->localToGlobal = g_pGlobalFlexController->FindGlobalFlexController( flex->pszName() );
|
|
}
|
|
|
|
if ( !Q_stricmp( flex->pszName(), GetName() ) )
|
|
{
|
|
nGlobalFlexControllerIndex = flex->localToGlobal;
|
|
// Grow the array
|
|
if ( (uint)flex->localToGlobal >= m_gameModel->NumFlexWeights() )
|
|
{
|
|
m_gameModel->SetNumFlexWeights( (uint)( flex->localToGlobal + 1 ) );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return nGlobalFlexControllerIndex;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Expose this class to the scene database
|
|
//-----------------------------------------------------------------------------
|
|
IMPLEMENT_ELEMENT_FACTORY( DmeGameModel, CDmeGameModel );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGameModel::OnConstruction()
|
|
{
|
|
m_flexWeights.Init( this, "flexWeights" );
|
|
m_modelName.Init( this, "modelName", FATTRIB_HAS_CALLBACK );
|
|
m_skin.Init( this, "skin" );
|
|
m_body.Init( this, "body" );
|
|
m_sequence.Init( this, "sequence" );
|
|
m_flags.Init( this, "flags" );
|
|
m_bones.Init( this, "bones" );
|
|
m_globalFlexControllers.Init( this, "globalFlexControllers" );
|
|
m_bComputeBounds.Init( this, "computeBounds" );
|
|
m_bEvaluateProceduralBones.InitAndSet( this, "evaluateProceduralBones", true );
|
|
|
|
m_hMDL = MDLHANDLE_INVALID;
|
|
m_bHMDLDirty = true;
|
|
}
|
|
|
|
void CDmeGameModel::OnDestruction()
|
|
{
|
|
if ( m_hMDL != MDLHANDLE_INVALID )
|
|
{
|
|
g_pMDLCache->Release( m_hMDL );
|
|
m_hMDL = MDLHANDLE_INVALID;
|
|
}
|
|
}
|
|
|
|
void CDmeGameModel::OnAttributeChanged( CDmAttribute *pAttribute )
|
|
{
|
|
if ( pAttribute == m_modelName.GetAttribute() )
|
|
{
|
|
m_bHMDLDirty = true;
|
|
}
|
|
}
|
|
|
|
CDmeGlobalFlexControllerOperator *CDmeGameModel::AddGlobalFlexController( const char *controllerName, int globalIndex )
|
|
{
|
|
int i, c;
|
|
c = m_globalFlexControllers.Count();
|
|
for ( i = 0; i < c; ++i )
|
|
{
|
|
CDmeGlobalFlexControllerOperator *op = m_globalFlexControllers.Get( i );
|
|
Assert( op );
|
|
if ( op && !Q_stricmp( op->GetName(), controllerName ) )
|
|
break;
|
|
}
|
|
|
|
if ( i >= c )
|
|
{
|
|
CDmeGlobalFlexControllerOperator *newOperator = CreateElement< CDmeGlobalFlexControllerOperator >( controllerName, GetFileId() );
|
|
Assert( newOperator );
|
|
if ( !newOperator )
|
|
return NULL;
|
|
|
|
i = m_globalFlexControllers.AddToTail( newOperator );
|
|
}
|
|
|
|
Assert( m_globalFlexControllers.IsValidIndex( i ) );
|
|
CDmeGlobalFlexControllerOperator *op = m_globalFlexControllers.Get( i );
|
|
Assert( op );
|
|
if ( op )
|
|
{
|
|
op->SetMapping( globalIndex );
|
|
op->SetGameModel( this );
|
|
}
|
|
|
|
if ( (uint)globalIndex >= NumFlexWeights() )
|
|
{
|
|
SetNumFlexWeights( globalIndex + 1 );
|
|
}
|
|
|
|
return op;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Find a flex controller by its global index
|
|
//-----------------------------------------------------------------------------
|
|
CDmeGlobalFlexControllerOperator *CDmeGameModel::FindGlobalFlexController( int nGlobalIndex )
|
|
{
|
|
int i, c;
|
|
c = m_globalFlexControllers.Count();
|
|
for ( i = 0; i < c; ++i )
|
|
{
|
|
CDmeGlobalFlexControllerOperator *op = m_globalFlexControllers.Get( i );
|
|
Assert( op );
|
|
if ( op && op->GetGlobalIndex() == nGlobalIndex )
|
|
return op;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
studiohdr_t* CDmeGameModel::GetStudioHdr() const
|
|
{
|
|
const char *pModelName = GetModelName();
|
|
MDLHandle_t h = pModelName && pModelName[0] ? g_pMDLCache->FindMDL( pModelName ) : MDLHANDLE_INVALID;
|
|
return ( h != MDLHANDLE_INVALID ) ? g_pMDLCache->GetStudioHdr( h ) : NULL;
|
|
}
|
|
|
|
|
|
// A src bone transform transforms pre-compiled data (.dmx or .smd files, for example)
|
|
// into post-compiled data (.mdl or .ani files)
|
|
bool CDmeGameModel::GetSrcBoneTransforms( matrix3x4_t *pPreTransform, matrix3x4_t *pPostTransform, int nBoneIndex ) const
|
|
{
|
|
studiohdr_t *pStudioHdr = GetStudioHdr();
|
|
if ( !pStudioHdr )
|
|
return false;
|
|
|
|
if ( pStudioHdr->numbones <= nBoneIndex )
|
|
return false;
|
|
|
|
const char *pBoneName = pStudioHdr->pBone( nBoneIndex )->pszName();
|
|
int nCount = pStudioHdr->NumSrcBoneTransforms();
|
|
for ( int i = 0; i < nCount; ++i )
|
|
{
|
|
const mstudiosrcbonetransform_t *pSrcTransform = pStudioHdr->SrcBoneTransform( i );
|
|
if ( Q_stricmp( pSrcTransform->pszName(), pBoneName ) )
|
|
continue;
|
|
|
|
MatrixCopy( pSrcTransform->pretransform, *pPreTransform );
|
|
MatrixCopy( pSrcTransform->posttransform, *pPostTransform );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Get the default position of the specified bone.
|
|
//-----------------------------------------------------------------------------
|
|
bool CDmeGameModel::GetBoneDefaultPosition( int nBoneIndex, Vector &position ) const
|
|
{
|
|
studiohdr_t *pStudioHdr = GetStudioHdr();
|
|
if ( !pStudioHdr )
|
|
return false;
|
|
|
|
if ( ( nBoneIndex < 0 ) || ( nBoneIndex >= pStudioHdr->numbones ) )
|
|
return false;
|
|
|
|
const mstudiobone_t *pBone = pStudioHdr->pBone( nBoneIndex );
|
|
if ( pBone == NULL )
|
|
return false;
|
|
|
|
position = pBone->pos;
|
|
return true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Get the default orientation of the specified bone.
|
|
//-----------------------------------------------------------------------------
|
|
bool CDmeGameModel::GetBoneDefaultOrientation( int nBoneIndex, Quaternion &orientation ) const
|
|
{
|
|
studiohdr_t *pStudioHdr = GetStudioHdr();
|
|
if ( !pStudioHdr )
|
|
return false;
|
|
|
|
if ( ( nBoneIndex < 0 ) || ( nBoneIndex >= pStudioHdr->numbones ) )
|
|
return false;
|
|
|
|
const mstudiobone_t *pBone = pStudioHdr->pBone( nBoneIndex );
|
|
if ( pBone == NULL )
|
|
return false;
|
|
|
|
orientation = pBone->quat;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CDmeGameModel::IsRootTransform( int nBoneIndex ) const
|
|
{
|
|
studiohdr_t *pStudioHdr = GetStudioHdr();
|
|
if ( !pStudioHdr )
|
|
return true;
|
|
|
|
if ( pStudioHdr->numbones <= nBoneIndex )
|
|
return true;
|
|
|
|
const mstudiobone_t *pBone = pStudioHdr->pBone( nBoneIndex );
|
|
return pBone->parent == -1;
|
|
}
|
|
|
|
int CDmeGameModel::NumGlobalFlexControllers() const
|
|
{
|
|
return m_globalFlexControllers.Count();
|
|
}
|
|
|
|
CDmeGlobalFlexControllerOperator *CDmeGameModel::GetGlobalFlexController( int localIndex )
|
|
{
|
|
return m_globalFlexControllers.Get( localIndex );
|
|
}
|
|
|
|
void CDmeGameModel::RemoveGlobalFlexController( CDmeGlobalFlexControllerOperator *controller )
|
|
{
|
|
int c = m_globalFlexControllers.Count();
|
|
for ( int i = 0; i < c; ++i )
|
|
{
|
|
CDmeGlobalFlexControllerOperator *check = m_globalFlexControllers.Get( i );
|
|
if ( check == controller )
|
|
{
|
|
m_globalFlexControllers.Remove( i );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CDmeGameModel::AppendGlobalFlexControllerOperators( CUtlVector< IDmeOperator * >& list )
|
|
{
|
|
int c = m_globalFlexControllers.Count();
|
|
for ( int i = 0 ; i < c; ++i )
|
|
{
|
|
CDmeOperator *op = m_globalFlexControllers.Get( i );
|
|
if ( !op )
|
|
continue;
|
|
list.AddToTail( op );
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Find the dependencies of each flex controller on the other flex
|
|
// controllers
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGameModel::FindFlexControllerDependencies( CUtlVector< CUtlVector< int > > &dependencyList ) const
|
|
{
|
|
studiohdr_t *hdr = GetStudioHdr();
|
|
if ( hdr == NULL )
|
|
return;
|
|
|
|
|
|
// Build a table to reference the controller operators by the
|
|
// global index of the flex control they are associated with.
|
|
int controllerTable[ MAXSTUDIOFLEXDESC ];
|
|
memset( controllerTable, -1, sizeof( controllerTable ) );
|
|
|
|
int nControllers = m_globalFlexControllers.Count();
|
|
if ( nControllers > MAXSTUDIOFLEXDESC )
|
|
{
|
|
Assert( nControllers < MAXSTUDIOFLEXDESC );
|
|
return;
|
|
}
|
|
|
|
for ( int iCtrl = 0; iCtrl < nControllers; ++iCtrl )
|
|
{
|
|
CDmeGlobalFlexControllerOperator *pCtrlOp = m_globalFlexControllers[ iCtrl ];
|
|
if ( pCtrlOp )
|
|
{
|
|
int globalIndex = pCtrlOp->GetGlobalIndex();
|
|
if ( ( globalIndex < MAXSTUDIOFLEXDESC ) && ( globalIndex >= 0 ) )
|
|
{
|
|
controllerTable[ globalIndex ] = iCtrl;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Determine which rules each of the controllers contribute to
|
|
CStudioHdr studioHdr( hdr );
|
|
|
|
CUtlVector< int > controllerRuleTable[ MAXSTUDIOFLEXDESC ]; // Table of rules each controller contributes to
|
|
CUtlVector< int > ruleDepTable[ MAXSTUDIOFLEXDESC ]; // Table of controllers contributing to each rule
|
|
|
|
int nFlexRules = studioHdr.numflexrules();
|
|
|
|
for ( int iRule = 0; iRule < nFlexRules; ++iRule )
|
|
{
|
|
mstudioflexrule_t *pRule = studioHdr.pFlexRule( iRule );
|
|
|
|
if ( pRule == NULL )
|
|
return;
|
|
|
|
for ( int iOp = 0; iOp < pRule->numops; ++iOp )
|
|
{
|
|
mstudioflexop_t *pOp = pRule->iFlexOp( iOp );
|
|
|
|
switch ( pOp->op )
|
|
{
|
|
case STUDIO_FETCH1:
|
|
case STUDIO_2WAY_0:
|
|
case STUDIO_2WAY_1:
|
|
case STUDIO_NWAY:
|
|
case STUDIO_DME_LOWER_EYELID:
|
|
case STUDIO_DME_UPPER_EYELID:
|
|
{
|
|
int globalIndex = studioHdr.pFlexcontroller( (LocalFlexController_t)pOp->d.index )->localToGlobal;
|
|
if ( ( globalIndex < MAXSTUDIOFLEXDESC ) && ( pRule->flex < MAXSTUDIOFLEXDESC ) && ( globalIndex >= 0 ) )
|
|
{
|
|
int controllerIndex = controllerTable[ globalIndex ];
|
|
if ( controllerIndex >= 0 )
|
|
{
|
|
if ( controllerRuleTable[ controllerIndex ].Find( pRule->flex ) == CUtlVector< int >::InvalidIndex() )
|
|
{
|
|
controllerRuleTable[ controllerIndex ].AddToTail( pRule->flex );
|
|
ruleDepTable[ pRule->flex ].AddToTail( controllerIndex );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// For each controller, find the other controllers that contribute to the same rules.
|
|
bool dependencyTable[ MAXSTUDIOFLEXDESC ];
|
|
memset( dependencyTable, 0, sizeof( dependencyTable ) );
|
|
for ( int iCtrl = 0; iCtrl < nControllers; ++iCtrl )
|
|
{
|
|
memset( dependencyTable, 0, sizeof( bool ) * nControllers );
|
|
|
|
// Get the list of rules that controller contributes to
|
|
CUtlVector< int > &ruleList = controllerRuleTable[ iCtrl ];
|
|
int nRules = ruleList.Count();
|
|
int nDependencies = 0;
|
|
|
|
for ( int iRule = 0; iRule < nRules; ++iRule )
|
|
{
|
|
int ruleIndex = ruleList[ iRule ];
|
|
CUtlVector< int > &ruleControllerList = ruleDepTable[ ruleIndex ];
|
|
int nRuleDep = ruleControllerList.Count();
|
|
|
|
for ( int iDep = 0; iDep < nRuleDep; ++iDep )
|
|
{
|
|
int controllerIndex = ruleControllerList[ iDep ];
|
|
if ( ( controllerIndex != iCtrl ) && ( dependencyTable[ controllerIndex ] == false ) )
|
|
{
|
|
dependencyTable[ controllerIndex ] = true;
|
|
++nDependencies;
|
|
}
|
|
}
|
|
}
|
|
if ( nDependencies > 0 )
|
|
{
|
|
dependencyList.AddToTail();
|
|
CUtlVector< int > &dependencies = dependencyList.Tail();
|
|
dependencies.EnsureCapacity( nDependencies + 1 );
|
|
dependencies.AddToTail( iCtrl );
|
|
for ( int iDepCtrl = 0; iDepCtrl < nControllers; ++iDepCtrl )
|
|
{
|
|
if ( dependencyTable[ iDepCtrl ] == true )
|
|
{
|
|
dependencies.AddToTail( iDepCtrl );
|
|
--nDependencies;
|
|
}
|
|
}
|
|
Assert( nDependencies == 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// accessors
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGameModel::AddBone( CDmeTransform* pTransform )
|
|
{
|
|
m_bones.AddToTail( pTransform );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Is this dag under the game model?
|
|
//-----------------------------------------------------------------------------
|
|
static bool IsDagUnderGameModel( CDmeDag *pDag, CDmeGameModel *pGameModel )
|
|
{
|
|
if ( pDag == pGameModel )
|
|
return true;
|
|
|
|
DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( pDag->GetHandle() );
|
|
while ( i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID )
|
|
{
|
|
CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
|
|
CDmElement *pDmeParent = pAttribute->GetOwner();
|
|
const static CUtlSymbolLarge symChildren = g_pDataModel->GetSymbol( "children" );
|
|
if ( pDmeParent && pAttribute->GetNameSymbol() == symChildren )
|
|
{
|
|
CDmeDag *pParent = CastElement< CDmeDag >( pDmeParent );
|
|
if ( pParent && ( pParent->GetFileId() == pDag->GetFileId() ) )
|
|
{
|
|
if ( IsDagUnderGameModel( pParent, pGameModel ) )
|
|
return true;
|
|
}
|
|
}
|
|
i = g_pDataModel->NextAttributeReferencingElement( i );
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Finds existing dags
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGameModel::PopulateExistingDagList( CDmeDag** pDags, int nCount )
|
|
{
|
|
int nCurrentBoneCount = m_bones.Count();
|
|
for ( int i = 0; i < nCount; ++i )
|
|
{
|
|
if ( i >= nCurrentBoneCount )
|
|
{
|
|
pDags[ i ] = NULL;
|
|
continue;
|
|
}
|
|
|
|
CDmeTransform *pTransform = GetBone( i );
|
|
Assert( pTransform );
|
|
pDags[ i ] = pTransform ? pTransform->GetDag() : NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Adds bones to the game model
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGameModel::AddBones( studiohdr_t *pStudioHdr, int nFirstBone, int nCount )
|
|
{
|
|
if ( nFirstBone + nCount > pStudioHdr->numbones )
|
|
{
|
|
nCount = pStudioHdr->numbones - nFirstBone;
|
|
if ( nCount <= 0 )
|
|
return;
|
|
}
|
|
|
|
// make room for bones
|
|
CDmeDag** pDags = ( CDmeDag** )_alloca( pStudioHdr->numbones * sizeof(CDmeDag*) );
|
|
int nDagCount = nFirstBone;
|
|
PopulateExistingDagList( pDags, nFirstBone );
|
|
|
|
char name[ 256 ];
|
|
for ( int i = 0; i < nCount; ++i )
|
|
{
|
|
int bi = i + nFirstBone;
|
|
|
|
// get parent
|
|
const mstudiobone_t *pBone = pStudioHdr->pBone( bi );
|
|
int parentIndex = pBone->parent;
|
|
Assert( parentIndex < nDagCount );
|
|
|
|
// build dag hierarchy to match bone hierarchy
|
|
CDmeDag *pParent = ( parentIndex < 0 ) ? this : pDags[ parentIndex ];
|
|
Q_snprintf( name, sizeof( name ), "bone %d (%s)", bi, pBone->pszName() );
|
|
CDmeDag *pDag = CreateElement< CDmeDag >( name, GetFileId() );
|
|
pDags[nDagCount++] = pDag;
|
|
pParent->AddChild( pDag );
|
|
|
|
CDmeTransform *pTransform = pDag->GetTransform();
|
|
pTransform->SetName( name );
|
|
|
|
// add different bone representations to dme model and input
|
|
AddBone( pTransform );
|
|
}
|
|
}
|
|
|
|
void CDmeGameModel::SetBone( uint index, const Vector& pos, const Quaternion& rot )
|
|
{
|
|
m_bones[ index ]->SetPosition( pos );
|
|
m_bones[ index ]->SetOrientation( rot );
|
|
}
|
|
|
|
void CDmeGameModel::RemoveAllBones()
|
|
{
|
|
m_bones.RemoveAll();
|
|
}
|
|
|
|
uint CDmeGameModel::NumBones() const
|
|
{
|
|
return m_bones.Count();
|
|
}
|
|
|
|
CDmeTransform *CDmeGameModel::GetBone( uint index ) const
|
|
{
|
|
return m_bones[ index ];
|
|
}
|
|
|
|
int CDmeGameModel::FindBone( CDmeTransform *pTransform ) const
|
|
{
|
|
return m_bones.Find( pTransform );
|
|
}
|
|
|
|
uint CDmeGameModel::NumFlexWeights() const
|
|
{
|
|
return m_flexWeights.Count();
|
|
}
|
|
|
|
const CUtlVector< float >& CDmeGameModel::GetFlexWeights() const
|
|
{
|
|
return m_flexWeights.Get();
|
|
}
|
|
|
|
void CDmeGameModel::SetNumFlexWeights( uint nFlexWeights )
|
|
{
|
|
if ( nFlexWeights > (uint)m_flexWeights.Count() )
|
|
{
|
|
while ( (uint)m_flexWeights.Count() < nFlexWeights )
|
|
{
|
|
m_flexWeights.AddToTail( 0.0f );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while ( (uint)m_flexWeights.Count() > nFlexWeights )
|
|
{
|
|
m_flexWeights.Remove( (uint)m_flexWeights.Count() - 1 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void CDmeGameModel::SetFlexWeights( uint nFlexWeights, const float* flexWeights )
|
|
{
|
|
m_flexWeights.CopyArray( flexWeights, nFlexWeights );
|
|
}
|
|
|
|
void CDmeGameModel::SetFlags( int nFlags )
|
|
{
|
|
m_flags = nFlags;
|
|
}
|
|
|
|
void CDmeGameModel::SetSkin( int nSkin )
|
|
{
|
|
m_skin = nSkin;
|
|
}
|
|
|
|
void CDmeGameModel::SetBody( int nBody )
|
|
{
|
|
m_body = nBody;
|
|
}
|
|
|
|
void CDmeGameModel::SetSequence( int nSequence )
|
|
{
|
|
m_sequence = nSequence;
|
|
}
|
|
|
|
int CDmeGameModel::GetSkin() const
|
|
{
|
|
return m_skin;
|
|
}
|
|
|
|
int CDmeGameModel::GetBody() const
|
|
{
|
|
return m_body;
|
|
}
|
|
|
|
int CDmeGameModel::GetSequence() const
|
|
{
|
|
return m_sequence;
|
|
}
|
|
|
|
int CDmeGameModel::GetFlags() const
|
|
{
|
|
return m_flags;
|
|
}
|
|
|
|
const char *CDmeGameModel::GetModelName() const
|
|
{
|
|
return m_modelName.Get();
|
|
}
|
|
|
|
MDLHandle_t CDmeGameModel::GetModelHandle()
|
|
{
|
|
if ( m_bHMDLDirty )
|
|
{
|
|
UpdateHMDL();
|
|
}
|
|
return m_hMDL;
|
|
}
|
|
|
|
void CDmeGameModel::UpdateHMDL()
|
|
{
|
|
// Yes, we're intentionally referencing before we unref
|
|
MDLHandle_t h = MDLHANDLE_INVALID;
|
|
const char *pModelName = m_modelName.Get();
|
|
if ( pModelName && *pModelName )
|
|
{
|
|
h = g_pMDLCache->FindMDL( pModelName );
|
|
}
|
|
|
|
if ( m_hMDL != MDLHANDLE_INVALID )
|
|
{
|
|
g_pMDLCache->Release( m_hMDL );
|
|
}
|
|
|
|
m_hMDL = h;
|
|
m_bHMDLDirty = false;
|
|
}
|
|
|
|
|
|
int CDmeGameModel::FindAttachment( const char *pchAttachmentName ) const
|
|
{
|
|
if ( studiohdr_t *pStudioHdr = GetStudioHdr() )
|
|
{
|
|
CStudioHdr studioHdr( pStudioHdr );
|
|
return Studio_FindAttachment( &studioHdr, pchAttachmentName ) + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Compute the world space position of the specified attachment.
|
|
//-----------------------------------------------------------------------------
|
|
Vector CDmeGameModel::ComputeAttachmentPosition( const char *pchAttachmentName ) const
|
|
{
|
|
studiohdr_t *pStudioHdr = GetStudioHdr();
|
|
if ( pStudioHdr == NULL )
|
|
return vec3_origin;
|
|
|
|
// Find the index of the attachment by its name and verify
|
|
// that the attachment was found and that the index is valid.
|
|
CStudioHdr studioHdr( pStudioHdr );
|
|
int attachmentIndex = Studio_FindAttachment( &studioHdr, pchAttachmentName );
|
|
if ( ( attachmentIndex < 0 ) || ( attachmentIndex > studioHdr.GetNumAttachments() ) )
|
|
return vec3_origin;
|
|
|
|
// Get the bone to which in attachment position is defined
|
|
// and then find the dag node using the bone transform.
|
|
int boneIndex = studioHdr.GetAttachmentBone( attachmentIndex );
|
|
CDmeTransform *pBoneTranform = GetBone( boneIndex );
|
|
CDmeDag *pBoneDag = pBoneTranform->GetDag();
|
|
if ( pBoneDag == NULL )
|
|
return vec3_origin;
|
|
|
|
// Get the local offset position of the attachment and then transform
|
|
// it into world space using the transform of the associated dag node.
|
|
const mstudioattachment_t &attachment = studioHdr.pAttachment( attachmentIndex );
|
|
|
|
matrix3x4_t wsTransform;
|
|
Vector localPosition;
|
|
Vector worldPosition;
|
|
pBoneDag->GetAbsTransform( wsTransform );
|
|
MatrixPosition( attachment.local, localPosition );
|
|
VectorTransform( localPosition, wsTransform, worldPosition );
|
|
|
|
return worldPosition;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Create a dag node for the specified attachment and make it a child of the
|
|
// the bone it is local to.
|
|
//-----------------------------------------------------------------------------
|
|
CDmeDag *CDmeGameModel::CreateDagForAttachment( const char *pchAttachmentName ) const
|
|
{
|
|
studiohdr_t *pStudioHdr = GetStudioHdr();
|
|
if ( pStudioHdr == NULL )
|
|
return NULL;
|
|
|
|
// Find the index of the attachment by its name and verify
|
|
// that the attachment was found and that the index is valid.
|
|
CStudioHdr studioHdr( pStudioHdr );
|
|
int attachmentIndex = Studio_FindAttachment( &studioHdr, pchAttachmentName );
|
|
if ( ( attachmentIndex < 0 ) || ( attachmentIndex > studioHdr.GetNumAttachments() ) )
|
|
return NULL;
|
|
|
|
// Get the bone in which the attachment position is defined
|
|
// and then find the dag node using the bone transform.
|
|
int boneIndex = studioHdr.GetAttachmentBone( attachmentIndex );
|
|
CDmeTransform *pBoneTranform = GetBone( boneIndex );
|
|
CDmeDag *pBoneDag = pBoneTranform->GetDag();
|
|
if ( pBoneDag == NULL )
|
|
return NULL;
|
|
|
|
CDmeDag *pDagNode = CreateElement< CDmeDag >( CFmtStr( "attach_%s", pchAttachmentName ), GetFileId() );
|
|
|
|
if ( pDagNode )
|
|
{
|
|
// Position the node based on the attachment position
|
|
const mstudioattachment_t &attachment = studioHdr.pAttachment( attachmentIndex );
|
|
CDmeTransform *pTransform = pDagNode->GetTransform();
|
|
if ( pTransform )
|
|
{
|
|
Vector vAttachmentPos;
|
|
MatrixPosition( attachment.local, vAttachmentPos );
|
|
pTransform->SetPosition( vAttachmentPos );
|
|
}
|
|
|
|
// Make the attachment dag node a child of bone it is associated with
|
|
pBoneDag->AddChild( pDagNode );
|
|
}
|
|
|
|
return pDagNode;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Expose this class to the scene database
|
|
//-----------------------------------------------------------------------------
|
|
IMPLEMENT_ELEMENT_FACTORY( DmeGameSprite, CDmeGameSprite );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGameSprite::OnConstruction()
|
|
{
|
|
m_modelName .Init( this, "modelName" );
|
|
m_frame .Init( this, "frame" );
|
|
m_rendermode.Init( this, "rendermode" );
|
|
m_renderfx .Init( this, "renderfx" );
|
|
m_renderscale.Init( this, "renderscale" );
|
|
m_color .Init( this, "color" );
|
|
m_proxyRadius.Init( this, "proxyRadius" );
|
|
}
|
|
|
|
void CDmeGameSprite::OnDestruction()
|
|
{
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// accessors
|
|
//-----------------------------------------------------------------------------
|
|
const char *CDmeGameSprite::GetModelName() const
|
|
{
|
|
return m_modelName.Get();
|
|
}
|
|
|
|
float CDmeGameSprite::GetScale() const
|
|
{
|
|
return m_renderscale;
|
|
}
|
|
|
|
float CDmeGameSprite::GetFrame() const
|
|
{
|
|
return m_frame;
|
|
}
|
|
|
|
int CDmeGameSprite::GetRenderMode() const
|
|
{
|
|
return m_rendermode;
|
|
}
|
|
|
|
int CDmeGameSprite::GetRenderFX() const
|
|
{
|
|
return m_renderfx;
|
|
}
|
|
|
|
const Color &CDmeGameSprite::GetColor() const
|
|
{
|
|
return m_color;
|
|
}
|
|
|
|
float CDmeGameSprite::GetProxyRadius() const
|
|
{
|
|
return m_proxyRadius;
|
|
}
|
|
|
|
void CDmeGameSprite::SetState( bool bVisible, float nFrame, int nRenderMode, int nRenderFX, float flRenderScale, float flProxyRadius,
|
|
const Vector &pos, const Quaternion &rot, const Color &color )
|
|
{
|
|
m_Visible = bVisible;
|
|
m_frame = nFrame;
|
|
m_rendermode = nRenderMode;
|
|
m_renderfx = nRenderFX;
|
|
m_renderscale = flRenderScale;
|
|
m_proxyRadius = flProxyRadius;
|
|
m_color = color;
|
|
|
|
CDmeTransform *pTransform = GetTransform();
|
|
pTransform->SetPosition( pos );
|
|
pTransform->SetOrientation( rot );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Expose this class to the scene database
|
|
//-----------------------------------------------------------------------------
|
|
IMPLEMENT_ELEMENT_FACTORY( DmeGamePortal, CDmeGamePortal );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CDmeGamePortal::OnConstruction()
|
|
{
|
|
m_flStaticAmount .Init( this, "staticAmount" );
|
|
m_flSecondaryStaticAmount .Init( this, "secondaryStaticAmount" );
|
|
m_flOpenAmount .Init( this, "openAmount" );
|
|
m_flHalfWidth .Init( this, "halfWidth" );
|
|
m_flHalfHeight .Init( this, "halfHeight" );
|
|
m_nPortalId .Init( this, "portalId" );
|
|
m_nLinkedPortalId .Init( this, "linkedPortalId" );
|
|
m_bIsPortal2 .Init( this, "isPortal2" );
|
|
m_PortalType .Init( this, "portalType" );
|
|
}
|
|
|
|
void CDmeGamePortal::OnDestruction()
|
|
{
|
|
}
|
|
|