This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions

347
tier3/choreoutils.cpp Normal file
View File

@ -0,0 +1,347 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Helper methods + classes for file access
//
//===========================================================================//
#include "tier3/choreoutils.h"
#include "tier3/tier3.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include "studio.h"
#include "../game/shared/choreoscene.h"
#include "../game/shared/choreoevent.h"
#include "tier1/KeyValues.h"
#include "bone_setup.h"
#include "soundchars.h"
//-----------------------------------------------------------------------------
// Find sequence by name
//-----------------------------------------------------------------------------
static int LookupSequence( CStudioHdr *pStudioHdr, const char *pSequenceName )
{
for ( int i = 0; i < pStudioHdr->GetNumSeq(); i++ )
{
if ( !Q_stricmp( pSequenceName, pStudioHdr->pSeqdesc( i ).pszLabel() ) )
return i;
}
return -1;
}
//-----------------------------------------------------------------------------
// Returns sequence flags
//-----------------------------------------------------------------------------
static int GetSequenceFlags( CStudioHdr *pStudioHdr, int nSequence )
{
if ( !pStudioHdr || nSequence < 0 || nSequence >= pStudioHdr->GetNumSeq() )
return 0;
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSequence );
return seqdesc.flags;
}
//-----------------------------------------------------------------------------
// Does a sequence loop?
//-----------------------------------------------------------------------------
static bool DoesSequenceLoop( CStudioHdr *pStudioHdr, int nSequence )
{
int nFlags = GetSequenceFlags( pStudioHdr, nSequence );
bool bLooping = ( nFlags & STUDIO_LOOPING ) ? true : false;
return bLooping;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool AutoAddGestureKeys( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly )
{
int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
if ( iSequence < 0 )
return false;
KeyValues *pSeqKeyValues = new KeyValues( "" );
if ( !pSeqKeyValues->LoadFromBuffer( pStudioHdr->pszName(), Studio_GetKeyValueText( pStudioHdr, iSequence ) ) )
{
pSeqKeyValues->deleteThis();
return false;
}
// Do we have a build point section?
KeyValues *pKVAllFaceposer = pSeqKeyValues->FindKey("faceposer");
if ( !pKVAllFaceposer )
{
pSeqKeyValues->deleteThis();
return false;
}
int nMaxFrame = Studio_MaxFrame( pStudioHdr, iSequence, pPoseParameters ) - 1;
// Start grabbing the sounds and slotting them in
KeyValues *pkvFaceposer;
char szStartLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "loop" };
char szEndLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "end" };
char szEntry[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "apex" };
char szExit[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "end" };
for ( pkvFaceposer = pKVAllFaceposer->GetFirstSubKey(); pkvFaceposer; pkvFaceposer = pkvFaceposer->GetNextKey() )
{
if ( !Q_stricmp( pkvFaceposer->GetName(), "startloop" ) )
{
Q_strncpy( szStartLoop, pkvFaceposer->GetString(), sizeof(szStartLoop) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "endloop" ) )
{
Q_strncpy( szEndLoop, pkvFaceposer->GetString(), sizeof(szEndLoop) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "entrytag" ) )
{
Q_strncpy( szEntry, pkvFaceposer->GetString(), sizeof(szEntry) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "exittag" ) )
{
Q_strncpy( szExit, pkvFaceposer->GetString(), sizeof(szExit) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "tags" ) )
{
if ( nMaxFrame <= 0 )
continue;
KeyValues *pkvTags;
for ( pkvTags = pkvFaceposer->GetFirstSubKey(); pkvTags; pkvTags = pkvTags->GetNextKey() )
{
float flPercentage = (float)pkvTags->GetInt() / nMaxFrame;
CEventAbsoluteTag *ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName() );
if (ptag)
{
// reposition tag
ptag->SetPercentage( flPercentage );
}
else
{
e->AddAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName(), flPercentage );
e->AddAbsoluteTag( CChoreoEvent::PLAYBACK, pkvTags->GetName(), flPercentage );
}
// lock the original tags so they can't be edited
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName() );
Assert( ptag );
ptag->SetLocked( true );
}
e->VerifyTagOrder();
e->PreventTagOverlap();
continue;
}
}
// FIXME: lookup linear tags in sequence data
{
CEventAbsoluteTag *ptag;
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szStartLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szStartLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szEndLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szEndLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szEntry );
if (ptag)
{
ptag->SetEntry( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szEntry );
if (ptag)
{
ptag->SetEntry( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szExit );
if (ptag)
{
ptag->SetExit( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szExit );
if (ptag)
{
ptag->SetExit( true );
}
}
pSeqKeyValues->deleteThis();
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool UpdateGestureLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly )
{
Assert( e );
if ( !e )
return false;
if ( e->GetType() != CChoreoEvent::GESTURE )
return false;
int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
if ( iSequence < 0 )
return false;
bool bChanged = false;
float flSeqDuration = Studio_Duration( pStudioHdr, iSequence, pPoseParameters );
float flCurDuration;
e->GetGestureSequenceDuration( flCurDuration );
if ( flSeqDuration != 0.0f && flSeqDuration != flCurDuration )
{
bChanged = true;
if ( !bCheckOnly )
{
e->SetGestureSequenceDuration( flSeqDuration );
}
}
return bChanged;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool UpdateSequenceLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly, bool bVerbose )
{
Assert( e );
if ( !e )
return false;
if ( e->GetType() != CChoreoEvent::SEQUENCE )
{
if ( bVerbose )
{
ConMsg( "UpdateSequenceLength: called on non-SEQUENCE event %s\n", e->GetName() );
}
return false;
}
int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
if ( iSequence < 0 )
return false;
bool bChanged = false;
bool bLooping = DoesSequenceLoop( pStudioHdr, iSequence );
float flSeqDuration = Studio_Duration( pStudioHdr, iSequence, pPoseParameters );
if ( bLooping )
{
if ( e->IsFixedLength() )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "UpdateSequenceLength: %s is looping, removing fixed length flag\n", e->GetName() );
}
bChanged = true;
}
e->SetFixedLength( false );
if ( !e->HasEndTime() )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s is looping, setting default end time\n", e->GetName() );
}
e->SetEndTime( e->GetStartTime() + flSeqDuration );
bChanged = true;
}
return bChanged;
}
if ( !e->IsFixedLength() )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s is fixed length, removing looping flag\n", e->GetName() );
}
bChanged = true;
}
e->SetFixedLength( true );
if ( e->HasEndTime() )
{
float dt = e->GetDuration();
if ( fabs( dt - flSeqDuration ) > 0.01f )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s has wrong duration, changing length from %f to %f seconds\n",
e->GetName(), dt, flSeqDuration );
}
bChanged = true;
}
}
else
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s has wrong duration, changing length to %f seconds\n",
e->GetName(), flSeqDuration );
}
bChanged = true;
}
if ( !bCheckOnly )
{
e->SetEndTime( e->GetStartTime() + flSeqDuration );
}
return bChanged;
}
//-----------------------------------------------------------------------------
// Finds sound files associated with events
//-----------------------------------------------------------------------------
const char *GetSoundForEvent( CChoreoEvent *pEvent, CStudioHdr *pStudioHdr )
{
const char *pSoundName = pEvent->GetParameters();
if ( Q_stristr( pSoundName, ".wav" ) )
return PSkipSoundChars( pSoundName );
const char *pFileName = g_pSoundEmitterSystem->GetWavFileForSound( pSoundName, ( pStudioHdr && pStudioHdr->IsValid() ) ? pStudioHdr->pszName() : NULL );
return PSkipSoundChars( pFileName );
}

