diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tier3 | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'tier3')
| -rw-r--r-- | tier3/choreoutils.cpp | 347 | ||||
| -rw-r--r-- | tier3/mdlutils.cpp | 459 | ||||
| -rw-r--r-- | tier3/scenetokenprocessor.cpp | 201 | ||||
| -rw-r--r-- | tier3/studiohdrstub.cpp | 47 | ||||
| -rw-r--r-- | tier3/tier3.cpp | 154 | ||||
| -rw-r--r-- | tier3/tier3.vpc | 29 |
6 files changed, 1237 insertions, 0 deletions
diff --git a/tier3/choreoutils.cpp b/tier3/choreoutils.cpp new file mode 100644 index 0000000..613103e --- /dev/null +++ b/tier3/choreoutils.cpp @@ -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 ); +} diff --git a/tier3/mdlutils.cpp b/tier3/mdlutils.cpp new file mode 100644 index 0000000..afe8729 --- /dev/null +++ b/tier3/mdlutils.cpp @@ -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] ); + } + } + } +} + diff --git a/tier3/scenetokenprocessor.cpp b/tier3/scenetokenprocessor.cpp new file mode 100644 index 0000000..b1730a5 --- /dev/null +++ b/tier3/scenetokenprocessor.cpp @@ -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 ); +} + diff --git a/tier3/studiohdrstub.cpp b/tier3/studiohdrstub.cpp new file mode 100644 index 0000000..44d05ad --- /dev/null +++ b/tier3/studiohdrstub.cpp @@ -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) ); +} + diff --git a/tier3/tier3.cpp b/tier3/tier3.cpp new file mode 100644 index 0000000..20241a6 --- /dev/null +++ b/tier3/tier3.cpp @@ -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; +} diff --git a/tier3/tier3.vpc b/tier3/tier3.vpc new file mode 100644 index 0000000..ccec731 --- /dev/null +++ b/tier3/tier3.vpc @@ -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" + } +} |