aboutsummaryrefslogtreecommitdiff
path: root/mp/src/public/studio.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/public/studio.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/public/studio.cpp')
-rw-r--r--mp/src/public/studio.cpp3658
1 files changed, 1829 insertions, 1829 deletions
diff --git a/mp/src/public/studio.cpp b/mp/src/public/studio.cpp
index 643c9e6e..9bf97018 100644
--- a/mp/src/public/studio.cpp
+++ b/mp/src/public/studio.cpp
@@ -1,1830 +1,1830 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-
-#include "studio.h"
-#include "datacache/idatacache.h"
-#include "datacache/imdlcache.h"
-#include "convar.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-mstudioanimdesc_t &studiohdr_t::pAnimdesc( int i ) const
-{
- if (numincludemodels == 0)
- {
- return *pLocalAnimdesc( i );
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_anim[i].group ];
- const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
- Assert( pStudioHdr );
-
- return *pStudioHdr->pLocalAnimdesc( pVModel->m_anim[i].index );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-mstudioanim_t *mstudioanimdesc_t::pAnimBlock( int block, int index ) const
-{
- if (block == -1)
- {
- return (mstudioanim_t *)NULL;
- }
- if (block == 0)
- {
- return (mstudioanim_t *)(((byte *)this) + index);
- }
-
- byte *pAnimBlock = pStudiohdr()->GetAnimBlock( block );
- if ( pAnimBlock )
- {
- return (mstudioanim_t *)(pAnimBlock + index);
- }
-
- return (mstudioanim_t *)NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-static ConVar mod_load_showstall( "mod_load_showstall", "0", 0, "1 - show hitches , 2 - show stalls" );
-mstudioanim_t *mstudioanimdesc_t::pAnim( int *piFrame ) const
-{
- float flStall;
- return pAnim( piFrame, flStall );
-}
-
-mstudioanim_t *mstudioanimdesc_t::pAnim( int *piFrame, float &flStall ) const
-{
- mstudioanim_t *panim = NULL;
-
- int block = animblock;
- int index = animindex;
- int section = 0;
-
- if (sectionframes != 0)
- {
- if (numframes > sectionframes && *piFrame == numframes - 1)
- {
- // last frame on long anims is stored separately
- *piFrame = 0;
- section = (numframes / sectionframes) + 1;
- }
- else
- {
- section = *piFrame / sectionframes;
- *piFrame -= section * sectionframes;
- }
-
- block = pSection( section )->animblock;
- index = pSection( section )->animindex;
- }
-
- if (block == -1)
- {
- // model needs to be recompiled
- return NULL;
- }
-
- panim = pAnimBlock( block, index );
-
- // force a preload on the next block
- if ( sectionframes != 0 )
- {
- int count = ( numframes / sectionframes) + 2;
- for ( int i = section + 1; i < count; i++ )
- {
- if ( pSection( i )->animblock != block )
- {
- pAnimBlock( pSection( i )->animblock, pSection( i )->animindex );
- break;
- }
- }
- }
-
- if (panim == NULL)
- {
- if (section > 0 && mod_load_showstall.GetInt() > 0)
- {
- Msg("[%8.3f] hitch on %s:%s:%d:%d\n", Plat_FloatTime(), pStudiohdr()->pszName(), pszName(), section, block );
- }
- // back up until a previously loaded block is found
- while (--section >= 0)
- {
- block = pSection( section )->animblock;
- index = pSection( section )->animindex;
- panim = pAnimBlock( block, index );
- if (panim)
- {
- // set it to the last frame in the last valid section
- *piFrame = sectionframes - 1;
- break;
- }
- }
- }
-
- // try to guess a valid stall time interval (tuned for the X360)
- flStall = 0.0f;
- if (panim == NULL && section <= 0)
- {
- zeroframestalltime = Plat_FloatTime();
- flStall = 1.0f;
- }
- else if (panim != NULL && zeroframestalltime != 0.0f)
- {
- float dt = Plat_FloatTime() - zeroframestalltime;
- if (dt >= 0.0)
- {
- flStall = SimpleSpline( clamp( (0.200f - dt) * 5.0f, 0.0f, 1.0f ) );
- }
-
- if (flStall == 0.0f)
- {
- // disable stalltime
- zeroframestalltime = 0.0f;
- }
- else if (mod_load_showstall.GetInt() > 1)
- {
- Msg("[%8.3f] stall blend %.2f on %s:%s:%d:%d\n", Plat_FloatTime(), flStall, pStudiohdr()->pszName(), pszName(), section, block );
- }
- }
-
- if (panim == NULL && mod_load_showstall.GetInt() > 1)
- {
- Msg("[%8.3f] stall on %s:%s:%d:%d\n", Plat_FloatTime(), pStudiohdr()->pszName(), pszName(), section, block );
- }
-
- return panim;
-}
-
-mstudioikrule_t *mstudioanimdesc_t::pIKRule( int i ) const
-{
- if (ikruleindex)
- {
- return (mstudioikrule_t *)(((byte *)this) + ikruleindex) + i;
- }
- else if (animblockikruleindex)
- {
- if (animblock == 0)
- {
- return (mstudioikrule_t *)(((byte *)this) + animblockikruleindex) + i;
- }
- else
- {
- byte *pAnimBlocks = pStudiohdr()->GetAnimBlock( animblock );
-
- if ( pAnimBlocks )
- {
- return (mstudioikrule_t *)(pAnimBlocks + animblockikruleindex) + i;
- }
- }
- }
-
- return NULL;
-}
-
-
-mstudiolocalhierarchy_t *mstudioanimdesc_t::pHierarchy( int i ) const
-{
- if (localhierarchyindex)
- {
- if (animblock == 0)
- {
- return (mstudiolocalhierarchy_t *)(((byte *)this) + localhierarchyindex) + i;
- }
- else
- {
- byte *pAnimBlocks = pStudiohdr()->GetAnimBlock( animblock );
-
- if ( pAnimBlocks )
- {
- return (mstudiolocalhierarchy_t *)(pAnimBlocks + localhierarchyindex) + i;
- }
- }
- }
-
- return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-bool studiohdr_t::SequencesAvailable() const
-{
- if (numincludemodels == 0)
- {
- return true;
- }
-
- return ( GetVirtualModel() != NULL );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::GetNumSeq( void ) const
-{
- if (numincludemodels == 0)
- {
- return numlocalseq;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
- return pVModel->m_seq.Count();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-mstudioseqdesc_t &studiohdr_t::pSeqdesc( int i ) const
-{
- if (numincludemodels == 0)
- {
- return *pLocalSeqdesc( i );
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- if ( !pVModel )
- {
- return *pLocalSeqdesc( i );
- }
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[i].group ];
- const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
- Assert( pStudioHdr );
-
- return *pStudioHdr->pLocalSeqdesc( pVModel->m_seq[i].index );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::iRelativeAnim( int baseseq, int relanim ) const
-{
- if (numincludemodels == 0)
- {
- return relanim;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[baseseq].group ];
-
- return pGroup->masterAnim[ relanim ];
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::iRelativeSeq( int baseseq, int relseq ) const
-{
- if (numincludemodels == 0)
- {
- return relseq;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[baseseq].group ];
-
- return pGroup->masterSeq[ relseq ];
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::GetNumPoseParameters( void ) const
-{
- if (numincludemodels == 0)
- {
- return numlocalposeparameters;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- return pVModel->m_pose.Count();
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-const mstudioposeparamdesc_t &studiohdr_t::pPoseParameter( int i )
-{
- if (numincludemodels == 0)
- {
- return *pLocalPoseParameter( i );
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- if ( pVModel->m_pose[i].group == 0)
- return *pLocalPoseParameter( pVModel->m_pose[i].index );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_pose[i].group ];
-
- const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
- Assert( pStudioHdr );
-
- return *pStudioHdr->pLocalPoseParameter( pVModel->m_pose[i].index );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::GetSharedPoseParameter( int iSequence, int iLocalPose ) const
-{
- if (numincludemodels == 0)
- {
- return iLocalPose;
- }
-
- if (iLocalPose == -1)
- return iLocalPose;
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ];
-
- return pGroup->masterPose[iLocalPose];
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::EntryNode( int iSequence )
-{
- mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
-
- if (numincludemodels == 0 || seqdesc.localentrynode == 0)
- {
- return seqdesc.localentrynode;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ];
-
- return pGroup->masterNode[seqdesc.localentrynode-1]+1;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-
-int studiohdr_t::ExitNode( int iSequence )
-{
- mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
-
- if (numincludemodels == 0 || seqdesc.localexitnode == 0)
- {
- return seqdesc.localexitnode;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ];
-
- return pGroup->masterNode[seqdesc.localexitnode-1]+1;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::GetNumAttachments( void ) const
-{
- if (numincludemodels == 0)
- {
- return numlocalattachments;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- return pVModel->m_attachment.Count();
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-const mstudioattachment_t &studiohdr_t::pAttachment( int i ) const
-{
- if (numincludemodels == 0)
- {
- return *pLocalAttachment( i );
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[i].group ];
- const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
- Assert( pStudioHdr );
-
- return *pStudioHdr->pLocalAttachment( pVModel->m_attachment[i].index );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::GetAttachmentBone( int i )
-{
- const mstudioattachment_t &attachment = pAttachment( i );
-
- // remap bone
- virtualmodel_t *pVModel = GetVirtualModel();
- if (pVModel)
- {
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[i].group ];
- int iBone = pGroup->masterBone[attachment.localbone];
- if (iBone == -1)
- return 0;
- return iBone;
- }
- return attachment.localbone;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-void studiohdr_t::SetAttachmentBone( int iAttachment, int iBone )
-{
- mstudioattachment_t &attachment = (mstudioattachment_t &)pAttachment( iAttachment );
-
- // remap bone
- virtualmodel_t *pVModel = GetVirtualModel();
- if (pVModel)
- {
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[iAttachment].group ];
- iBone = pGroup->boneMap[iBone];
- }
- attachment.localbone = iBone;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-char *studiohdr_t::pszNodeName( int iNode )
-{
- if (numincludemodels == 0)
- {
- return pszLocalNodeName( iNode );
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- if ( pVModel->m_node.Count() <= iNode-1 )
- return "Invalid node";
-
- return pVModel->m_group[ pVModel->m_node[iNode-1].group ].GetStudioHdr()->pszLocalNodeName( pVModel->m_node[iNode-1].index );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::GetTransition( int iFrom, int iTo ) const
-{
- if (numincludemodels == 0)
- {
- return *pLocalTransition( (iFrom-1)*numlocalnodes + (iTo - 1) );
- }
-
- return iTo;
- /*
- FIXME: not connected
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- return pVModel->m_transition.Element( iFrom ).Element( iTo );
- */
-}
-
-
-int studiohdr_t::GetActivityListVersion( void )
-{
- if (numincludemodels == 0)
- {
- return activitylistversion;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- int version = activitylistversion;
-
- int i;
- for (i = 1; i < pVModel->m_group.Count(); i++)
- {
- virtualgroup_t *pGroup = &pVModel->m_group[ i ];
- const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
-
- Assert( pStudioHdr );
-
- version = min( version, pStudioHdr->activitylistversion );
- }
-
- return version;
-}
-
-void studiohdr_t::SetActivityListVersion( int version ) const
-{
- activitylistversion = version;
-
- if (numincludemodels == 0)
- {
- return;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- int i;
- for (i = 1; i < pVModel->m_group.Count(); i++)
- {
- virtualgroup_t *pGroup = &pVModel->m_group[ i ];
- const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
-
- Assert( pStudioHdr );
-
- pStudioHdr->SetActivityListVersion( version );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-
-int studiohdr_t::GetNumIKAutoplayLocks( void ) const
-{
- if (numincludemodels == 0)
- {
- return numlocalikautoplaylocks;
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- return pVModel->m_iklock.Count();
-}
-
-const mstudioiklock_t &studiohdr_t::pIKAutoplayLock( int i )
-{
- if (numincludemodels == 0)
- {
- return *pLocalIKAutoplayLock( i );
- }
-
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_iklock[i].group ];
- const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
- Assert( pStudioHdr );
-
- return *pStudioHdr->pLocalIKAutoplayLock( pVModel->m_iklock[i].index );
-}
-
-int studiohdr_t::CountAutoplaySequences() const
-{
- int count = 0;
- for (int i = 0; i < GetNumSeq(); i++)
- {
- mstudioseqdesc_t &seqdesc = pSeqdesc( i );
- if (seqdesc.flags & STUDIO_AUTOPLAY)
- {
- count++;
- }
- }
- return count;
-}
-
-int studiohdr_t::CopyAutoplaySequences( unsigned short *pOut, int outCount ) const
-{
- int outIndex = 0;
- for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++)
- {
- mstudioseqdesc_t &seqdesc = pSeqdesc( i );
- if (seqdesc.flags & STUDIO_AUTOPLAY)
- {
- pOut[outIndex] = i;
- outIndex++;
- }
- }
- return outIndex;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: maps local sequence bone to global bone
-//-----------------------------------------------------------------------------
-
-int studiohdr_t::RemapSeqBone( int iSequence, int iLocalBone ) const
-{
- // remap bone
- virtualmodel_t *pVModel = GetVirtualModel();
- if (pVModel)
- {
- const virtualgroup_t *pSeqGroup = pVModel->pSeqGroup( iSequence );
- return pSeqGroup->masterBone[iLocalBone];
- }
- return iLocalBone;
-}
-
-int studiohdr_t::RemapAnimBone( int iAnim, int iLocalBone ) const
-{
- // remap bone
- virtualmodel_t *pVModel = GetVirtualModel();
- if (pVModel)
- {
- const virtualgroup_t *pAnimGroup = pVModel->pAnimGroup( iAnim );
- return pAnimGroup->masterBone[iLocalBone];
- }
- return iLocalBone;
-}
-
-
-
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-CStudioHdr::CStudioHdr( void )
-{
- // set pointer to bogus value
- m_nFrameUnlockCounter = 0;
- m_pFrameUnlockCounter = &m_nFrameUnlockCounter;
- Init( NULL );
-}
-
-CStudioHdr::CStudioHdr( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache )
-{
- // preset pointer to bogus value (it may be overwritten with legitimate data later)
- m_nFrameUnlockCounter = 0;
- m_pFrameUnlockCounter = &m_nFrameUnlockCounter;
- Init( pStudioHdr, mdlcache );
-}
-
-
-// extern IDataCache *g_pDataCache;
-
-void CStudioHdr::Init( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache )
-{
- m_pStudioHdr = pStudioHdr;
-
- m_pVModel = NULL;
- m_pStudioHdrCache.RemoveAll();
-
- if (m_pStudioHdr == NULL)
- {
- return;
- }
-
- if ( mdlcache )
- {
- m_pFrameUnlockCounter = mdlcache->GetFrameUnlockCounterPtr( MDLCACHE_STUDIOHDR );
- m_nFrameUnlockCounter = *m_pFrameUnlockCounter - 1;
- }
-
- if (m_pStudioHdr->numincludemodels == 0)
- {
-#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE
-#else
- m_ActivityToSequence.Initialize(this);
-#endif
- }
- else
- {
- ResetVModel( m_pStudioHdr->GetVirtualModel() );
-#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE
-#else
- m_ActivityToSequence.Initialize(this);
-#endif
- }
-
- m_boneFlags.EnsureCount( numbones() );
- m_boneParent.EnsureCount( numbones() );
- for (int i = 0; i < numbones(); i++)
- {
- m_boneFlags[i] = pBone( i )->flags;
- m_boneParent[i] = pBone( i )->parent;
- }
-}
-
-void CStudioHdr::Term()
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-bool CStudioHdr::SequencesAvailable() const
-{
- if (m_pStudioHdr->numincludemodels == 0)
- {
- return true;
- }
-
- if (m_pVModel == NULL)
- {
- // repoll m_pVModel
- return (ResetVModel( m_pStudioHdr->GetVirtualModel() ) != NULL);
- }
- else
- return true;
-}
-
-
-const virtualmodel_t * CStudioHdr::ResetVModel( const virtualmodel_t *pVModel ) const
-{
- if (pVModel != NULL)
- {
- m_pVModel = (virtualmodel_t *)pVModel;
- Assert( !pVModel->m_Lock.GetOwnerId() );
- m_pStudioHdrCache.SetCount( m_pVModel->m_group.Count() );
-
- int i;
- for (i = 0; i < m_pStudioHdrCache.Count(); i++)
- {
- m_pStudioHdrCache[ i ] = NULL;
- }
-
- return const_cast<virtualmodel_t *>(pVModel);
- }
- else
- {
- m_pVModel = NULL;
- return NULL;
- }
-}
-
-const studiohdr_t *CStudioHdr::GroupStudioHdr( int i )
-{
- if ( !this )
- {
- ExecuteNTimes( 5, Warning( "Call to NULL CStudioHdr::GroupStudioHdr()\n" ) );
- }
-
- if ( m_nFrameUnlockCounter != *m_pFrameUnlockCounter )
- {
- m_FrameUnlockCounterMutex.Lock();
- if ( *m_pFrameUnlockCounter != m_nFrameUnlockCounter ) // i.e., this thread got the mutex
- {
- memset( m_pStudioHdrCache.Base(), 0, m_pStudioHdrCache.Count() * sizeof(studiohdr_t *) );
- m_nFrameUnlockCounter = *m_pFrameUnlockCounter;
- }
- m_FrameUnlockCounterMutex.Unlock();
- }
-
- if ( !m_pStudioHdrCache.IsValidIndex( i ) )
- {
- const char *pszName = ( m_pStudioHdr ) ? m_pStudioHdr->pszName() : "<<null>>";
- ExecuteNTimes( 5, Warning( "Invalid index passed to CStudioHdr(%s)::GroupStudioHdr(): %d, but max is %d\n", pszName, i, m_pStudioHdrCache.Count() ) );
- DebuggerBreakIfDebugging();
- return m_pStudioHdr; // return something known to probably exist, certainly things will be messed up, but hopefully not crash before the warning is noticed
- }
-
- const studiohdr_t *pStudioHdr = m_pStudioHdrCache[ i ];
-
- if (pStudioHdr == NULL)
- {
- Assert( !m_pVModel->m_Lock.GetOwnerId() );
- virtualgroup_t *pGroup = &m_pVModel->m_group[ i ];
- pStudioHdr = pGroup->GetStudioHdr();
- m_pStudioHdrCache[ i ] = pStudioHdr;
- }
-
- Assert( pStudioHdr );
- return pStudioHdr;
-}
-
-
-const studiohdr_t *CStudioHdr::pSeqStudioHdr( int sequence )
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr;
- }
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_seq[sequence].group );
-
- return pStudioHdr;
-}
-
-
-const studiohdr_t *CStudioHdr::pAnimStudioHdr( int animation )
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr;
- }
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_anim[animation].group );
-
- return pStudioHdr;
-}
-
-
-
-mstudioanimdesc_t &CStudioHdr::pAnimdesc( int i )
-{
- if (m_pVModel == NULL)
- {
- return *m_pStudioHdr->pLocalAnimdesc( i );
- }
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_anim[i].group );
-
- return *pStudioHdr->pLocalAnimdesc( m_pVModel->m_anim[i].index );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetNumSeq( void ) const
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr->numlocalseq;
- }
-
- return m_pVModel->m_seq.Count();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-mstudioseqdesc_t &CStudioHdr::pSeqdesc( int i )
-{
- Assert( ( i >= 0 && i < GetNumSeq() ) || ( i == 1 && GetNumSeq() <= 1 ) );
- if ( i < 0 || i >= GetNumSeq() )
- {
- // Avoid reading random memory.
- i = 0;
- }
-
- if (m_pVModel == NULL)
- {
- return *m_pStudioHdr->pLocalSeqdesc( i );
- }
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_seq[i].group );
-
- return *pStudioHdr->pLocalSeqdesc( m_pVModel->m_seq[i].index );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::iRelativeAnim( int baseseq, int relanim ) const
-{
- if (m_pVModel == NULL)
- {
- return relanim;
- }
-
- virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[baseseq].group ];
-
- return pGroup->masterAnim[ relanim ];
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::iRelativeSeq( int baseseq, int relseq ) const
-{
- if (m_pVModel == NULL)
- {
- return relseq;
- }
-
- Assert( m_pVModel );
-
- virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[baseseq].group ];
-
- return pGroup->masterSeq[ relseq ];
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetNumPoseParameters( void ) const
-{
- if (m_pVModel == NULL)
- {
- if ( m_pStudioHdr )
- return m_pStudioHdr->numlocalposeparameters;
- else
- return 0;
- }
-
- Assert( m_pVModel );
-
- return m_pVModel->m_pose.Count();
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-const mstudioposeparamdesc_t &CStudioHdr::pPoseParameter( int i )
-{
- if (m_pVModel == NULL)
- {
- return *m_pStudioHdr->pLocalPoseParameter( i );
- }
-
- if ( m_pVModel->m_pose[i].group == 0)
- return *m_pStudioHdr->pLocalPoseParameter( m_pVModel->m_pose[i].index );
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_pose[i].group );
-
- return *pStudioHdr->pLocalPoseParameter( m_pVModel->m_pose[i].index );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetSharedPoseParameter( int iSequence, int iLocalPose ) const
-{
- if (m_pVModel == NULL)
- {
- return iLocalPose;
- }
-
- if (iLocalPose == -1)
- return iLocalPose;
-
- Assert( m_pVModel );
-
- virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ];
-
- return pGroup->masterPose[iLocalPose];
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::EntryNode( int iSequence )
-{
- mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
-
- if (m_pVModel == NULL || seqdesc.localentrynode == 0)
- {
- return seqdesc.localentrynode;
- }
-
- Assert( m_pVModel );
-
- virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ];
-
- return pGroup->masterNode[seqdesc.localentrynode-1]+1;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-
-int CStudioHdr::ExitNode( int iSequence )
-{
- mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
-
- if (m_pVModel == NULL || seqdesc.localexitnode == 0)
- {
- return seqdesc.localexitnode;
- }
-
- Assert( m_pVModel );
-
- virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ];
-
- return pGroup->masterNode[seqdesc.localexitnode-1]+1;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetNumAttachments( void ) const
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr->numlocalattachments;
- }
-
- Assert( m_pVModel );
-
- return m_pVModel->m_attachment.Count();
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-const mstudioattachment_t &CStudioHdr::pAttachment( int i )
-{
- if (m_pVModel == NULL)
- {
- return *m_pStudioHdr->pLocalAttachment( i );
- }
-
- Assert( m_pVModel );
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_attachment[i].group );
-
- return *pStudioHdr->pLocalAttachment( m_pVModel->m_attachment[i].index );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetAttachmentBone( int i )
-{
- if (m_pVModel == 0)
- {
- return m_pStudioHdr->pLocalAttachment( i )->localbone;
- }
-
- virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_attachment[i].group ];
- const mstudioattachment_t &attachment = pAttachment( i );
- int iBone = pGroup->masterBone[attachment.localbone];
- if (iBone == -1)
- return 0;
- return iBone;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-void CStudioHdr::SetAttachmentBone( int iAttachment, int iBone )
-{
- mstudioattachment_t &attachment = (mstudioattachment_t &)m_pStudioHdr->pAttachment( iAttachment );
-
- // remap bone
- if (m_pVModel)
- {
- virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_attachment[iAttachment].group ];
- iBone = pGroup->boneMap[iBone];
- }
- attachment.localbone = iBone;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-char *CStudioHdr::pszNodeName( int iNode )
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr->pszLocalNodeName( iNode );
- }
-
- if ( m_pVModel->m_node.Count() <= iNode-1 )
- return "Invalid node";
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_node[iNode-1].group );
-
- return pStudioHdr->pszLocalNodeName( m_pVModel->m_node[iNode-1].index );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetTransition( int iFrom, int iTo ) const
-{
- if (m_pVModel == NULL)
- {
- return *m_pStudioHdr->pLocalTransition( (iFrom-1)*m_pStudioHdr->numlocalnodes + (iTo - 1) );
- }
-
- return iTo;
- /*
- FIXME: not connected
- virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
- Assert( pVModel );
-
- return pVModel->m_transition.Element( iFrom ).Element( iTo );
- */
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetActivityListVersion( void )
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr->activitylistversion;
- }
-
- int version = m_pStudioHdr->activitylistversion;
-
- int i;
- for (i = 1; i < m_pVModel->m_group.Count(); i++)
- {
- const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
- Assert( pStudioHdr );
- version = min( version, pStudioHdr->activitylistversion );
- }
-
- return version;
-}
-
-void CStudioHdr::SetActivityListVersion( int version )
-{
- m_pStudioHdr->activitylistversion = version;
-
- if (m_pVModel == NULL)
- {
- return;
- }
-
- int i;
- for (i = 1; i < m_pVModel->m_group.Count(); i++)
- {
- const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
- Assert( pStudioHdr );
- pStudioHdr->SetActivityListVersion( version );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::GetEventListVersion( void )
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr->eventsindexed;
- }
-
- int version = m_pStudioHdr->eventsindexed;
-
- int i;
- for (i = 1; i < m_pVModel->m_group.Count(); i++)
- {
- const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
- Assert( pStudioHdr );
- version = min( version, pStudioHdr->eventsindexed );
- }
-
- return version;
-}
-
-void CStudioHdr::SetEventListVersion( int version )
-{
- m_pStudioHdr->eventsindexed = version;
-
- if (m_pVModel == NULL)
- {
- return;
- }
-
- int i;
- for (i = 1; i < m_pVModel->m_group.Count(); i++)
- {
- const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
- Assert( pStudioHdr );
- pStudioHdr->eventsindexed = version;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-
-int CStudioHdr::GetNumIKAutoplayLocks( void ) const
-{
- if (m_pVModel == NULL)
- {
- return m_pStudioHdr->numlocalikautoplaylocks;
- }
-
- return m_pVModel->m_iklock.Count();
-}
-
-const mstudioiklock_t &CStudioHdr::pIKAutoplayLock( int i )
-{
- if (m_pVModel == NULL)
- {
- return *m_pStudioHdr->pLocalIKAutoplayLock( i );
- }
-
- const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_iklock[i].group );
- Assert( pStudioHdr );
- return *pStudioHdr->pLocalIKAutoplayLock( m_pVModel->m_iklock[i].index );
-}
-
-#if 0
-int CStudioHdr::CountAutoplaySequences() const
-{
- int count = 0;
- for (int i = 0; i < GetNumSeq(); i++)
- {
- mstudioseqdesc_t &seqdesc = pSeqdesc( i );
- if (seqdesc.flags & STUDIO_AUTOPLAY)
- {
- count++;
- }
- }
- return count;
-}
-
-int CStudioHdr::CopyAutoplaySequences( unsigned short *pOut, int outCount ) const
-{
- int outIndex = 0;
- for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++)
- {
- mstudioseqdesc_t &seqdesc = pSeqdesc( i );
- if (seqdesc.flags & STUDIO_AUTOPLAY)
- {
- pOut[outIndex] = i;
- outIndex++;
- }
- }
- return outIndex;
-}
-
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose: maps local sequence bone to global bone
-//-----------------------------------------------------------------------------
-
-int CStudioHdr::RemapSeqBone( int iSequence, int iLocalBone ) const
-{
- // remap bone
- if (m_pVModel)
- {
- const virtualgroup_t *pSeqGroup = m_pVModel->pSeqGroup( iSequence );
- return pSeqGroup->masterBone[iLocalBone];
- }
- return iLocalBone;
-}
-
-int CStudioHdr::RemapAnimBone( int iAnim, int iLocalBone ) const
-{
- // remap bone
- if (m_pVModel)
- {
- const virtualgroup_t *pAnimGroup = m_pVModel->pAnimGroup( iAnim );
- return pAnimGroup->masterBone[iLocalBone];
- }
- return iLocalBone;
-}
-
-// JasonM hack
-//ConVar flex_maxrule( "flex_maxrule", "0" );
-
-
-//-----------------------------------------------------------------------------
-// Purpose: run the interpreted FAC's expressions, converting flex_controller
-// values into FAC weights
-//-----------------------------------------------------------------------------
-void CStudioHdr::RunFlexRules( const float *src, float *dest )
-{
- int i, j;
-
- // FIXME: this shouldn't be needed, flex without rules should be stripped in studiomdl
- for (i = 0; i < numflexdesc(); i++)
- {
- dest[i] = 0;
- }
-
- for (i = 0; i < numflexrules(); i++)
- {
- float stack[32] = {};
- int k = 0;
- mstudioflexrule_t *prule = pFlexRule( i );
-
- mstudioflexop_t *pops = prule->iFlexOp( 0 );
-/*
- // JasonM hack for flex perf testing...
- int nFlexRulesToRun = 0; // 0 means run them all
- const char *pszExpression = flex_maxrule.GetString();
- if ( pszExpression )
- {
- nFlexRulesToRun = atoi(pszExpression); // 0 will be returned if not a numeric string
- }
- // end JasonM hack
-//*/
- // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), i + 1, 0, "%2d:%d\n", i, prule->flex );
-
- for (j = 0; j < prule->numops; j++)
- {
- switch (pops->op)
- {
- case STUDIO_ADD: stack[k-2] = stack[k-2] + stack[k-1]; k--; break;
- case STUDIO_SUB: stack[k-2] = stack[k-2] - stack[k-1]; k--; break;
- case STUDIO_MUL: stack[k-2] = stack[k-2] * stack[k-1]; k--; break;
- case STUDIO_DIV:
- if (stack[k-1] > 0.0001)
- {
- stack[k-2] = stack[k-2] / stack[k-1];
- }
- else
- {
- stack[k-2] = 0;
- }
- k--;
- break;
- case STUDIO_NEG: stack[k-1] = -stack[k-1]; break;
- case STUDIO_MAX: stack[k-2] = max( stack[k-2], stack[k-1] ); k--; break;
- case STUDIO_MIN: stack[k-2] = min( stack[k-2], stack[k-1] ); k--; break;
- case STUDIO_CONST: stack[k] = pops->d.value; k++; break;
- case STUDIO_FETCH1:
- {
- int m = pFlexcontroller( (LocalFlexController_t)pops->d.index)->localToGlobal;
- stack[k] = src[m];
- k++;
- break;
- }
- case STUDIO_FETCH2:
- {
- stack[k] = dest[pops->d.index]; k++; break;
- }
- case STUDIO_COMBO:
- {
- int m = pops->d.index;
- int km = k - m;
- for ( int i = km + 1; i < k; ++i )
- {
- stack[ km ] *= stack[ i ];
- }
- k = k - m + 1;
- }
- break;
- case STUDIO_DOMINATE:
- {
- int m = pops->d.index;
- int km = k - m;
- float dv = stack[ km ];
- for ( int i = km + 1; i < k; ++i )
- {
- dv *= stack[ i ];
- }
- stack[ km - 1 ] *= 1.0f - dv;
- k -= m;
- }
- break;
- case STUDIO_2WAY_0:
- {
- int m = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal;
- stack[ k ] = RemapValClamped( src[m], -1.0f, 0.0f, 1.0f, 0.0f );
- k++;
- }
- break;
- case STUDIO_2WAY_1:
- {
- int m = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal;
- stack[ k ] = RemapValClamped( src[m], 0.0f, 1.0f, 0.0f, 1.0f );
- k++;
- }
- break;
- case STUDIO_NWAY:
- {
- LocalFlexController_t valueControllerIndex = static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] );
- int m = pFlexcontroller( valueControllerIndex )->localToGlobal;
- float flValue = src[ m ];
- int v = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal;
-
- const Vector4D filterRamp( stack[ k - 5 ], stack[ k - 4 ], stack[ k - 3 ], stack[ k - 2 ] );
-
- // Apply multicontrol remapping
- if ( flValue <= filterRamp.x || flValue >= filterRamp.w )
- {
- flValue = 0.0f;
- }
- else if ( flValue < filterRamp.y )
- {
- flValue = RemapValClamped( flValue, filterRamp.x, filterRamp.y, 0.0f, 1.0f );
- }
- else if ( flValue > filterRamp.z )
- {
- flValue = RemapValClamped( flValue, filterRamp.z, filterRamp.w, 1.0f, 0.0f );
- }
- else
- {
- flValue = 1.0f;
- }
-
- stack[ k - 5 ] = flValue * src[ v ];
-
- k -= 4;
- }
- break;
- case STUDIO_DME_LOWER_EYELID:
- {
- const mstudioflexcontroller_t *const pCloseLidV = pFlexcontroller( (LocalFlexController_t)pops->d.index );
- const float flCloseLidV = RemapValClamped( src[ pCloseLidV->localToGlobal ], pCloseLidV->min, pCloseLidV->max, 0.0f, 1.0f );
-
- const mstudioflexcontroller_t *const pCloseLid = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] ) );
- const float flCloseLid = RemapValClamped( src[ pCloseLid->localToGlobal ], pCloseLid->min, pCloseLid->max, 0.0f, 1.0f );
-
- int nBlinkIndex = static_cast< int >( stack[ k - 2 ] );
- float flBlink = 0.0f;
- if ( nBlinkIndex >= 0 )
- {
- const mstudioflexcontroller_t *const pBlink = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 2 ] ) );
- flBlink = RemapValClamped( src[ pBlink->localToGlobal ], pBlink->min, pBlink->max, 0.0f, 1.0f );
- }
-
- int nEyeUpDownIndex = static_cast< int >( stack[ k - 3 ] );
- float flEyeUpDown = 0.0f;
- if ( nEyeUpDownIndex >= 0 )
- {
- const mstudioflexcontroller_t *const pEyeUpDown = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 3 ] ) );
- flEyeUpDown = RemapValClamped( src[ pEyeUpDown->localToGlobal ], pEyeUpDown->min, pEyeUpDown->max, -1.0f, 1.0f );
- }
-
- if ( flEyeUpDown > 0.0 )
- {
- stack [ k - 3 ] = ( 1.0f - flEyeUpDown ) * ( 1.0f - flCloseLidV ) * flCloseLid;
- }
- else
- {
- stack [ k - 3 ] = ( 1.0f - flCloseLidV ) * flCloseLid;
- }
- k -= 2;
- }
- break;
- case STUDIO_DME_UPPER_EYELID:
- {
- const mstudioflexcontroller_t *const pCloseLidV = pFlexcontroller( (LocalFlexController_t)pops->d.index );
- const float flCloseLidV = RemapValClamped( src[ pCloseLidV->localToGlobal ], pCloseLidV->min, pCloseLidV->max, 0.0f, 1.0f );
-
- const mstudioflexcontroller_t *const pCloseLid = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] ) );
- const float flCloseLid = RemapValClamped( src[ pCloseLid->localToGlobal ], pCloseLid->min, pCloseLid->max, 0.0f, 1.0f );
-
- int nBlinkIndex = static_cast< int >( stack[ k - 2 ] );
- float flBlink = 0.0f;
- if ( nBlinkIndex >= 0 )
- {
- const mstudioflexcontroller_t *const pBlink = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 2 ] ) );
- flBlink = RemapValClamped( src[ pBlink->localToGlobal ], pBlink->min, pBlink->max, 0.0f, 1.0f );
- }
-
- int nEyeUpDownIndex = static_cast< int >( stack[ k - 3 ] );
- float flEyeUpDown = 0.0f;
- if ( nEyeUpDownIndex >= 0 )
- {
- const mstudioflexcontroller_t *const pEyeUpDown = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 3 ] ) );
- flEyeUpDown = RemapValClamped( src[ pEyeUpDown->localToGlobal ], pEyeUpDown->min, pEyeUpDown->max, -1.0f, 1.0f );
- }
-
- if ( flEyeUpDown < 0.0f )
- {
- stack [ k - 3 ] = ( 1.0f + flEyeUpDown ) * flCloseLidV * flCloseLid;
- }
- else
- {
- stack [ k - 3 ] = flCloseLidV * flCloseLid;
- }
- k -= 2;
- }
- break;
- }
-
- pops++;
- }
-
- dest[prule->flex] = stack[0];
-/*
- // JasonM hack
- if ( nFlexRulesToRun == 0) // 0 means run all rules correctly
- {
- dest[prule->flex] = stack[0];
- }
- else // run only up to nFlexRulesToRun correctly...zero out the rest
- {
- if ( j < nFlexRulesToRun )
- dest[prule->flex] = stack[0];
- else
- dest[prule->flex] = 0.0f;
- }
-
- dest[prule->flex] = 1.0f;
-//*/
- // end JasonM hack
-
- }
-}
-
-
-
-//-----------------------------------------------------------------------------
-// CODE PERTAINING TO ACTIVITY->SEQUENCE MAPPING SUBCLASS
-//-----------------------------------------------------------------------------
-#define iabs(i) (( (i) >= 0 ) ? (i) : -(i) )
-
-
-extern void SetActivityForSequence( CStudioHdr *pstudiohdr, int i );
-void CStudioHdr::CActivityToSequenceMapping::Initialize( CStudioHdr * __restrict pstudiohdr )
-{
- // Algorithm: walk through every sequence in the model, determine to which activity
- // it corresponds, and keep a count of sequences per activity. Once the total count
- // is available, allocate an array large enough to contain them all, update the
- // starting indices for every activity's section in the array, and go back through,
- // populating the array with its data.
-
- AssertMsg1( m_pSequenceTuples == NULL, "Tried to double-initialize sequence mapping for %s", pstudiohdr->pszName() );
- if ( m_pSequenceTuples != NULL )
- return; // don't double initialize.
-
- SetValidationPair(pstudiohdr);
-
- if ( ! pstudiohdr->SequencesAvailable() )
- return; // nothing to do.
-
-#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE
- m_bIsInitialized = true;
-#endif
-
- // Some studio headers have no activities at all. In those
- // cases we can avoid a lot of this effort.
- bool bFoundOne = false;
-
- // for each sequence in the header...
- const int NumSeq = pstudiohdr->GetNumSeq();
- for ( int i = 0 ; i < NumSeq ; ++i )
- {
- const mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
-#if defined(SERVER_DLL) || defined(CLIENT_DLL) || defined(GAME_DLL)
- if (!(seqdesc.flags & STUDIO_ACTIVITY))
- {
- // AssertMsg2( false, "Sequence %d on studiohdr %s didn't have its activity initialized!", i, pstudiohdr->pszName() );
- SetActivityForSequence( pstudiohdr, i );
- }
-#endif
-
- // is there an activity associated with this sequence?
- if (seqdesc.activity >= 0)
- {
- bFoundOne = true;
-
- // look up if we already have an entry. First we need to make a speculative one --
- HashValueType entry(seqdesc.activity, 0, 1, iabs(seqdesc.actweight));
- UtlHashHandle_t handle = m_ActToSeqHash.Find(entry);
- if ( m_ActToSeqHash.IsValidHandle(handle) )
- {
- // we already have an entry and must update it by incrementing count
- HashValueType * __restrict toUpdate = &m_ActToSeqHash.Element(handle);
- toUpdate->count += 1;
- toUpdate->totalWeight += iabs(seqdesc.actweight);
- Assert( toUpdate->totalWeight > 0 );
- }
- else
- {
- // we do not have an entry yet; create one.
- m_ActToSeqHash.Insert(entry);
- }
- }
- }
-
- // if we found nothing, don't bother with any other initialization!
- if (!bFoundOne)
- return;
-
- // Now, create starting indices for each activity. For an activity n,
- // the starting index is of course the sum of counts [0..n-1].
- register int sequenceCount = 0;
- int topActivity = 0; // this will store the highest seen activity number (used later to make an ad hoc map on the stack)
- for ( UtlHashHandle_t handle = m_ActToSeqHash.GetFirstHandle() ;
- m_ActToSeqHash.IsValidHandle(handle) ;
- handle = m_ActToSeqHash.GetNextHandle(handle) )
- {
- HashValueType &element = m_ActToSeqHash[handle];
- element.startingIdx = sequenceCount;
- sequenceCount += element.count;
- topActivity = max(topActivity, element.activityIdx);
- }
-
-
- // Allocate the actual array of sequence information. Note the use of restrict;
- // this is an important optimization, but means that you must never refer to this
- // array through m_pSequenceTuples in the scope of this function.
- SequenceTuple * __restrict tupleList = new SequenceTuple[sequenceCount];
- m_pSequenceTuples = tupleList; // save it off -- NEVER USE m_pSequenceTuples in this function!
- m_iSequenceTuplesCount = sequenceCount;
-
-
-
- // Now we're going to actually populate that list with the relevant data.
- // First, create an array on the stack to store how many sequences we've written
- // so far for each activity. (This is basically a very simple way of doing a map.)
- // This stack may potentially grow very large; so if you have problems with it,
- // go to a utlmap or similar structure.
- unsigned int allocsize = (topActivity + 1) * sizeof(int);
-#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) // need macro for constant expression
- allocsize = ALIGN_VALUE(allocsize,16);
- int * __restrict seqsPerAct = static_cast<int *>(stackalloc(allocsize));
- memset(seqsPerAct, 0, allocsize);
-
- // okay, walk through all the sequences again, and write the relevant data into
- // our little table.
- for ( int i = 0 ; i < NumSeq ; ++i )
- {
- const mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
- if (seqdesc.activity >= 0)
- {
- const HashValueType &element = m_ActToSeqHash[m_ActToSeqHash.Find(HashValueType(seqdesc.activity, 0, 0, 0))];
-
- // If this assert trips, we've written more sequences per activity than we allocated
- // (therefore there must have been a miscount in the first for loop above).
- int tupleOffset = seqsPerAct[seqdesc.activity];
- Assert( tupleOffset < element.count );
-
- // You might be tempted to collapse this pointer math into a single pointer --
- // don't! the tuple list is marked __restrict above.
- (tupleList + element.startingIdx + tupleOffset)->seqnum = i; // store sequence number
- (tupleList + element.startingIdx + tupleOffset)->weight = iabs(seqdesc.actweight);
-
- // We can't have weights of 0
- // Assert( (tupleList + element.startingIdx + tupleOffset)->weight > 0 );
- if ( (tupleList + element.startingIdx + tupleOffset)->weight == 0 )
- {
- (tupleList + element.startingIdx + tupleOffset)->weight = 1;
- }
-
- seqsPerAct[seqdesc.activity] += 1;
- }
- }
-
-#ifdef DBGFLAG_ASSERT
- // double check that we wrote exactly the right number of sequences.
- unsigned int chkSequenceCount = 0;
- for (int j = 0 ; j <= topActivity ; ++j)
- {
- chkSequenceCount += seqsPerAct[j];
- }
- Assert(chkSequenceCount == m_iSequenceTuplesCount);
-#endif
-
-}
-
-/// Force Initialize() to occur again, even if it has already occured.
-void CStudioHdr::CActivityToSequenceMapping::Reinitialize( CStudioHdr *pstudiohdr )
-{
- m_bIsInitialized = false;
- if (m_pSequenceTuples)
- {
- delete m_pSequenceTuples;
- m_pSequenceTuples = NULL;
- }
- m_ActToSeqHash.RemoveAll();
-
- Initialize(pstudiohdr);
-}
-
-// Look up relevant data for an activity's sequences. This isn't terribly efficient, due to the
-// load-hit-store on the output parameters, so the most common case -- SelectWeightedSequence --
-// is specially implemented.
-const CStudioHdr::CActivityToSequenceMapping::SequenceTuple *CStudioHdr::CActivityToSequenceMapping::GetSequences( int forActivity, int * __restrict outSequenceCount, int * __restrict outTotalWeight )
-{
- // Construct a dummy entry so we can do a hash lookup (the UtlHash does not divorce keys from values)
-
- HashValueType entry(forActivity, 0, 0, 0);
- UtlHashHandle_t handle = m_ActToSeqHash.Find(entry);
-
- if (m_ActToSeqHash.IsValidHandle(handle))
- {
- const HashValueType &element = m_ActToSeqHash[handle];
- const SequenceTuple *retval = m_pSequenceTuples + element.startingIdx;
- *outSequenceCount = element.count;
- *outTotalWeight = element.totalWeight;
-
- return retval;
- }
- else
- {
- // invalid handle; return NULL.
- // this is actually a legit use case, so no need to assert.
- return NULL;
- }
-}
-
-int CStudioHdr::CActivityToSequenceMapping::NumSequencesForActivity( int forActivity )
-{
- // If this trips, you've called this function on something that doesn't
- // have activities.
- //Assert(m_pSequenceTuples != NULL);
- if ( m_pSequenceTuples == NULL )
- return 0;
-
- HashValueType entry(forActivity, 0, 0, 0);
- UtlHashHandle_t handle = m_ActToSeqHash.Find(entry);
- if (m_ActToSeqHash.IsValidHandle(handle))
- {
- return m_ActToSeqHash[handle].count;
- }
- else
- {
- return 0;
- }
-}
-
-// double-check that the data I point to hasn't changed
-bool CStudioHdr::CActivityToSequenceMapping::ValidateAgainst( const CStudioHdr * RESTRICT pstudiohdr ) RESTRICT
-{
- if (m_bIsInitialized)
- {
- return m_expectedPStudioHdr == pstudiohdr->GetRenderHdr() &&
- m_expectedVModel == pstudiohdr->GetVirtualModel();
- }
- else
- {
- return true; // Allow an ordinary initialization to take place without printing a panicky assert.
- }
-}
-
-void CStudioHdr::CActivityToSequenceMapping::SetValidationPair( const CStudioHdr *RESTRICT pstudiohdr ) RESTRICT
-{
- m_expectedPStudioHdr = pstudiohdr->GetRenderHdr();
- m_expectedVModel = pstudiohdr->GetVirtualModel();
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "studio.h"
+#include "datacache/idatacache.h"
+#include "datacache/imdlcache.h"
+#include "convar.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+mstudioanimdesc_t &studiohdr_t::pAnimdesc( int i ) const
+{
+ if (numincludemodels == 0)
+ {
+ return *pLocalAnimdesc( i );
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_anim[i].group ];
+ const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
+ Assert( pStudioHdr );
+
+ return *pStudioHdr->pLocalAnimdesc( pVModel->m_anim[i].index );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+mstudioanim_t *mstudioanimdesc_t::pAnimBlock( int block, int index ) const
+{
+ if (block == -1)
+ {
+ return (mstudioanim_t *)NULL;
+ }
+ if (block == 0)
+ {
+ return (mstudioanim_t *)(((byte *)this) + index);
+ }
+
+ byte *pAnimBlock = pStudiohdr()->GetAnimBlock( block );
+ if ( pAnimBlock )
+ {
+ return (mstudioanim_t *)(pAnimBlock + index);
+ }
+
+ return (mstudioanim_t *)NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+static ConVar mod_load_showstall( "mod_load_showstall", "0", 0, "1 - show hitches , 2 - show stalls" );
+mstudioanim_t *mstudioanimdesc_t::pAnim( int *piFrame ) const
+{
+ float flStall;
+ return pAnim( piFrame, flStall );
+}
+
+mstudioanim_t *mstudioanimdesc_t::pAnim( int *piFrame, float &flStall ) const
+{
+ mstudioanim_t *panim = NULL;
+
+ int block = animblock;
+ int index = animindex;
+ int section = 0;
+
+ if (sectionframes != 0)
+ {
+ if (numframes > sectionframes && *piFrame == numframes - 1)
+ {
+ // last frame on long anims is stored separately
+ *piFrame = 0;
+ section = (numframes / sectionframes) + 1;
+ }
+ else
+ {
+ section = *piFrame / sectionframes;
+ *piFrame -= section * sectionframes;
+ }
+
+ block = pSection( section )->animblock;
+ index = pSection( section )->animindex;
+ }
+
+ if (block == -1)
+ {
+ // model needs to be recompiled
+ return NULL;
+ }
+
+ panim = pAnimBlock( block, index );
+
+ // force a preload on the next block
+ if ( sectionframes != 0 )
+ {
+ int count = ( numframes / sectionframes) + 2;
+ for ( int i = section + 1; i < count; i++ )
+ {
+ if ( pSection( i )->animblock != block )
+ {
+ pAnimBlock( pSection( i )->animblock, pSection( i )->animindex );
+ break;
+ }
+ }
+ }
+
+ if (panim == NULL)
+ {
+ if (section > 0 && mod_load_showstall.GetInt() > 0)
+ {
+ Msg("[%8.3f] hitch on %s:%s:%d:%d\n", Plat_FloatTime(), pStudiohdr()->pszName(), pszName(), section, block );
+ }
+ // back up until a previously loaded block is found
+ while (--section >= 0)
+ {
+ block = pSection( section )->animblock;
+ index = pSection( section )->animindex;
+ panim = pAnimBlock( block, index );
+ if (panim)
+ {
+ // set it to the last frame in the last valid section
+ *piFrame = sectionframes - 1;
+ break;
+ }
+ }
+ }
+
+ // try to guess a valid stall time interval (tuned for the X360)
+ flStall = 0.0f;
+ if (panim == NULL && section <= 0)
+ {
+ zeroframestalltime = Plat_FloatTime();
+ flStall = 1.0f;
+ }
+ else if (panim != NULL && zeroframestalltime != 0.0f)
+ {
+ float dt = Plat_FloatTime() - zeroframestalltime;
+ if (dt >= 0.0)
+ {
+ flStall = SimpleSpline( clamp( (0.200f - dt) * 5.0f, 0.0f, 1.0f ) );
+ }
+
+ if (flStall == 0.0f)
+ {
+ // disable stalltime
+ zeroframestalltime = 0.0f;
+ }
+ else if (mod_load_showstall.GetInt() > 1)
+ {
+ Msg("[%8.3f] stall blend %.2f on %s:%s:%d:%d\n", Plat_FloatTime(), flStall, pStudiohdr()->pszName(), pszName(), section, block );
+ }
+ }
+
+ if (panim == NULL && mod_load_showstall.GetInt() > 1)
+ {
+ Msg("[%8.3f] stall on %s:%s:%d:%d\n", Plat_FloatTime(), pStudiohdr()->pszName(), pszName(), section, block );
+ }
+
+ return panim;
+}
+
+mstudioikrule_t *mstudioanimdesc_t::pIKRule( int i ) const
+{
+ if (ikruleindex)
+ {
+ return (mstudioikrule_t *)(((byte *)this) + ikruleindex) + i;
+ }
+ else if (animblockikruleindex)
+ {
+ if (animblock == 0)
+ {
+ return (mstudioikrule_t *)(((byte *)this) + animblockikruleindex) + i;
+ }
+ else
+ {
+ byte *pAnimBlocks = pStudiohdr()->GetAnimBlock( animblock );
+
+ if ( pAnimBlocks )
+ {
+ return (mstudioikrule_t *)(pAnimBlocks + animblockikruleindex) + i;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+mstudiolocalhierarchy_t *mstudioanimdesc_t::pHierarchy( int i ) const
+{
+ if (localhierarchyindex)
+ {
+ if (animblock == 0)
+ {
+ return (mstudiolocalhierarchy_t *)(((byte *)this) + localhierarchyindex) + i;
+ }
+ else
+ {
+ byte *pAnimBlocks = pStudiohdr()->GetAnimBlock( animblock );
+
+ if ( pAnimBlocks )
+ {
+ return (mstudiolocalhierarchy_t *)(pAnimBlocks + localhierarchyindex) + i;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+bool studiohdr_t::SequencesAvailable() const
+{
+ if (numincludemodels == 0)
+ {
+ return true;
+ }
+
+ return ( GetVirtualModel() != NULL );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::GetNumSeq( void ) const
+{
+ if (numincludemodels == 0)
+ {
+ return numlocalseq;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+ return pVModel->m_seq.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+mstudioseqdesc_t &studiohdr_t::pSeqdesc( int i ) const
+{
+ if (numincludemodels == 0)
+ {
+ return *pLocalSeqdesc( i );
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ if ( !pVModel )
+ {
+ return *pLocalSeqdesc( i );
+ }
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[i].group ];
+ const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
+ Assert( pStudioHdr );
+
+ return *pStudioHdr->pLocalSeqdesc( pVModel->m_seq[i].index );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::iRelativeAnim( int baseseq, int relanim ) const
+{
+ if (numincludemodels == 0)
+ {
+ return relanim;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[baseseq].group ];
+
+ return pGroup->masterAnim[ relanim ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::iRelativeSeq( int baseseq, int relseq ) const
+{
+ if (numincludemodels == 0)
+ {
+ return relseq;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[baseseq].group ];
+
+ return pGroup->masterSeq[ relseq ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::GetNumPoseParameters( void ) const
+{
+ if (numincludemodels == 0)
+ {
+ return numlocalposeparameters;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ return pVModel->m_pose.Count();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+const mstudioposeparamdesc_t &studiohdr_t::pPoseParameter( int i )
+{
+ if (numincludemodels == 0)
+ {
+ return *pLocalPoseParameter( i );
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ if ( pVModel->m_pose[i].group == 0)
+ return *pLocalPoseParameter( pVModel->m_pose[i].index );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_pose[i].group ];
+
+ const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
+ Assert( pStudioHdr );
+
+ return *pStudioHdr->pLocalPoseParameter( pVModel->m_pose[i].index );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::GetSharedPoseParameter( int iSequence, int iLocalPose ) const
+{
+ if (numincludemodels == 0)
+ {
+ return iLocalPose;
+ }
+
+ if (iLocalPose == -1)
+ return iLocalPose;
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ];
+
+ return pGroup->masterPose[iLocalPose];
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::EntryNode( int iSequence )
+{
+ mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
+
+ if (numincludemodels == 0 || seqdesc.localentrynode == 0)
+ {
+ return seqdesc.localentrynode;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ];
+
+ return pGroup->masterNode[seqdesc.localentrynode-1]+1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+
+int studiohdr_t::ExitNode( int iSequence )
+{
+ mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
+
+ if (numincludemodels == 0 || seqdesc.localexitnode == 0)
+ {
+ return seqdesc.localexitnode;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_seq[iSequence].group ];
+
+ return pGroup->masterNode[seqdesc.localexitnode-1]+1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::GetNumAttachments( void ) const
+{
+ if (numincludemodels == 0)
+ {
+ return numlocalattachments;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ return pVModel->m_attachment.Count();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+const mstudioattachment_t &studiohdr_t::pAttachment( int i ) const
+{
+ if (numincludemodels == 0)
+ {
+ return *pLocalAttachment( i );
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[i].group ];
+ const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
+ Assert( pStudioHdr );
+
+ return *pStudioHdr->pLocalAttachment( pVModel->m_attachment[i].index );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::GetAttachmentBone( int i )
+{
+ const mstudioattachment_t &attachment = pAttachment( i );
+
+ // remap bone
+ virtualmodel_t *pVModel = GetVirtualModel();
+ if (pVModel)
+ {
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[i].group ];
+ int iBone = pGroup->masterBone[attachment.localbone];
+ if (iBone == -1)
+ return 0;
+ return iBone;
+ }
+ return attachment.localbone;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+void studiohdr_t::SetAttachmentBone( int iAttachment, int iBone )
+{
+ mstudioattachment_t &attachment = (mstudioattachment_t &)pAttachment( iAttachment );
+
+ // remap bone
+ virtualmodel_t *pVModel = GetVirtualModel();
+ if (pVModel)
+ {
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_attachment[iAttachment].group ];
+ iBone = pGroup->boneMap[iBone];
+ }
+ attachment.localbone = iBone;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+char *studiohdr_t::pszNodeName( int iNode )
+{
+ if (numincludemodels == 0)
+ {
+ return pszLocalNodeName( iNode );
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ if ( pVModel->m_node.Count() <= iNode-1 )
+ return "Invalid node";
+
+ return pVModel->m_group[ pVModel->m_node[iNode-1].group ].GetStudioHdr()->pszLocalNodeName( pVModel->m_node[iNode-1].index );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::GetTransition( int iFrom, int iTo ) const
+{
+ if (numincludemodels == 0)
+ {
+ return *pLocalTransition( (iFrom-1)*numlocalnodes + (iTo - 1) );
+ }
+
+ return iTo;
+ /*
+ FIXME: not connected
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ return pVModel->m_transition.Element( iFrom ).Element( iTo );
+ */
+}
+
+
+int studiohdr_t::GetActivityListVersion( void )
+{
+ if (numincludemodels == 0)
+ {
+ return activitylistversion;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ int version = activitylistversion;
+
+ int i;
+ for (i = 1; i < pVModel->m_group.Count(); i++)
+ {
+ virtualgroup_t *pGroup = &pVModel->m_group[ i ];
+ const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
+
+ Assert( pStudioHdr );
+
+ version = min( version, pStudioHdr->activitylistversion );
+ }
+
+ return version;
+}
+
+void studiohdr_t::SetActivityListVersion( int version ) const
+{
+ activitylistversion = version;
+
+ if (numincludemodels == 0)
+ {
+ return;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ int i;
+ for (i = 1; i < pVModel->m_group.Count(); i++)
+ {
+ virtualgroup_t *pGroup = &pVModel->m_group[ i ];
+ const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
+
+ Assert( pStudioHdr );
+
+ pStudioHdr->SetActivityListVersion( version );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+
+int studiohdr_t::GetNumIKAutoplayLocks( void ) const
+{
+ if (numincludemodels == 0)
+ {
+ return numlocalikautoplaylocks;
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ return pVModel->m_iklock.Count();
+}
+
+const mstudioiklock_t &studiohdr_t::pIKAutoplayLock( int i )
+{
+ if (numincludemodels == 0)
+ {
+ return *pLocalIKAutoplayLock( i );
+ }
+
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ virtualgroup_t *pGroup = &pVModel->m_group[ pVModel->m_iklock[i].group ];
+ const studiohdr_t *pStudioHdr = pGroup->GetStudioHdr();
+ Assert( pStudioHdr );
+
+ return *pStudioHdr->pLocalIKAutoplayLock( pVModel->m_iklock[i].index );
+}
+
+int studiohdr_t::CountAutoplaySequences() const
+{
+ int count = 0;
+ for (int i = 0; i < GetNumSeq(); i++)
+ {
+ mstudioseqdesc_t &seqdesc = pSeqdesc( i );
+ if (seqdesc.flags & STUDIO_AUTOPLAY)
+ {
+ count++;
+ }
+ }
+ return count;
+}
+
+int studiohdr_t::CopyAutoplaySequences( unsigned short *pOut, int outCount ) const
+{
+ int outIndex = 0;
+ for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++)
+ {
+ mstudioseqdesc_t &seqdesc = pSeqdesc( i );
+ if (seqdesc.flags & STUDIO_AUTOPLAY)
+ {
+ pOut[outIndex] = i;
+ outIndex++;
+ }
+ }
+ return outIndex;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: maps local sequence bone to global bone
+//-----------------------------------------------------------------------------
+
+int studiohdr_t::RemapSeqBone( int iSequence, int iLocalBone ) const
+{
+ // remap bone
+ virtualmodel_t *pVModel = GetVirtualModel();
+ if (pVModel)
+ {
+ const virtualgroup_t *pSeqGroup = pVModel->pSeqGroup( iSequence );
+ return pSeqGroup->masterBone[iLocalBone];
+ }
+ return iLocalBone;
+}
+
+int studiohdr_t::RemapAnimBone( int iAnim, int iLocalBone ) const
+{
+ // remap bone
+ virtualmodel_t *pVModel = GetVirtualModel();
+ if (pVModel)
+ {
+ const virtualgroup_t *pAnimGroup = pVModel->pAnimGroup( iAnim );
+ return pAnimGroup->masterBone[iLocalBone];
+ }
+ return iLocalBone;
+}
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+CStudioHdr::CStudioHdr( void )
+{
+ // set pointer to bogus value
+ m_nFrameUnlockCounter = 0;
+ m_pFrameUnlockCounter = &m_nFrameUnlockCounter;
+ Init( NULL );
+}
+
+CStudioHdr::CStudioHdr( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache )
+{
+ // preset pointer to bogus value (it may be overwritten with legitimate data later)
+ m_nFrameUnlockCounter = 0;
+ m_pFrameUnlockCounter = &m_nFrameUnlockCounter;
+ Init( pStudioHdr, mdlcache );
+}
+
+
+// extern IDataCache *g_pDataCache;
+
+void CStudioHdr::Init( const studiohdr_t *pStudioHdr, IMDLCache *mdlcache )
+{
+ m_pStudioHdr = pStudioHdr;
+
+ m_pVModel = NULL;
+ m_pStudioHdrCache.RemoveAll();
+
+ if (m_pStudioHdr == NULL)
+ {
+ return;
+ }
+
+ if ( mdlcache )
+ {
+ m_pFrameUnlockCounter = mdlcache->GetFrameUnlockCounterPtr( MDLCACHE_STUDIOHDR );
+ m_nFrameUnlockCounter = *m_pFrameUnlockCounter - 1;
+ }
+
+ if (m_pStudioHdr->numincludemodels == 0)
+ {
+#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE
+#else
+ m_ActivityToSequence.Initialize(this);
+#endif
+ }
+ else
+ {
+ ResetVModel( m_pStudioHdr->GetVirtualModel() );
+#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE
+#else
+ m_ActivityToSequence.Initialize(this);
+#endif
+ }
+
+ m_boneFlags.EnsureCount( numbones() );
+ m_boneParent.EnsureCount( numbones() );
+ for (int i = 0; i < numbones(); i++)
+ {
+ m_boneFlags[i] = pBone( i )->flags;
+ m_boneParent[i] = pBone( i )->parent;
+ }
+}
+
+void CStudioHdr::Term()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+bool CStudioHdr::SequencesAvailable() const
+{
+ if (m_pStudioHdr->numincludemodels == 0)
+ {
+ return true;
+ }
+
+ if (m_pVModel == NULL)
+ {
+ // repoll m_pVModel
+ return (ResetVModel( m_pStudioHdr->GetVirtualModel() ) != NULL);
+ }
+ else
+ return true;
+}
+
+
+const virtualmodel_t * CStudioHdr::ResetVModel( const virtualmodel_t *pVModel ) const
+{
+ if (pVModel != NULL)
+ {
+ m_pVModel = (virtualmodel_t *)pVModel;
+ Assert( !pVModel->m_Lock.GetOwnerId() );
+ m_pStudioHdrCache.SetCount( m_pVModel->m_group.Count() );
+
+ int i;
+ for (i = 0; i < m_pStudioHdrCache.Count(); i++)
+ {
+ m_pStudioHdrCache[ i ] = NULL;
+ }
+
+ return const_cast<virtualmodel_t *>(pVModel);
+ }
+ else
+ {
+ m_pVModel = NULL;
+ return NULL;
+ }
+}
+
+const studiohdr_t *CStudioHdr::GroupStudioHdr( int i )
+{
+ if ( !this )
+ {
+ ExecuteNTimes( 5, Warning( "Call to NULL CStudioHdr::GroupStudioHdr()\n" ) );
+ }
+
+ if ( m_nFrameUnlockCounter != *m_pFrameUnlockCounter )
+ {
+ m_FrameUnlockCounterMutex.Lock();
+ if ( *m_pFrameUnlockCounter != m_nFrameUnlockCounter ) // i.e., this thread got the mutex
+ {
+ memset( m_pStudioHdrCache.Base(), 0, m_pStudioHdrCache.Count() * sizeof(studiohdr_t *) );
+ m_nFrameUnlockCounter = *m_pFrameUnlockCounter;
+ }
+ m_FrameUnlockCounterMutex.Unlock();
+ }
+
+ if ( !m_pStudioHdrCache.IsValidIndex( i ) )
+ {
+ const char *pszName = ( m_pStudioHdr ) ? m_pStudioHdr->pszName() : "<<null>>";
+ ExecuteNTimes( 5, Warning( "Invalid index passed to CStudioHdr(%s)::GroupStudioHdr(): %d, but max is %d\n", pszName, i, m_pStudioHdrCache.Count() ) );
+ DebuggerBreakIfDebugging();
+ return m_pStudioHdr; // return something known to probably exist, certainly things will be messed up, but hopefully not crash before the warning is noticed
+ }
+
+ const studiohdr_t *pStudioHdr = m_pStudioHdrCache[ i ];
+
+ if (pStudioHdr == NULL)
+ {
+ Assert( !m_pVModel->m_Lock.GetOwnerId() );
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ i ];
+ pStudioHdr = pGroup->GetStudioHdr();
+ m_pStudioHdrCache[ i ] = pStudioHdr;
+ }
+
+ Assert( pStudioHdr );
+ return pStudioHdr;
+}
+
+
+const studiohdr_t *CStudioHdr::pSeqStudioHdr( int sequence )
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr;
+ }
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_seq[sequence].group );
+
+ return pStudioHdr;
+}
+
+
+const studiohdr_t *CStudioHdr::pAnimStudioHdr( int animation )
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr;
+ }
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_anim[animation].group );
+
+ return pStudioHdr;
+}
+
+
+
+mstudioanimdesc_t &CStudioHdr::pAnimdesc( int i )
+{
+ if (m_pVModel == NULL)
+ {
+ return *m_pStudioHdr->pLocalAnimdesc( i );
+ }
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_anim[i].group );
+
+ return *pStudioHdr->pLocalAnimdesc( m_pVModel->m_anim[i].index );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetNumSeq( void ) const
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr->numlocalseq;
+ }
+
+ return m_pVModel->m_seq.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+mstudioseqdesc_t &CStudioHdr::pSeqdesc( int i )
+{
+ Assert( ( i >= 0 && i < GetNumSeq() ) || ( i == 1 && GetNumSeq() <= 1 ) );
+ if ( i < 0 || i >= GetNumSeq() )
+ {
+ // Avoid reading random memory.
+ i = 0;
+ }
+
+ if (m_pVModel == NULL)
+ {
+ return *m_pStudioHdr->pLocalSeqdesc( i );
+ }
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_seq[i].group );
+
+ return *pStudioHdr->pLocalSeqdesc( m_pVModel->m_seq[i].index );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::iRelativeAnim( int baseseq, int relanim ) const
+{
+ if (m_pVModel == NULL)
+ {
+ return relanim;
+ }
+
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[baseseq].group ];
+
+ return pGroup->masterAnim[ relanim ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::iRelativeSeq( int baseseq, int relseq ) const
+{
+ if (m_pVModel == NULL)
+ {
+ return relseq;
+ }
+
+ Assert( m_pVModel );
+
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[baseseq].group ];
+
+ return pGroup->masterSeq[ relseq ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetNumPoseParameters( void ) const
+{
+ if (m_pVModel == NULL)
+ {
+ if ( m_pStudioHdr )
+ return m_pStudioHdr->numlocalposeparameters;
+ else
+ return 0;
+ }
+
+ Assert( m_pVModel );
+
+ return m_pVModel->m_pose.Count();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+const mstudioposeparamdesc_t &CStudioHdr::pPoseParameter( int i )
+{
+ if (m_pVModel == NULL)
+ {
+ return *m_pStudioHdr->pLocalPoseParameter( i );
+ }
+
+ if ( m_pVModel->m_pose[i].group == 0)
+ return *m_pStudioHdr->pLocalPoseParameter( m_pVModel->m_pose[i].index );
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_pose[i].group );
+
+ return *pStudioHdr->pLocalPoseParameter( m_pVModel->m_pose[i].index );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetSharedPoseParameter( int iSequence, int iLocalPose ) const
+{
+ if (m_pVModel == NULL)
+ {
+ return iLocalPose;
+ }
+
+ if (iLocalPose == -1)
+ return iLocalPose;
+
+ Assert( m_pVModel );
+
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ];
+
+ return pGroup->masterPose[iLocalPose];
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::EntryNode( int iSequence )
+{
+ mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
+
+ if (m_pVModel == NULL || seqdesc.localentrynode == 0)
+ {
+ return seqdesc.localentrynode;
+ }
+
+ Assert( m_pVModel );
+
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ];
+
+ return pGroup->masterNode[seqdesc.localentrynode-1]+1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+
+int CStudioHdr::ExitNode( int iSequence )
+{
+ mstudioseqdesc_t &seqdesc = pSeqdesc( iSequence );
+
+ if (m_pVModel == NULL || seqdesc.localexitnode == 0)
+ {
+ return seqdesc.localexitnode;
+ }
+
+ Assert( m_pVModel );
+
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_seq[iSequence].group ];
+
+ return pGroup->masterNode[seqdesc.localexitnode-1]+1;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetNumAttachments( void ) const
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr->numlocalattachments;
+ }
+
+ Assert( m_pVModel );
+
+ return m_pVModel->m_attachment.Count();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+const mstudioattachment_t &CStudioHdr::pAttachment( int i )
+{
+ if (m_pVModel == NULL)
+ {
+ return *m_pStudioHdr->pLocalAttachment( i );
+ }
+
+ Assert( m_pVModel );
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_attachment[i].group );
+
+ return *pStudioHdr->pLocalAttachment( m_pVModel->m_attachment[i].index );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetAttachmentBone( int i )
+{
+ if (m_pVModel == 0)
+ {
+ return m_pStudioHdr->pLocalAttachment( i )->localbone;
+ }
+
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_attachment[i].group ];
+ const mstudioattachment_t &attachment = pAttachment( i );
+ int iBone = pGroup->masterBone[attachment.localbone];
+ if (iBone == -1)
+ return 0;
+ return iBone;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+void CStudioHdr::SetAttachmentBone( int iAttachment, int iBone )
+{
+ mstudioattachment_t &attachment = (mstudioattachment_t &)m_pStudioHdr->pAttachment( iAttachment );
+
+ // remap bone
+ if (m_pVModel)
+ {
+ virtualgroup_t *pGroup = &m_pVModel->m_group[ m_pVModel->m_attachment[iAttachment].group ];
+ iBone = pGroup->boneMap[iBone];
+ }
+ attachment.localbone = iBone;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+char *CStudioHdr::pszNodeName( int iNode )
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr->pszLocalNodeName( iNode );
+ }
+
+ if ( m_pVModel->m_node.Count() <= iNode-1 )
+ return "Invalid node";
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_node[iNode-1].group );
+
+ return pStudioHdr->pszLocalNodeName( m_pVModel->m_node[iNode-1].index );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetTransition( int iFrom, int iTo ) const
+{
+ if (m_pVModel == NULL)
+ {
+ return *m_pStudioHdr->pLocalTransition( (iFrom-1)*m_pStudioHdr->numlocalnodes + (iTo - 1) );
+ }
+
+ return iTo;
+ /*
+ FIXME: not connected
+ virtualmodel_t *pVModel = (virtualmodel_t *)GetVirtualModel();
+ Assert( pVModel );
+
+ return pVModel->m_transition.Element( iFrom ).Element( iTo );
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetActivityListVersion( void )
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr->activitylistversion;
+ }
+
+ int version = m_pStudioHdr->activitylistversion;
+
+ int i;
+ for (i = 1; i < m_pVModel->m_group.Count(); i++)
+ {
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
+ Assert( pStudioHdr );
+ version = min( version, pStudioHdr->activitylistversion );
+ }
+
+ return version;
+}
+
+void CStudioHdr::SetActivityListVersion( int version )
+{
+ m_pStudioHdr->activitylistversion = version;
+
+ if (m_pVModel == NULL)
+ {
+ return;
+ }
+
+ int i;
+ for (i = 1; i < m_pVModel->m_group.Count(); i++)
+ {
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
+ Assert( pStudioHdr );
+ pStudioHdr->SetActivityListVersion( version );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::GetEventListVersion( void )
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr->eventsindexed;
+ }
+
+ int version = m_pStudioHdr->eventsindexed;
+
+ int i;
+ for (i = 1; i < m_pVModel->m_group.Count(); i++)
+ {
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
+ Assert( pStudioHdr );
+ version = min( version, pStudioHdr->eventsindexed );
+ }
+
+ return version;
+}
+
+void CStudioHdr::SetEventListVersion( int version )
+{
+ m_pStudioHdr->eventsindexed = version;
+
+ if (m_pVModel == NULL)
+ {
+ return;
+ }
+
+ int i;
+ for (i = 1; i < m_pVModel->m_group.Count(); i++)
+ {
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( i );
+ Assert( pStudioHdr );
+ pStudioHdr->eventsindexed = version;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+
+int CStudioHdr::GetNumIKAutoplayLocks( void ) const
+{
+ if (m_pVModel == NULL)
+ {
+ return m_pStudioHdr->numlocalikautoplaylocks;
+ }
+
+ return m_pVModel->m_iklock.Count();
+}
+
+const mstudioiklock_t &CStudioHdr::pIKAutoplayLock( int i )
+{
+ if (m_pVModel == NULL)
+ {
+ return *m_pStudioHdr->pLocalIKAutoplayLock( i );
+ }
+
+ const studiohdr_t *pStudioHdr = GroupStudioHdr( m_pVModel->m_iklock[i].group );
+ Assert( pStudioHdr );
+ return *pStudioHdr->pLocalIKAutoplayLock( m_pVModel->m_iklock[i].index );
+}
+
+#if 0
+int CStudioHdr::CountAutoplaySequences() const
+{
+ int count = 0;
+ for (int i = 0; i < GetNumSeq(); i++)
+ {
+ mstudioseqdesc_t &seqdesc = pSeqdesc( i );
+ if (seqdesc.flags & STUDIO_AUTOPLAY)
+ {
+ count++;
+ }
+ }
+ return count;
+}
+
+int CStudioHdr::CopyAutoplaySequences( unsigned short *pOut, int outCount ) const
+{
+ int outIndex = 0;
+ for (int i = 0; i < GetNumSeq() && outIndex < outCount; i++)
+ {
+ mstudioseqdesc_t &seqdesc = pSeqdesc( i );
+ if (seqdesc.flags & STUDIO_AUTOPLAY)
+ {
+ pOut[outIndex] = i;
+ outIndex++;
+ }
+ }
+ return outIndex;
+}
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: maps local sequence bone to global bone
+//-----------------------------------------------------------------------------
+
+int CStudioHdr::RemapSeqBone( int iSequence, int iLocalBone ) const
+{
+ // remap bone
+ if (m_pVModel)
+ {
+ const virtualgroup_t *pSeqGroup = m_pVModel->pSeqGroup( iSequence );
+ return pSeqGroup->masterBone[iLocalBone];
+ }
+ return iLocalBone;
+}
+
+int CStudioHdr::RemapAnimBone( int iAnim, int iLocalBone ) const
+{
+ // remap bone
+ if (m_pVModel)
+ {
+ const virtualgroup_t *pAnimGroup = m_pVModel->pAnimGroup( iAnim );
+ return pAnimGroup->masterBone[iLocalBone];
+ }
+ return iLocalBone;
+}
+
+// JasonM hack
+//ConVar flex_maxrule( "flex_maxrule", "0" );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: run the interpreted FAC's expressions, converting flex_controller
+// values into FAC weights
+//-----------------------------------------------------------------------------
+void CStudioHdr::RunFlexRules( const float *src, float *dest )
+{
+ int i, j;
+
+ // FIXME: this shouldn't be needed, flex without rules should be stripped in studiomdl
+ for (i = 0; i < numflexdesc(); i++)
+ {
+ dest[i] = 0;
+ }
+
+ for (i = 0; i < numflexrules(); i++)
+ {
+ float stack[32] = {};
+ int k = 0;
+ mstudioflexrule_t *prule = pFlexRule( i );
+
+ mstudioflexop_t *pops = prule->iFlexOp( 0 );
+/*
+ // JasonM hack for flex perf testing...
+ int nFlexRulesToRun = 0; // 0 means run them all
+ const char *pszExpression = flex_maxrule.GetString();
+ if ( pszExpression )
+ {
+ nFlexRulesToRun = atoi(pszExpression); // 0 will be returned if not a numeric string
+ }
+ // end JasonM hack
+//*/
+ // debugoverlay->AddTextOverlay( GetAbsOrigin() + Vector( 0, 0, 64 ), i + 1, 0, "%2d:%d\n", i, prule->flex );
+
+ for (j = 0; j < prule->numops; j++)
+ {
+ switch (pops->op)
+ {
+ case STUDIO_ADD: stack[k-2] = stack[k-2] + stack[k-1]; k--; break;
+ case STUDIO_SUB: stack[k-2] = stack[k-2] - stack[k-1]; k--; break;
+ case STUDIO_MUL: stack[k-2] = stack[k-2] * stack[k-1]; k--; break;
+ case STUDIO_DIV:
+ if (stack[k-1] > 0.0001)
+ {
+ stack[k-2] = stack[k-2] / stack[k-1];
+ }
+ else
+ {
+ stack[k-2] = 0;
+ }
+ k--;
+ break;
+ case STUDIO_NEG: stack[k-1] = -stack[k-1]; break;
+ case STUDIO_MAX: stack[k-2] = max( stack[k-2], stack[k-1] ); k--; break;
+ case STUDIO_MIN: stack[k-2] = min( stack[k-2], stack[k-1] ); k--; break;
+ case STUDIO_CONST: stack[k] = pops->d.value; k++; break;
+ case STUDIO_FETCH1:
+ {
+ int m = pFlexcontroller( (LocalFlexController_t)pops->d.index)->localToGlobal;
+ stack[k] = src[m];
+ k++;
+ break;
+ }
+ case STUDIO_FETCH2:
+ {
+ stack[k] = dest[pops->d.index]; k++; break;
+ }
+ case STUDIO_COMBO:
+ {
+ int m = pops->d.index;
+ int km = k - m;
+ for ( int i = km + 1; i < k; ++i )
+ {
+ stack[ km ] *= stack[ i ];
+ }
+ k = k - m + 1;
+ }
+ break;
+ case STUDIO_DOMINATE:
+ {
+ int m = pops->d.index;
+ int km = k - m;
+ float dv = stack[ km ];
+ for ( int i = km + 1; i < k; ++i )
+ {
+ dv *= stack[ i ];
+ }
+ stack[ km - 1 ] *= 1.0f - dv;
+ k -= m;
+ }
+ break;
+ case STUDIO_2WAY_0:
+ {
+ int m = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal;
+ stack[ k ] = RemapValClamped( src[m], -1.0f, 0.0f, 1.0f, 0.0f );
+ k++;
+ }
+ break;
+ case STUDIO_2WAY_1:
+ {
+ int m = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal;
+ stack[ k ] = RemapValClamped( src[m], 0.0f, 1.0f, 0.0f, 1.0f );
+ k++;
+ }
+ break;
+ case STUDIO_NWAY:
+ {
+ LocalFlexController_t valueControllerIndex = static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] );
+ int m = pFlexcontroller( valueControllerIndex )->localToGlobal;
+ float flValue = src[ m ];
+ int v = pFlexcontroller( (LocalFlexController_t)pops->d.index )->localToGlobal;
+
+ const Vector4D filterRamp( stack[ k - 5 ], stack[ k - 4 ], stack[ k - 3 ], stack[ k - 2 ] );
+
+ // Apply multicontrol remapping
+ if ( flValue <= filterRamp.x || flValue >= filterRamp.w )
+ {
+ flValue = 0.0f;
+ }
+ else if ( flValue < filterRamp.y )
+ {
+ flValue = RemapValClamped( flValue, filterRamp.x, filterRamp.y, 0.0f, 1.0f );
+ }
+ else if ( flValue > filterRamp.z )
+ {
+ flValue = RemapValClamped( flValue, filterRamp.z, filterRamp.w, 1.0f, 0.0f );
+ }
+ else
+ {
+ flValue = 1.0f;
+ }
+
+ stack[ k - 5 ] = flValue * src[ v ];
+
+ k -= 4;
+ }
+ break;
+ case STUDIO_DME_LOWER_EYELID:
+ {
+ const mstudioflexcontroller_t *const pCloseLidV = pFlexcontroller( (LocalFlexController_t)pops->d.index );
+ const float flCloseLidV = RemapValClamped( src[ pCloseLidV->localToGlobal ], pCloseLidV->min, pCloseLidV->max, 0.0f, 1.0f );
+
+ const mstudioflexcontroller_t *const pCloseLid = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] ) );
+ const float flCloseLid = RemapValClamped( src[ pCloseLid->localToGlobal ], pCloseLid->min, pCloseLid->max, 0.0f, 1.0f );
+
+ int nBlinkIndex = static_cast< int >( stack[ k - 2 ] );
+ float flBlink = 0.0f;
+ if ( nBlinkIndex >= 0 )
+ {
+ const mstudioflexcontroller_t *const pBlink = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 2 ] ) );
+ flBlink = RemapValClamped( src[ pBlink->localToGlobal ], pBlink->min, pBlink->max, 0.0f, 1.0f );
+ }
+
+ int nEyeUpDownIndex = static_cast< int >( stack[ k - 3 ] );
+ float flEyeUpDown = 0.0f;
+ if ( nEyeUpDownIndex >= 0 )
+ {
+ const mstudioflexcontroller_t *const pEyeUpDown = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 3 ] ) );
+ flEyeUpDown = RemapValClamped( src[ pEyeUpDown->localToGlobal ], pEyeUpDown->min, pEyeUpDown->max, -1.0f, 1.0f );
+ }
+
+ if ( flEyeUpDown > 0.0 )
+ {
+ stack [ k - 3 ] = ( 1.0f - flEyeUpDown ) * ( 1.0f - flCloseLidV ) * flCloseLid;
+ }
+ else
+ {
+ stack [ k - 3 ] = ( 1.0f - flCloseLidV ) * flCloseLid;
+ }
+ k -= 2;
+ }
+ break;
+ case STUDIO_DME_UPPER_EYELID:
+ {
+ const mstudioflexcontroller_t *const pCloseLidV = pFlexcontroller( (LocalFlexController_t)pops->d.index );
+ const float flCloseLidV = RemapValClamped( src[ pCloseLidV->localToGlobal ], pCloseLidV->min, pCloseLidV->max, 0.0f, 1.0f );
+
+ const mstudioflexcontroller_t *const pCloseLid = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 1 ] ) );
+ const float flCloseLid = RemapValClamped( src[ pCloseLid->localToGlobal ], pCloseLid->min, pCloseLid->max, 0.0f, 1.0f );
+
+ int nBlinkIndex = static_cast< int >( stack[ k - 2 ] );
+ float flBlink = 0.0f;
+ if ( nBlinkIndex >= 0 )
+ {
+ const mstudioflexcontroller_t *const pBlink = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 2 ] ) );
+ flBlink = RemapValClamped( src[ pBlink->localToGlobal ], pBlink->min, pBlink->max, 0.0f, 1.0f );
+ }
+
+ int nEyeUpDownIndex = static_cast< int >( stack[ k - 3 ] );
+ float flEyeUpDown = 0.0f;
+ if ( nEyeUpDownIndex >= 0 )
+ {
+ const mstudioflexcontroller_t *const pEyeUpDown = pFlexcontroller( static_cast< LocalFlexController_t >( (int)stack[ k - 3 ] ) );
+ flEyeUpDown = RemapValClamped( src[ pEyeUpDown->localToGlobal ], pEyeUpDown->min, pEyeUpDown->max, -1.0f, 1.0f );
+ }
+
+ if ( flEyeUpDown < 0.0f )
+ {
+ stack [ k - 3 ] = ( 1.0f + flEyeUpDown ) * flCloseLidV * flCloseLid;
+ }
+ else
+ {
+ stack [ k - 3 ] = flCloseLidV * flCloseLid;
+ }
+ k -= 2;
+ }
+ break;
+ }
+
+ pops++;
+ }
+
+ dest[prule->flex] = stack[0];
+/*
+ // JasonM hack
+ if ( nFlexRulesToRun == 0) // 0 means run all rules correctly
+ {
+ dest[prule->flex] = stack[0];
+ }
+ else // run only up to nFlexRulesToRun correctly...zero out the rest
+ {
+ if ( j < nFlexRulesToRun )
+ dest[prule->flex] = stack[0];
+ else
+ dest[prule->flex] = 0.0f;
+ }
+
+ dest[prule->flex] = 1.0f;
+//*/
+ // end JasonM hack
+
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// CODE PERTAINING TO ACTIVITY->SEQUENCE MAPPING SUBCLASS
+//-----------------------------------------------------------------------------
+#define iabs(i) (( (i) >= 0 ) ? (i) : -(i) )
+
+
+extern void SetActivityForSequence( CStudioHdr *pstudiohdr, int i );
+void CStudioHdr::CActivityToSequenceMapping::Initialize( CStudioHdr * __restrict pstudiohdr )
+{
+ // Algorithm: walk through every sequence in the model, determine to which activity
+ // it corresponds, and keep a count of sequences per activity. Once the total count
+ // is available, allocate an array large enough to contain them all, update the
+ // starting indices for every activity's section in the array, and go back through,
+ // populating the array with its data.
+
+ AssertMsg1( m_pSequenceTuples == NULL, "Tried to double-initialize sequence mapping for %s", pstudiohdr->pszName() );
+ if ( m_pSequenceTuples != NULL )
+ return; // don't double initialize.
+
+ SetValidationPair(pstudiohdr);
+
+ if ( ! pstudiohdr->SequencesAvailable() )
+ return; // nothing to do.
+
+#if STUDIO_SEQUENCE_ACTIVITY_LAZY_INITIALIZE
+ m_bIsInitialized = true;
+#endif
+
+ // Some studio headers have no activities at all. In those
+ // cases we can avoid a lot of this effort.
+ bool bFoundOne = false;
+
+ // for each sequence in the header...
+ const int NumSeq = pstudiohdr->GetNumSeq();
+ for ( int i = 0 ; i < NumSeq ; ++i )
+ {
+ const mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
+#if defined(SERVER_DLL) || defined(CLIENT_DLL) || defined(GAME_DLL)
+ if (!(seqdesc.flags & STUDIO_ACTIVITY))
+ {
+ // AssertMsg2( false, "Sequence %d on studiohdr %s didn't have its activity initialized!", i, pstudiohdr->pszName() );
+ SetActivityForSequence( pstudiohdr, i );
+ }
+#endif
+
+ // is there an activity associated with this sequence?
+ if (seqdesc.activity >= 0)
+ {
+ bFoundOne = true;
+
+ // look up if we already have an entry. First we need to make a speculative one --
+ HashValueType entry(seqdesc.activity, 0, 1, iabs(seqdesc.actweight));
+ UtlHashHandle_t handle = m_ActToSeqHash.Find(entry);
+ if ( m_ActToSeqHash.IsValidHandle(handle) )
+ {
+ // we already have an entry and must update it by incrementing count
+ HashValueType * __restrict toUpdate = &m_ActToSeqHash.Element(handle);
+ toUpdate->count += 1;
+ toUpdate->totalWeight += iabs(seqdesc.actweight);
+ Assert( toUpdate->totalWeight > 0 );
+ }
+ else
+ {
+ // we do not have an entry yet; create one.
+ m_ActToSeqHash.Insert(entry);
+ }
+ }
+ }
+
+ // if we found nothing, don't bother with any other initialization!
+ if (!bFoundOne)
+ return;
+
+ // Now, create starting indices for each activity. For an activity n,
+ // the starting index is of course the sum of counts [0..n-1].
+ register int sequenceCount = 0;
+ int topActivity = 0; // this will store the highest seen activity number (used later to make an ad hoc map on the stack)
+ for ( UtlHashHandle_t handle = m_ActToSeqHash.GetFirstHandle() ;
+ m_ActToSeqHash.IsValidHandle(handle) ;
+ handle = m_ActToSeqHash.GetNextHandle(handle) )
+ {
+ HashValueType &element = m_ActToSeqHash[handle];
+ element.startingIdx = sequenceCount;
+ sequenceCount += element.count;
+ topActivity = max(topActivity, element.activityIdx);
+ }
+
+
+ // Allocate the actual array of sequence information. Note the use of restrict;
+ // this is an important optimization, but means that you must never refer to this
+ // array through m_pSequenceTuples in the scope of this function.
+ SequenceTuple * __restrict tupleList = new SequenceTuple[sequenceCount];
+ m_pSequenceTuples = tupleList; // save it off -- NEVER USE m_pSequenceTuples in this function!
+ m_iSequenceTuplesCount = sequenceCount;
+
+
+
+ // Now we're going to actually populate that list with the relevant data.
+ // First, create an array on the stack to store how many sequences we've written
+ // so far for each activity. (This is basically a very simple way of doing a map.)
+ // This stack may potentially grow very large; so if you have problems with it,
+ // go to a utlmap or similar structure.
+ unsigned int allocsize = (topActivity + 1) * sizeof(int);
+#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) ) // need macro for constant expression
+ allocsize = ALIGN_VALUE(allocsize,16);
+ int * __restrict seqsPerAct = static_cast<int *>(stackalloc(allocsize));
+ memset(seqsPerAct, 0, allocsize);
+
+ // okay, walk through all the sequences again, and write the relevant data into
+ // our little table.
+ for ( int i = 0 ; i < NumSeq ; ++i )
+ {
+ const mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
+ if (seqdesc.activity >= 0)
+ {
+ const HashValueType &element = m_ActToSeqHash[m_ActToSeqHash.Find(HashValueType(seqdesc.activity, 0, 0, 0))];
+
+ // If this assert trips, we've written more sequences per activity than we allocated
+ // (therefore there must have been a miscount in the first for loop above).
+ int tupleOffset = seqsPerAct[seqdesc.activity];
+ Assert( tupleOffset < element.count );
+
+ // You might be tempted to collapse this pointer math into a single pointer --
+ // don't! the tuple list is marked __restrict above.
+ (tupleList + element.startingIdx + tupleOffset)->seqnum = i; // store sequence number
+ (tupleList + element.startingIdx + tupleOffset)->weight = iabs(seqdesc.actweight);
+
+ // We can't have weights of 0
+ // Assert( (tupleList + element.startingIdx + tupleOffset)->weight > 0 );
+ if ( (tupleList + element.startingIdx + tupleOffset)->weight == 0 )
+ {
+ (tupleList + element.startingIdx + tupleOffset)->weight = 1;
+ }
+
+ seqsPerAct[seqdesc.activity] += 1;
+ }
+ }
+
+#ifdef DBGFLAG_ASSERT
+ // double check that we wrote exactly the right number of sequences.
+ unsigned int chkSequenceCount = 0;
+ for (int j = 0 ; j <= topActivity ; ++j)
+ {
+ chkSequenceCount += seqsPerAct[j];
+ }
+ Assert(chkSequenceCount == m_iSequenceTuplesCount);
+#endif
+
+}
+
+/// Force Initialize() to occur again, even if it has already occured.
+void CStudioHdr::CActivityToSequenceMapping::Reinitialize( CStudioHdr *pstudiohdr )
+{
+ m_bIsInitialized = false;
+ if (m_pSequenceTuples)
+ {
+ delete m_pSequenceTuples;
+ m_pSequenceTuples = NULL;
+ }
+ m_ActToSeqHash.RemoveAll();
+
+ Initialize(pstudiohdr);
+}
+
+// Look up relevant data for an activity's sequences. This isn't terribly efficient, due to the
+// load-hit-store on the output parameters, so the most common case -- SelectWeightedSequence --
+// is specially implemented.
+const CStudioHdr::CActivityToSequenceMapping::SequenceTuple *CStudioHdr::CActivityToSequenceMapping::GetSequences( int forActivity, int * __restrict outSequenceCount, int * __restrict outTotalWeight )
+{
+ // Construct a dummy entry so we can do a hash lookup (the UtlHash does not divorce keys from values)
+
+ HashValueType entry(forActivity, 0, 0, 0);
+ UtlHashHandle_t handle = m_ActToSeqHash.Find(entry);
+
+ if (m_ActToSeqHash.IsValidHandle(handle))
+ {
+ const HashValueType &element = m_ActToSeqHash[handle];
+ const SequenceTuple *retval = m_pSequenceTuples + element.startingIdx;
+ *outSequenceCount = element.count;
+ *outTotalWeight = element.totalWeight;
+
+ return retval;
+ }
+ else
+ {
+ // invalid handle; return NULL.
+ // this is actually a legit use case, so no need to assert.
+ return NULL;
+ }
+}
+
+int CStudioHdr::CActivityToSequenceMapping::NumSequencesForActivity( int forActivity )
+{
+ // If this trips, you've called this function on something that doesn't
+ // have activities.
+ //Assert(m_pSequenceTuples != NULL);
+ if ( m_pSequenceTuples == NULL )
+ return 0;
+
+ HashValueType entry(forActivity, 0, 0, 0);
+ UtlHashHandle_t handle = m_ActToSeqHash.Find(entry);
+ if (m_ActToSeqHash.IsValidHandle(handle))
+ {
+ return m_ActToSeqHash[handle].count;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// double-check that the data I point to hasn't changed
+bool CStudioHdr::CActivityToSequenceMapping::ValidateAgainst( const CStudioHdr * RESTRICT pstudiohdr ) RESTRICT
+{
+ if (m_bIsInitialized)
+ {
+ return m_expectedPStudioHdr == pstudiohdr->GetRenderHdr() &&
+ m_expectedVModel == pstudiohdr->GetVirtualModel();
+ }
+ else
+ {
+ return true; // Allow an ordinary initialization to take place without printing a panicky assert.
+ }
+}
+
+void CStudioHdr::CActivityToSequenceMapping::SetValidationPair( const CStudioHdr *RESTRICT pstudiohdr ) RESTRICT
+{
+ m_expectedPStudioHdr = pstudiohdr->GetRenderHdr();
+ m_expectedVModel = pstudiohdr->GetVirtualModel();
} \ No newline at end of file