459
tier3/mdlutils.cpp Normal file
View File

@ -0,0 +1,459 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Utility methods for mdl files
//
//===========================================================================//
#include "tier3/mdlutils.h"
#include "tier0/dbg.h"
#include "tier1/callqueue.h"
#include "tier3/tier3.h"
#include "studio.h"
#include "istudiorender.h"
#include "bone_setup.h"
//-----------------------------------------------------------------------------
// Returns the bounding box for the model
//-----------------------------------------------------------------------------
void GetMDLBoundingBox( Vector *pMins, Vector *pMaxs, MDLHandle_t h, int nSequence )
{
if ( h == MDLHANDLE_INVALID || !g_pMDLCache )
{
pMins->Init();
pMaxs->Init();
return;
}
pMins->Init( FLT_MAX, FLT_MAX );
pMaxs->Init( -FLT_MAX, -FLT_MAX );
studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( h );
if ( !VectorCompare( vec3_origin, pStudioHdr->view_bbmin ) || !VectorCompare( vec3_origin, pStudioHdr->view_bbmax ))
{
// look for view clip
*pMins = pStudioHdr->view_bbmin;
*pMaxs = pStudioHdr->view_bbmax;
}
else if ( !VectorCompare( vec3_origin, pStudioHdr->hull_min ) || !VectorCompare( vec3_origin, pStudioHdr->hull_max ))
{
// look for hull
*pMins = pStudioHdr->hull_min;
*pMaxs = pStudioHdr->hull_max;
}
// Else use the sequence box
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSequence );
VectorMin( seqdesc.bbmin, *pMins, *pMins );
VectorMax( seqdesc.bbmax, *pMaxs, *pMaxs );
}
//-----------------------------------------------------------------------------
// Returns the radius of the model as measured from the origin
//-----------------------------------------------------------------------------
float GetMDLRadius( MDLHandle_t h, int nSequence )
{
Vector vecMins, vecMaxs;
GetMDLBoundingBox( &vecMins, &vecMaxs, h, nSequence );
float flRadius = vecMaxs.Length();
float flRadius2 = vecMins.Length();
if ( flRadius2 > flRadius )
{
flRadius = flRadius2;
}
return flRadius;
}
//-----------------------------------------------------------------------------
// Returns a more accurate bounding sphere
//-----------------------------------------------------------------------------
void GetMDLBoundingSphere( Vector *pVecCenter, float *pRadius, MDLHandle_t h, int nSequence )
{
Vector vecMins, vecMaxs;
GetMDLBoundingBox( &vecMins, &vecMaxs, h, nSequence );
VectorAdd( vecMins, vecMaxs, *pVecCenter );
*pVecCenter *= 0.5f;
*pRadius = vecMaxs.DistTo( *pVecCenter );
}
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CMDL::CMDL()
{
m_MDLHandle = MDLHANDLE_INVALID;
m_Color.SetColor( 255, 255, 255, 255 );
m_nSkin = 0;
m_nBody = 0;
m_nSequence = 0;
m_nLOD = 0;
m_flPlaybackRate = 30.0f;
m_flTime = 0.0f;
m_vecViewTarget.Init( 0, 0, 0 );
m_bWorldSpaceViewTarget = false;
memset( m_pFlexControls, 0, sizeof(m_pFlexControls) );
m_pProxyData = NULL;
}
CMDL::~CMDL()
{
UnreferenceMDL();
}
void CMDL::SetMDL( MDLHandle_t h )
{
UnreferenceMDL();
m_MDLHandle = h;
if ( m_MDLHandle != MDLHANDLE_INVALID )
{
g_pMDLCache->AddRef( m_MDLHandle );
studiohdr_t *pHdr = g_pMDLCache->LockStudioHdr( m_MDLHandle );
if ( pHdr )
{
for ( LocalFlexController_t i = LocalFlexController_t(0); i < pHdr->numflexcontrollers; ++i )
{
if ( pHdr->pFlexcontroller( i )->localToGlobal == -1 )
{
pHdr->pFlexcontroller( i )->localToGlobal = i;
}
}
}
}
}
MDLHandle_t CMDL::GetMDL() const
{
return m_MDLHandle;
}
//-----------------------------------------------------------------------------
// Release the MDL handle
//-----------------------------------------------------------------------------
void CMDL::UnreferenceMDL()
{
if ( !g_pMDLCache )
return;
if ( m_MDLHandle != MDLHANDLE_INVALID )
{
// XXX need to figure out where it is safe to flush the queue during map change to not crash
#if 0
if ( ICallQueue *pCallQueue = materials->GetRenderContext()->GetCallQueue() )
{
// Parallel rendering: don't unlock model data until end of rendering
pCallQueue->QueueCall( g_pMDLCache, &IMDLCache::UnlockStudioHdr, m_MDLHandle );
pCallQueue->QueueCall( g_pMDLCache, &IMDLCache::Release, m_MDLHandle );
}
else
#endif
{
// Immediate-mode rendering, can unlock immediately
g_pMDLCache->UnlockStudioHdr( m_MDLHandle );
g_pMDLCache->Release( m_MDLHandle );
}
m_MDLHandle = MDLHANDLE_INVALID;
}
}
//-----------------------------------------------------------------------------
// Gets the studiohdr
//-----------------------------------------------------------------------------
studiohdr_t *CMDL::GetStudioHdr()
{
if ( !g_pMDLCache )
return NULL;
return g_pMDLCache->GetStudioHdr( m_MDLHandle );
}
//-----------------------------------------------------------------------------
// Draws the mesh
//-----------------------------------------------------------------------------
void CMDL::Draw( const matrix3x4_t& rootToWorld, const matrix3x4_t *pBoneToWorld )
{
if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
return;
if ( m_MDLHandle == MDLHANDLE_INVALID )
return;
// Color + alpha modulation
Vector white( m_Color.r() / 255.0f, m_Color.g() / 255.0f, m_Color.b() / 255.0f );
g_pStudioRender->SetColorModulation( white.Base() );
g_pStudioRender->SetAlphaModulation( m_Color.a() / 255.0f );
DrawModelInfo_t info;
info.m_pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
info.m_pHardwareData = g_pMDLCache->GetHardwareData( m_MDLHandle );
info.m_Decals = STUDIORENDER_DECAL_INVALID;
info.m_Skin = m_nSkin;
info.m_Body = m_nBody;
info.m_HitboxSet = 0;
info.m_pClientEntity = m_pProxyData;
info.m_pColorMeshes = NULL;
info.m_bStaticLighting = false;
info.m_Lod = m_nLOD;
Vector vecWorldViewTarget;
if ( m_bWorldSpaceViewTarget )
{
vecWorldViewTarget = m_vecViewTarget;
}
else
{
VectorTransform( m_vecViewTarget, rootToWorld, vecWorldViewTarget );
}
g_pStudioRender->SetEyeViewTarget( info.m_pStudioHdr, info.m_Body, vecWorldViewTarget );
// FIXME: Why is this necessary!?!?!?
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
// Set default flex values
float *pFlexWeights = NULL;
const int nFlexDescCount = info.m_pStudioHdr->numflexdesc;
if ( nFlexDescCount )
{
CStudioHdr cStudioHdr( info.m_pStudioHdr, g_pMDLCache );
g_pStudioRender->LockFlexWeights( info.m_pStudioHdr->numflexdesc, &pFlexWeights );
cStudioHdr.RunFlexRules( m_pFlexControls, pFlexWeights );
g_pStudioRender->UnlockFlexWeights();
}
Vector vecModelOrigin;
MatrixGetColumn( rootToWorld, 3, vecModelOrigin );
g_pStudioRender->DrawModel( NULL, info, const_cast<matrix3x4_t*>( pBoneToWorld ),
pFlexWeights, NULL, vecModelOrigin, STUDIORENDER_DRAW_ENTIRE_MODEL );
}
void CMDL::Draw( const matrix3x4_t &rootToWorld )
{
if ( !g_pMaterialSystem || !g_pMDLCache || !g_pStudioRender )
return;
if ( m_MDLHandle == MDLHANDLE_INVALID )
return;
studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( m_MDLHandle );
matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( pStudioHdr->numbones );
SetUpBones( rootToWorld, pStudioHdr->numbones, pBoneToWorld );
g_pStudioRender->UnlockBoneMatrices();
Draw( rootToWorld, pBoneToWorld );
}
void CMDL::SetUpBones( const matrix3x4_t& rootToWorld, int nMaxBoneCount, matrix3x4_t *pBoneToWorld, const float *pPoseParameters, MDLSquenceLayer_t *pSequenceLayers, int nNumSequenceLayers )
{
CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_MDLHandle ), g_pMDLCache );
float pPoseParameter[MAXSTUDIOPOSEPARAM];
if ( pPoseParameters )
{
V_memcpy( pPoseParameter, pPoseParameters, sizeof(pPoseParameter) );
}
else
{
// Default to middle of the pose parameter range
int nPoseCount = studioHdr.GetNumPoseParameters();
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i )
{
pPoseParameter[i] = 0.5f;
if ( i < nPoseCount )
{
const mstudioposeparamdesc_t &Pose = studioHdr.pPoseParameter( i );
// Want to try for a zero state. If one doesn't exist set it to .5 by default.
if ( Pose.start < 0.0f && Pose.end > 0.0f )
{
float flPoseDelta = Pose.end - Pose.start;
pPoseParameter[i] = -Pose.start / flPoseDelta;
}
}
}
}
int nFrameCount = Studio_MaxFrame( &studioHdr, m_nSequence, pPoseParameter );
if ( nFrameCount == 0 )
{
nFrameCount = 1;
}
float flCycle = ( m_flTime * m_flPlaybackRate ) / nFrameCount;
// FIXME: We're always wrapping; may want to determing if we should clamp
flCycle -= (int)(flCycle);
Vector pos[MAXSTUDIOBONES];
Quaternion q[MAXSTUDIOBONES];
IBoneSetup boneSetup( &studioHdr, BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ), pPoseParameter, NULL );
boneSetup.InitPose( pos, q );
boneSetup.AccumulatePose( pos, q, m_nSequence, flCycle, 1.0f, m_flTime, NULL );
// Accumulate the additional layers if specified.
if ( pSequenceLayers )
{
int nNumSeq = studioHdr.GetNumSeq();
for ( int i = 0; i < nNumSequenceLayers; ++i )
{
int nSeqIndex = pSequenceLayers[ i ].m_nSequenceIndex;
if ( ( nSeqIndex >= 0 ) && ( nSeqIndex < nNumSeq ) )
{
float flWeight = pSequenceLayers[ i ].m_flWeight;
float flLayerCycle;
int nLayerFrameCount = MAX( 1, Studio_MaxFrame( &studioHdr, nSeqIndex, pPoseParameter ) );
if ( pSequenceLayers[i].m_bNoLoop )
{
if ( pSequenceLayers[i].m_flCycleBeganAt == 0 )
{
pSequenceLayers[i].m_flCycleBeganAt = m_flTime;
}
float flElapsedTime = m_flTime - pSequenceLayers[i].m_flCycleBeganAt;
flLayerCycle = ( flElapsedTime * m_flPlaybackRate ) / nLayerFrameCount;
// Should we keep playing layers that have ended?
//if ( flLayerCycle >= 1.0 )
//continue;
}
else
{
flLayerCycle = ( m_flTime * m_flPlaybackRate ) / nLayerFrameCount;
// FIXME: We're always wrapping; may want to determing if we should clamp
flLayerCycle -= (int)(flLayerCycle);
}
boneSetup.AccumulatePose( pos, q, nSeqIndex, flLayerCycle, flWeight, m_flTime, NULL );
}
}
}
// FIXME: Try enabling this?
// CalcAutoplaySequences( pStudioHdr, NULL, pos, q, pPoseParameter, BONE_USED_BY_VERTEX_AT_LOD( m_nLOD ), flTime );
matrix3x4_t temp;
if ( nMaxBoneCount > studioHdr.numbones() )
{
nMaxBoneCount = studioHdr.numbones();
}
for ( int i = 0; i < nMaxBoneCount; i++ )
{
// If it's not being used, fill with NAN for errors
#ifdef _DEBUG
if ( !(studioHdr.pBone( i )->flags & BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ) ) )
{
int j, k;
for (j = 0; j < 3; j++)
{
for (k = 0; k < 4; k++)
{
pBoneToWorld[i][j][k] = VEC_T_NAN;
}
}
continue;
}
#endif
matrix3x4_t boneMatrix;
QuaternionMatrix( q[i], boneMatrix );
MatrixSetColumn( pos[i], 3, boneMatrix );
if ( studioHdr.pBone(i)->parent == -1 )
{
ConcatTransforms( rootToWorld, boneMatrix, pBoneToWorld[i] );
}
else
{
ConcatTransforms( pBoneToWorld[ studioHdr.pBone(i)->parent ], boneMatrix, pBoneToWorld[i] );
}
}
Studio_RunBoneFlexDrivers( m_pFlexControls, &studioHdr, pos, pBoneToWorld, rootToWorld );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDL::SetupBonesWithBoneMerge( const CStudioHdr *pMergeHdr, matrix3x4_t *pMergeBoneToWorld,
const CStudioHdr *pFollow, const matrix3x4_t *pFollowBoneToWorld,
const matrix3x4_t &matModelToWorld )
{
// Default to middle of the pose parameter range
int nPoseCount = pMergeHdr->GetNumPoseParameters();
float pPoseParameter[MAXSTUDIOPOSEPARAM];
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; ++i )
{
pPoseParameter[i] = 0.5f;
if ( i < nPoseCount )
{
const mstudioposeparamdesc_t &Pose = ((CStudioHdr *)pMergeHdr)->pPoseParameter( i );
// Want to try for a zero state. If one doesn't exist set it to .5 by default.
if ( Pose.start < 0.0f && Pose.end > 0.0f )
{
float flPoseDelta = Pose.end - Pose.start;
pPoseParameter[i] = -Pose.start / flPoseDelta;
}
}
}
int nFrameCount = Studio_MaxFrame( pMergeHdr, m_nSequence, pPoseParameter );
if ( nFrameCount == 0 )
{
nFrameCount = 1;
}
float flCycle = ( m_flTime * m_flPlaybackRate ) / nFrameCount;
// FIXME: We're always wrapping; may want to determing if we should clamp
flCycle -= (int)(flCycle);
Vector pos[MAXSTUDIOBONES];
Quaternion q[MAXSTUDIOBONES];
IBoneSetup boneSetup( pMergeHdr, BONE_USED_BY_ANYTHING_AT_LOD( m_nLOD ), pPoseParameter );
boneSetup.InitPose( pos, q );
boneSetup.AccumulatePose( pos, q, m_nSequence, flCycle, 1.0f, m_flTime, NULL );
// Get the merge bone list.
mstudiobone_t *pMergeBones = pMergeHdr->pBone( 0 );
for ( int iMergeBone = 0; iMergeBone < pMergeHdr->numbones(); ++iMergeBone )
{
// Now find the bone in the parent entity.
bool bMerged = false;
int iParentBoneIndex = Studio_BoneIndexByName( pFollow, pMergeBones[iMergeBone].pszName() );
if ( iParentBoneIndex >= 0 )
{
MatrixCopy( pFollowBoneToWorld[iParentBoneIndex], pMergeBoneToWorld[iMergeBone] );
bMerged = true;
}
if ( !bMerged )
{
// If we get down here, then the bone wasn't merged.
matrix3x4_t matBone;
QuaternionMatrix( q[iMergeBone], pos[iMergeBone], matBone );
if ( pMergeBones[iMergeBone].parent == -1 )
{
ConcatTransforms( matModelToWorld, matBone, pMergeBoneToWorld[iMergeBone] );
}
else
{
ConcatTransforms( pMergeBoneToWorld[pMergeBones[iMergeBone].parent], matBone, pMergeBoneToWorld[iMergeBone] );
}
}
}
}

View File

@ -0,0 +1,201 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "../game/shared/choreoscene.h"
#include "../game/shared/choreoactor.h"
#include "../game/shared/choreochannel.h"
#include "../game/shared/choreoevent.h"
#include "../game/shared/iscenetokenprocessor.h"
#include "characterset.h"
//-----------------------------------------------------------------------------
// Purpose: Helper for parsing scene data file
//-----------------------------------------------------------------------------
class CSceneTokenProcessor : public ISceneTokenProcessor
{
public:
CSceneTokenProcessor();
const char *CurrentToken( void );
bool GetToken( bool crossline );
bool TokenAvailable( void );
void Error( const char *fmt, ... );
void SetBuffer( char *buffer );
private:
const char *ParseNextToken (const char *data);
const char *m_pBuffer;
char m_szToken[ 1024 ];
characterset_t m_BreakSetIncludingColons;
};
CSceneTokenProcessor::CSceneTokenProcessor()
{
CharacterSetBuild( &m_BreakSetIncludingColons, "{}()':" );
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : const char
//-----------------------------------------------------------------------------
const char *CSceneTokenProcessor::CurrentToken( void )
{
return m_szToken;
}
const char *CSceneTokenProcessor::ParseNextToken (const char *data)
{
unsigned char c;
int len;
characterset_t *breaks;
breaks = &m_BreakSetIncludingColons;
len = 0;
m_szToken[0] = 0;
if (!data)
return NULL;
// skip whitespace
skipwhite:
while ( (c = *data) <= ' ')
{
if (c == 0)
return NULL; // end of file;
data++;
}
// skip // comments
if (c=='/' && data[1] == '/')
{
while (*data && *data != '\n')
data++;
goto skipwhite;
}
// handle quoted strings specially
if (c == '\"')
{
data++;
while (1)
{
c = *data++;
if (c=='\"' || !c)
{
m_szToken[len] = 0;
return data;
}
m_szToken[len] = c;
len++;
}
}
// parse single characters
if ( IN_CHARACTERSET( *breaks, c ) )
{
m_szToken[len] = c;
len++;
m_szToken[len] = 0;
return data+1;
}
// parse a regular word
do
{
m_szToken[len] = c;
data++;
len++;
c = *data;
if ( IN_CHARACTERSET( *breaks, c ) )
break;
} while (c>32);
m_szToken[len] = 0;
return data;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : crossline -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CSceneTokenProcessor::GetToken( bool crossline )
{
// NOTE: crossline is ignored here, may need to implement if needed
m_pBuffer = ParseNextToken( m_pBuffer );
if ( m_szToken[0] )
return true;
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CSceneTokenProcessor::TokenAvailable( void )
{
const char *search_p = m_pBuffer;
while ( *search_p <= 32)
{
if (*search_p == '\n')
return false;
search_p++;
if ( !*search_p )
return false;
}
if (*search_p == ';' || *search_p == '#' || // semicolon and # is comment field
(*search_p == '/' && *((search_p)+1) == '/')) // also make // a comment field
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *fmt -
// ... -
//-----------------------------------------------------------------------------
void CSceneTokenProcessor::Error( const char *fmt, ... )
{
char string[ 2048 ];
va_list argptr;
va_start( argptr, fmt );
Q_vsnprintf( string, sizeof(string), fmt, argptr );
va_end( argptr );
Warning( "%s", string );
Assert(0);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *buffer -
//-----------------------------------------------------------------------------
void CSceneTokenProcessor::SetBuffer( char *buffer )
{
m_pBuffer = buffer;
}
CSceneTokenProcessor g_TokenProcessor;
ISceneTokenProcessor *GetTokenProcessor()
{
return &g_TokenProcessor;
}
void SetTokenProcessorBuffer( const char *buf )
{
g_TokenProcessor.SetBuffer( (char *)buf );
}

47
tier3/studiohdrstub.cpp Normal file
View File

@ -0,0 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
//#include "studio.h"
#include "studio.h"
#include "datacache/imdlcache.h"
#include "datamodel/dmelementfactoryhelper.h"
#include "istudiorender.h"
#include "bone_setup.h"
#include "tier3/tier3.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
// FIXME: This trashy glue code is really not acceptable. Figure out a way of making it unnecessary.
//-----------------------------------------------------------------------------
const studiohdr_t *studiohdr_t::FindModel( void **cache, char const *pModelName ) const
{
MDLHandle_t handle = g_pMDLCache->FindMDL( pModelName );
*cache = (void*)(uintp)handle;
return g_pMDLCache->GetStudioHdr( handle );
}
virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const
{
return g_pMDLCache->GetVirtualModel( (MDLHandle_t)((int)virtualModel&0xffff) );
}
byte *studiohdr_t::GetAnimBlock( int i ) const
{
return g_pMDLCache->GetAnimBlock( (MDLHandle_t)((int)virtualModel&0xffff), i );
}
int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const
{
return g_pMDLCache->GetAutoplayList( (MDLHandle_t)((int)virtualModel&0xffff), pOut );
}
const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const
{
return g_pMDLCache->GetStudioHdr( (MDLHandle_t)((int)cache&0xffff) );
}

154
tier3/tier3.cpp Normal file
View File

@ -0,0 +1,154 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: A higher level link library for general use in the game and tools.
//
//===========================================================================//
#include "tier3/tier3.h"
#include "tier0/dbg.h"
#include "istudiorender.h"
#include "vgui/IVGui.h"
#include "vgui/IInput.h"
#include "vgui/IPanel.h"
#include "vgui/ISurface.h"
#include "vgui/ILocalize.h"
#include "vgui/IScheme.h"
#include "vgui/ISystem.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "datacache/idatacache.h"
#include "datacache/imdlcache.h"
#include "video/ivideoservices.h"
#include "movieobjects/idmemakefileutils.h"
#include "vphysics_interface.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include "ivtex.h"
//-----------------------------------------------------------------------------
// These tier3 libraries must be set by any users of this library.
// They can be set by calling ConnectTier3Libraries.
// It is hoped that setting this, and using this library will be the common mechanism for
// allowing link libraries to access tier3 library interfaces
//-----------------------------------------------------------------------------
IStudioRender *g_pStudioRender = 0;
IStudioRender *studiorender = 0;
IMatSystemSurface *g_pMatSystemSurface = 0;
vgui::IInput *g_pVGuiInput = 0;
vgui::ISurface *g_pVGuiSurface = 0;
vgui::IPanel *g_pVGuiPanel = 0;
vgui::IVGui *g_pVGui = 0;
vgui::ILocalize *g_pVGuiLocalize = 0;
vgui::ISchemeManager *g_pVGuiSchemeManager = 0;
vgui::ISystem *g_pVGuiSystem = 0;
IDataCache *g_pDataCache = 0;
IMDLCache *g_pMDLCache = 0;
IMDLCache *mdlcache = 0;
IVideoServices *g_pVideo = NULL;
IDmeMakefileUtils *g_pDmeMakefileUtils = 0;
IPhysicsCollision *g_pPhysicsCollision = 0;
ISoundEmitterSystemBase *g_pSoundEmitterSystem = 0;
IVTex *g_pVTex = 0;
//-----------------------------------------------------------------------------
// Call this to connect to all tier 3 libraries.
// It's up to the caller to check the globals it cares about to see if ones are missing
//-----------------------------------------------------------------------------
void ConnectTier3Libraries( CreateInterfaceFn *pFactoryList, int nFactoryCount )
{
// Don't connect twice..
Assert( !g_pStudioRender && !studiorender && !g_pMatSystemSurface && !g_pVGui && !g_pVGuiPanel && !g_pVGuiInput &&
!g_pVGuiSurface && !g_pDataCache && !g_pMDLCache && !mdlcache && !g_pVideo &&
!g_pDmeMakefileUtils && !g_pPhysicsCollision && !g_pVGuiLocalize && !g_pSoundEmitterSystem &&
!g_pVGuiSchemeManager && !g_pVGuiSystem );
for ( int i = 0; i < nFactoryCount; ++i )
{
if ( !g_pStudioRender )
{
g_pStudioRender = studiorender = ( IStudioRender * )pFactoryList[i]( STUDIO_RENDER_INTERFACE_VERSION, NULL );
}
if ( !g_pVGui )
{
g_pVGui = (vgui::IVGui*)pFactoryList[i]( VGUI_IVGUI_INTERFACE_VERSION, NULL );
}
if ( !g_pVGuiInput )
{
g_pVGuiInput = (vgui::IInput*)pFactoryList[i]( VGUI_INPUT_INTERFACE_VERSION, NULL );
}
if ( !g_pVGuiPanel )
{
g_pVGuiPanel = (vgui::IPanel*)pFactoryList[i]( VGUI_PANEL_INTERFACE_VERSION, NULL );
}
if ( !g_pVGuiSurface )
{
g_pVGuiSurface = (vgui::ISurface*)pFactoryList[i]( VGUI_SURFACE_INTERFACE_VERSION, NULL );
}
if ( !g_pVGuiSchemeManager )
{
g_pVGuiSchemeManager = (vgui::ISchemeManager*)pFactoryList[i]( VGUI_SCHEME_INTERFACE_VERSION, NULL );
}
if ( !g_pVGuiSystem )
{
g_pVGuiSystem = (vgui::ISystem*)pFactoryList[i]( VGUI_SYSTEM_INTERFACE_VERSION, NULL );
}
if ( !g_pVGuiLocalize )
{
g_pVGuiLocalize = (vgui::ILocalize*)pFactoryList[i]( VGUI_LOCALIZE_INTERFACE_VERSION, NULL );
}
if ( !g_pMatSystemSurface )
{
g_pMatSystemSurface = ( IMatSystemSurface * )pFactoryList[i]( MAT_SYSTEM_SURFACE_INTERFACE_VERSION, NULL );
}
if ( !g_pDataCache )
{
g_pDataCache = (IDataCache*)pFactoryList[i]( DATACACHE_INTERFACE_VERSION, NULL );
}
if ( !g_pMDLCache )
{
g_pMDLCache = mdlcache = (IMDLCache*)pFactoryList[i]( MDLCACHE_INTERFACE_VERSION, NULL );
}
if ( !g_pVideo )
{
g_pVideo = (IVideoServices *)pFactoryList[i](VIDEO_SERVICES_INTERFACE_VERSION, NULL);
}
if ( !g_pDmeMakefileUtils )
{
g_pDmeMakefileUtils = (IDmeMakefileUtils*)pFactoryList[i]( DMEMAKEFILE_UTILS_INTERFACE_VERSION, NULL );
}
if ( !g_pPhysicsCollision )
{
g_pPhysicsCollision = ( IPhysicsCollision* )pFactoryList[i]( VPHYSICS_COLLISION_INTERFACE_VERSION, NULL );
}
if ( !g_pSoundEmitterSystem )
{
g_pSoundEmitterSystem = ( ISoundEmitterSystemBase* )pFactoryList[i]( SOUNDEMITTERSYSTEM_INTERFACE_VERSION, NULL );
}
if ( !g_pVTex )
{
g_pVTex = ( IVTex * )pFactoryList[i]( IVTEX_VERSION_STRING, NULL );
}
}
}
void DisconnectTier3Libraries()
{
g_pStudioRender = 0;
studiorender = 0;
g_pVGui = 0;
g_pVGuiInput = 0;
g_pVGuiPanel = 0;
g_pVGuiSurface = 0;
g_pVGuiLocalize = 0;
g_pVGuiSchemeManager = 0;
g_pVGuiSystem = 0;
g_pMatSystemSurface = 0;
g_pDataCache = 0;
g_pMDLCache = 0;
mdlcache = 0;
g_pVideo = NULL;
g_pPhysicsCollision = 0;
g_pDmeMakefileUtils = NULL;
g_pSoundEmitterSystem = 0;
g_pVTex = NULL;
}

29
tier3/tier3.vpc Normal file
View File

@ -0,0 +1,29 @@
//-----------------------------------------------------------------------------
// TIER3.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$macro SRCDIR ".."
$include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
$Project "tier3"
{
$Folder "Source Files"
{
$File "tier3.cpp"
$File "mdlutils.cpp"
$File "choreoutils.cpp"
$File "scenetokenprocessor.cpp"
$File "studiohdrstub.cpp"
}
$Folder "Header Files"
{
$File "$SRCDIR\public\tier3\tier3.h"
$File "$SRCDIR\public\tier3\mdlutils.h"
$File "$SRCDIR\public\tier3\choreoutils.h"
$File "$SRCDIR\public\tier3\scenetokenprocessor.h"
}
}