summaryrefslogtreecommitdiff
path: root/utils/hlmv/studio_utils.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/hlmv/studio_utils.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'utils/hlmv/studio_utils.cpp')
-rw-r--r--utils/hlmv/studio_utils.cpp1224
1 files changed, 1224 insertions, 0 deletions
diff --git a/utils/hlmv/studio_utils.cpp b/utils/hlmv/studio_utils.cpp
new file mode 100644
index 0000000..d37f87b
--- /dev/null
+++ b/utils/hlmv/studio_utils.cpp
@@ -0,0 +1,1224 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// updates:
+// 1-4-99 fixed file texture load and file read bug
+
+////////////////////////////////////////////////////////////////////////
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include "StudioModel.h"
+#include "vphysics/constraints.h"
+#include "physmesh.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/imaterial.h"
+#include "ViewerSettings.h"
+#include "bone_setup.h"
+#include "UtlMemory.h"
+#include "mxtk/mx.h"
+#include "filesystem.h"
+#include "IStudioRender.h"
+#include "materialsystem/IMaterialSystemHardwareConfig.h"
+#include "MDLViewer.h"
+#include "optimize.h"
+
+extern char g_appTitle[];
+Vector *StudioModel::m_AmbientLightColors;
+
+#pragma warning( disable : 4244 ) // double to float
+
+
+static StudioModel g_studioModel;
+static StudioModel *g_pActiveModel;
+
+// Expose it to the rest of the app
+StudioModel *g_pStudioModel = &g_studioModel;
+StudioModel *g_pStudioExtraModel[HLMV_MAX_MERGED_MODELS];
+
+StudioModel::StudioModel()
+{
+ m_MDLHandle = MDLHANDLE_INVALID;
+ ClearLookTargets();
+}
+
+void StudioModel::Init()
+{
+ m_AmbientLightColors = new Vector[g_pStudioRender->GetNumAmbientLightSamples()];
+
+ // JasonM & garymcthack - should really only do this once a frame and at init time.
+ UpdateStudioRenderConfig( g_viewerSettings.renderMode == RM_WIREFRAME, false,
+ g_viewerSettings.showNormals,
+ g_viewerSettings.showTangentFrame );
+}
+
+void StudioModel::Shutdown( void )
+{
+ g_pStudioModel->FreeModel( false );
+ delete [] m_AmbientLightColors;
+}
+
+void StudioModel::SetCurrentModel()
+{
+ // track the correct model
+ g_pActiveModel = this;
+}
+
+void StudioModel::ReleaseStudioModel()
+{
+ SaveViewerSettings( g_pStudioModel->GetFileName(), g_pStudioModel );
+ g_pStudioModel->FreeModel( true );
+}
+
+void StudioModel::RestoreStudioModel()
+{
+ // should view settings be loaded before the model is loaded?
+ if ( g_pStudioModel->LoadModel( g_pStudioModel->m_pModelName ) )
+ {
+ g_pStudioModel->PostLoadModel( g_pStudioModel->m_pModelName );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees the model data and releases textures from OpenGL.
+//-----------------------------------------------------------------------------
+void StudioModel::FreeModel( bool bReleasing )
+{
+ if ( m_pStudioHdr )
+ {
+ delete m_pStudioHdr;
+ m_pStudioHdr = NULL;
+ }
+
+ if ( m_MDLHandle != MDLHANDLE_INVALID )
+ {
+ g_pMDLCache->Release( m_MDLHandle );
+ m_MDLHandle = MDLHANDLE_INVALID;
+ }
+
+ if ( !bReleasing )
+ {
+ if (m_pModelName)
+ {
+ delete[] m_pModelName;
+ m_pModelName = NULL;
+ }
+ }
+
+ m_SurfaceProps.Purge();
+
+ DestroyPhysics( m_pPhysics );
+ m_pPhysics = NULL;
+}
+
+void *StudioModel::operator new( size_t stAllocateBlock )
+{
+ // call into engine to get memory
+ Assert( stAllocateBlock != 0 );
+ return calloc( 1, stAllocateBlock );
+}
+
+void StudioModel::operator delete( void *pMem )
+{
+#ifdef _DEBUG
+ // set the memory to a known value
+ int size = _msize( pMem );
+ memset( pMem, 0xcd, size );
+#endif
+
+ // get the engine to free the memory
+ free( pMem );
+}
+
+void *StudioModel::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
+{
+ // call into engine to get memory
+ Assert( stAllocateBlock != 0 );
+ return calloc( 1, stAllocateBlock );
+}
+
+void StudioModel::operator delete( void *pMem, int nBlockUse, const char *pFileName, int nLine )
+{
+#ifdef _DEBUG
+ // set the memory to a known value
+ int size = _msize( pMem );
+ memset( pMem, 0xcd, size );
+#endif
+ // get the engine to free the memory
+ free( pMem );
+}
+
+bool StudioModel::LoadModel( const char *pModelName )
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ if (!pModelName)
+ return 0;
+
+ // In the case of restore, m_pModelName == modelname
+ if (m_pModelName != pModelName)
+ {
+ // Copy over the model name; we'll need it later...
+ if (m_pModelName)
+ {
+ delete[] m_pModelName;
+ }
+ m_pModelName = new char[Q_strlen(pModelName) + 1];
+ strcpy( m_pModelName, pModelName );
+ }
+
+ m_MDLHandle = g_pMDLCache->FindMDL( pModelName );
+
+ // allocate a pool for a studiohdr cache
+ if (m_pStudioHdr != NULL)
+ {
+ delete m_pStudioHdr;
+ }
+ m_pStudioHdr = new CStudioHdr( g_pMDLCache->GetStudioHdr( m_MDLHandle ), g_pMDLCache );
+
+ // manadatory to access correct verts
+ SetCurrentModel();
+
+ m_pPhysics = LoadPhysics( m_MDLHandle );
+
+ // Copy over all of the hitboxes; we may add and remove elements
+ m_HitboxSets.RemoveAll();
+
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+
+ int i;
+ for ( int s = 0; s < pStudioHdr->numhitboxsets(); s++ )
+ {
+ mstudiohitboxset_t *pSrcSet = pStudioHdr->pHitboxSet( s );
+ if ( !pSrcSet )
+ continue;
+
+ int j = m_HitboxSets.AddToTail();
+ HitboxSet_t &set = m_HitboxSets[j];
+ set.m_Name = pSrcSet->pszName();
+
+ for ( i = 0; i < pSrcSet->numhitboxes; ++i )
+ {
+ mstudiobbox_t *pHit = pSrcSet->pHitbox(i);
+ int nIndex = set.m_Hitboxes.AddToTail( );
+ HitboxInfo_t &hitbox = set.m_Hitboxes[nIndex];
+
+ hitbox.m_Name = pHit->pszHitboxName();
+ hitbox.m_BBox = *pHit;
+
+ // Blat out bbox name index so we don't use it by mistake...
+ hitbox.m_BBox.szhitboxnameindex = 0;
+ }
+ }
+
+ // Copy over all of the surface props; we may change them...
+ for ( i = 0; i < pStudioHdr->numbones(); ++i )
+ {
+ mstudiobone_t* pBone = pStudioHdr->pBone(i);
+
+ CUtlSymbol prop( pBone->pszSurfaceProp() );
+ m_SurfaceProps.AddToTail( prop );
+ }
+
+ m_physPreviewBone = -1;
+
+ bool forceOpaque = (pStudioHdr->flags() & STUDIOHDR_FLAGS_FORCE_OPAQUE) != 0;
+ bool vertexLit = false;
+ m_bIsTransparent = false;
+ m_bHasProxy = false;
+
+ studiohwdata_t *pHardwareData = g_pMDLCache->GetHardwareData( m_MDLHandle );
+ if ( !pHardwareData )
+ {
+ Assert( 0 );
+ return false;
+ }
+
+ for( int lodID = pHardwareData->m_RootLOD; lodID < pHardwareData->m_NumLODs; lodID++ )
+ {
+ studioloddata_t *pLODData = &pHardwareData->m_pLODs[lodID];
+ for ( i = 0; i < pLODData->numMaterials; ++i )
+ {
+ if (pLODData->ppMaterials[i]->IsVertexLit())
+ {
+ vertexLit = true;
+ }
+ if ((!forceOpaque) && pLODData->ppMaterials[i]->IsTranslucent())
+ {
+ m_bIsTransparent = true;
+ //Msg("Translucent material %s for model %s\n", pLODData->ppMaterials[i]->GetName(), pStudioHdr->name );
+ }
+ if (pLODData->ppMaterials[i]->HasProxy())
+ {
+ m_bHasProxy = true;
+ }
+ }
+ }
+
+ return true;
+}
+
+
+
+bool StudioModel::PostLoadModel( const char *modelname )
+{
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (pStudioHdr == NULL)
+ return false;
+
+ SetSequence (0);
+ SetController (0, 0.0f);
+ SetController (1, 0.0f);
+ SetController (2, 0.0f);
+ SetController (3, 0.0f);
+ SetBlendTime( DEFAULT_BLEND_TIME );
+ // SetHeadTurn( 1.0f ); // FIXME:!!!
+
+ int n;
+ for (n = 0; n < pStudioHdr->numbodyparts(); n++)
+ {
+ SetBodygroup (n, 0);
+ }
+
+ SetSkin (0);
+
+/*
+ Vector mins, maxs;
+ ExtractBbox (mins, maxs);
+ if (mins[2] < 5.0f)
+ m_origin[2] = -mins[2];
+*/
+ return true;
+}
+
+
+//------------------------------------------------------------------------------
+// Returns true if the model has at least one body part with model data, false if not.
+//------------------------------------------------------------------------------
+bool StudioModel::HasModel()
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return false;
+
+ for ( int i = 0; i < pStudioHdr->numbodyparts(); i++ )
+ {
+ if ( pStudioHdr->pBodypart(i)->nummodels )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+
+
+int StudioModel::GetSequence( )
+{
+ return m_sequence;
+}
+
+int StudioModel::SetSequence( int iSequence )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return 0;
+
+ if (iSequence < 0)
+ return 0;
+
+ if (iSequence > pStudioHdr->GetNumSeq())
+ return m_sequence;
+
+ m_prevsequence = m_sequence;
+ m_sequence = iSequence;
+ m_cycle = 0;
+ m_sequencetime = 0.0;
+
+ return m_sequence;
+}
+
+const char* StudioModel::GetSequenceName( int iSequence )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return NULL;
+
+ if (iSequence < 0)
+ return NULL;
+
+ if (iSequence > pStudioHdr->GetNumSeq())
+ return NULL;
+
+ return pStudioHdr->pSeqdesc( iSequence ).pszLabel();
+}
+
+void StudioModel::ClearOverlaysSequences( void )
+{
+ ClearAnimationLayers( );
+ memset( m_Layer, 0, sizeof( m_Layer ) );
+}
+
+void StudioModel::ClearAnimationLayers( void )
+{
+ m_iActiveLayers = 0;
+}
+
+int StudioModel::GetNewAnimationLayer( int iPriority )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return 0;
+
+ if ( m_iActiveLayers >= MAXSTUDIOANIMLAYERS )
+ {
+ Assert( 0 );
+ return MAXSTUDIOANIMLAYERS - 1;
+ }
+
+ m_Layer[m_iActiveLayers].m_priority = iPriority;
+
+ return m_iActiveLayers++;
+}
+
+int StudioModel::SetOverlaySequence( int iLayer, int iSequence, float flWeight )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return 0;
+
+ if (iSequence < 0)
+ return 0;
+
+ if (iLayer < 0 || iLayer >= MAXSTUDIOANIMLAYERS)
+ {
+ Assert(0);
+ return 0;
+ }
+
+ if (iSequence > pStudioHdr->GetNumSeq())
+ return m_Layer[iLayer].m_sequence;
+
+ m_Layer[iLayer].m_sequence = iSequence;
+ m_Layer[iLayer].m_weight = flWeight;
+ m_Layer[iLayer].m_playbackrate = 1.0;
+
+ return iSequence;
+}
+
+float StudioModel::SetOverlayRate( int iLayer, float flCycle, float flPlaybackRate )
+{
+ if (iLayer >= 0 && iLayer < MAXSTUDIOANIMLAYERS)
+ {
+ m_Layer[iLayer].m_cycle = flCycle;
+ m_Layer[iLayer].m_playbackrate = flPlaybackRate;
+ }
+ return flCycle;
+}
+
+
+int StudioModel::GetOverlaySequence( int iLayer )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return -1;
+
+ if (iLayer < 0 || iLayer >= MAXSTUDIOANIMLAYERS)
+ {
+ Assert(0);
+ return 0;
+ }
+
+ return m_Layer[iLayer].m_sequence;
+}
+
+
+float StudioModel::GetOverlaySequenceWeight( int iLayer )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return -1;
+
+ if (iLayer < 0 || iLayer >= MAXSTUDIOANIMLAYERS)
+ {
+ Assert(0);
+ return 0;
+ }
+
+ return m_Layer[iLayer].m_weight;
+}
+
+
+int StudioModel::LookupSequence( const char *szSequence )
+{
+ int i;
+
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return -1;
+
+ for (i = 0; i < pStudioHdr->GetNumSeq(); i++)
+ {
+ if (!stricmp( szSequence, pStudioHdr->pSeqdesc( i ).pszLabel() ))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int StudioModel::LookupActivity( const char *szActivity )
+{
+ int i;
+
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return -1;
+
+ for (i = 0; i < pStudioHdr->GetNumSeq(); i++)
+ {
+ if (!stricmp( szActivity, pStudioHdr->pSeqdesc( i ).pszActivityName() ))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int StudioModel::SetSequence( const char *szSequence )
+{
+ return SetSequence( LookupSequence( szSequence ) );
+}
+
+void StudioModel::StartBlending( void )
+{
+ // Switch back to old sequence ( this will oscillate between this one and the last one )
+ SetSequence( m_prevsequence );
+}
+
+void StudioModel::SetBlendTime( float blendtime )
+{
+ if ( blendtime > 0.0f )
+ {
+ m_blendtime = blendtime;
+ }
+}
+
+float StudioModel::GetTransitionAmount( void )
+{
+ if ( g_viewerSettings.blendSequenceChanges &&
+ m_sequencetime < m_blendtime && m_prevsequence != m_sequence )
+ {
+ float s;
+ s = ( m_sequencetime / m_blendtime );
+ return s;
+ }
+
+ return 0.0f;
+}
+
+LocalFlexController_t StudioModel::LookupFlexController( char *szName )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return LocalFlexController_t(0);
+
+ for (LocalFlexController_t iFlex = LocalFlexController_t(0); iFlex < pStudioHdr->numflexcontrollers(); iFlex++)
+ {
+ if (stricmp( szName, pStudioHdr->pFlexcontroller( iFlex )->pszName() ) == 0)
+ {
+ return iFlex;
+ }
+ }
+ return LocalFlexController_t(-1);
+}
+
+
+void StudioModel::SetFlexController( char *szName, float flValue )
+{
+ SetFlexController( LookupFlexController( szName ), flValue );
+}
+
+void StudioModel::SetFlexController( LocalFlexController_t iFlex, float flValue )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return;
+
+ if (iFlex >= 0 && iFlex < pStudioHdr->numflexcontrollers())
+ {
+ mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller(iFlex);
+
+ if (pflex->min != pflex->max)
+ {
+ flValue = (flValue - pflex->min) / (pflex->max - pflex->min);
+ }
+ m_flexweight[iFlex] = clamp( flValue, 0.0f, 1.0f );
+ }
+}
+
+
+void StudioModel::SetFlexControllerRaw( LocalFlexController_t iFlex, float flValue )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return;
+
+ if (iFlex >= 0 && iFlex < pStudioHdr->numflexcontrollers())
+ {
+// mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller(iFlex);
+ m_flexweight[iFlex] = clamp( flValue, 0.0f, 1.0f );
+ }
+}
+
+float StudioModel::GetFlexController( char *szName )
+{
+ return GetFlexController( LookupFlexController( szName ) );
+}
+
+float StudioModel::GetFlexController( LocalFlexController_t iFlex )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return 0.0f;
+
+ if (iFlex >= 0 && iFlex < pStudioHdr->numflexcontrollers())
+ {
+ mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller(iFlex);
+
+ float flValue = m_flexweight[iFlex];
+
+ if (pflex->min != pflex->max)
+ {
+ flValue = flValue * (pflex->max - pflex->min) + pflex->min;
+ }
+ return flValue;
+ }
+ return 0.0;
+}
+
+
+float StudioModel::GetFlexControllerRaw( LocalFlexController_t iFlex )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return 0.0f;
+
+ if (iFlex >= 0 && iFlex < pStudioHdr->numflexcontrollers())
+ {
+// mstudioflexcontroller_t *pflex = pStudioHdr->pFlexcontroller(iFlex);
+ return m_flexweight[iFlex];
+ }
+ return 0.0;
+}
+
+int StudioModel::GetNumLODs() const
+{
+ return g_pStudioRender->GetNumLODs( *GetHardwareData() );
+}
+
+float StudioModel::GetLODSwitchValue( int lod ) const
+{
+ return g_pStudioRender->GetLODSwitchValue( *GetHardwareData(), lod );
+}
+
+void StudioModel::SetLODSwitchValue( int lod, float switchValue )
+{
+ g_pStudioRender->SetLODSwitchValue( *GetHardwareData(), lod, switchValue );
+}
+
+void StudioModel::ExtractBbox( Vector &mins, Vector &maxs )
+{
+ studiohdr_t *pStudioHdr = GetStudioRenderHdr();
+ if ( !pStudioHdr )
+ return;
+
+ // look for hull
+ if ( ((Vector)pStudioHdr->hull_min).Length() != 0 )
+ {
+ mins = pStudioHdr->hull_min;
+ maxs = pStudioHdr->hull_max;
+ }
+ // look for view clip
+ else if (((Vector)pStudioHdr->view_bbmin).Length() != 0)
+ {
+ mins = pStudioHdr->view_bbmin;
+ maxs = pStudioHdr->view_bbmax;
+ }
+ else
+ {
+ mstudioseqdesc_t &pseqdesc = pStudioHdr->pSeqdesc( m_sequence );
+
+ mins = pseqdesc.bbmin;
+ maxs = pseqdesc.bbmax;
+ }
+}
+
+
+
+void StudioModel::GetSequenceInfo( int iSequence, float *pflFrameRate, float *pflGroundSpeed )
+{
+ float t = GetDuration( iSequence );
+
+ if (t > 0)
+ {
+ *pflFrameRate = 1.0 / t;
+ }
+ else
+ {
+ *pflFrameRate = 1.0;
+ }
+ *pflGroundSpeed = GetGroundSpeed( iSequence );
+}
+
+void StudioModel::GetSequenceInfo( float *pflFrameRate, float *pflGroundSpeed )
+{
+ GetSequenceInfo( m_sequence, pflFrameRate, pflGroundSpeed );
+}
+
+float StudioModel::GetFPS( int iSequence )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return 0.0f;
+
+ return Studio_FPS( pStudioHdr, iSequence, m_poseparameter );
+}
+
+float StudioModel::GetFPS( void )
+{
+ return GetFPS( m_sequence );
+}
+
+float StudioModel::GetDuration( int iSequence )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return 0.0f;
+
+ return Studio_Duration( pStudioHdr, iSequence, m_poseparameter );
+}
+
+
+int StudioModel::GetNumFrames( int iSequence )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr || iSequence < 0 || iSequence >= pStudioHdr->GetNumSeq() )
+ {
+ return 1;
+ }
+
+ return Studio_MaxFrame( pStudioHdr, iSequence, m_poseparameter );
+}
+
+static int GetSequenceFlags( CStudioHdr *pstudiohdr, int sequence )
+{
+ if ( !pstudiohdr ||
+ sequence < 0 ||
+ sequence >= pstudiohdr->GetNumSeq() )
+ {
+ return 0;
+ }
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
+
+ return seqdesc.flags;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : iSequence -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool StudioModel::GetSequenceLoops( int iSequence )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return false;
+
+ int flags = GetSequenceFlags( pStudioHdr, iSequence );
+ bool looping = flags & STUDIO_LOOPING ? true : false;
+ return looping;
+}
+
+float StudioModel::GetDuration( )
+{
+ return GetDuration( m_sequence );
+}
+
+
+void StudioModel::GetMovement( float prevcycle[5], Vector &vecPos, QAngle &vecAngles )
+{
+ vecPos.Init();
+ vecAngles.Init();
+
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return;
+
+ // assume that changes < -0.5 are loops....
+ if (m_cycle - prevcycle[0] < -0.5)
+ {
+ prevcycle[0] = prevcycle[0] - 1.0;
+ }
+
+ Studio_SeqMovement( pStudioHdr, m_sequence, prevcycle[0], m_cycle, m_poseparameter, vecPos, vecAngles );
+ prevcycle[0] = m_cycle;
+
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ Vector vecTmp;
+ QAngle angTmp;
+
+ if (m_Layer[i].m_cycle - prevcycle[i+1] < -0.5)
+ {
+ prevcycle[i+1] = prevcycle[i+1] - 1.0;
+ }
+
+ if (m_Layer[i].m_weight > 0.0)
+ {
+ vecTmp.Init();
+ angTmp.Init();
+ if (Studio_SeqMovement( pStudioHdr, m_Layer[i].m_sequence, prevcycle[i+1], m_Layer[i].m_cycle, m_poseparameter, vecTmp, angTmp ))
+ {
+ vecPos = vecPos * ( 1.0 - m_Layer[i].m_weight ) + vecTmp * m_Layer[i].m_weight;
+ }
+ }
+ prevcycle[i+1] = m_Layer[i].m_cycle;
+ }
+
+ return;
+}
+
+
+void StudioModel::GetMovement( int iSequence, float prevCycle, float nextCycle, Vector &vecPos, QAngle &vecAngles )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ {
+ vecPos.Init();
+ vecAngles.Init();
+ return;
+ }
+
+ // FIXME: this doesn't consider layers
+ Studio_SeqMovement( pStudioHdr, iSequence, prevCycle, nextCycle, m_poseparameter, vecPos, vecAngles );
+
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the ground speed of the specifed sequence.
+//-----------------------------------------------------------------------------
+float StudioModel::GetGroundSpeed( int iSequence )
+{
+ Vector vecMove;
+ QAngle vecAngles;
+ GetMovement( iSequence, 0, 1, vecMove, vecAngles );
+
+ float t = GetDuration( iSequence );
+
+ float flGroundSpeed = 0;
+ if (t > 0)
+ {
+ flGroundSpeed = vecMove.Length() / t;
+ }
+
+ return flGroundSpeed;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the ground speed of the current sequence.
+//-----------------------------------------------------------------------------
+float StudioModel::GetGroundSpeed( void )
+{
+ return GetGroundSpeed( m_sequence );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the ground speed of the current sequence.
+//-----------------------------------------------------------------------------
+float StudioModel::GetCurrentVelocity( void )
+{
+ Vector vecVelocity;
+
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (pStudioHdr && Studio_SeqVelocity( pStudioHdr, m_sequence, m_cycle, m_poseparameter, vecVelocity ))
+ {
+ return vecVelocity.Length();
+ }
+ return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the the sequence should be hidden or not
+//-----------------------------------------------------------------------------
+bool StudioModel::IsHidden( int iSequence )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (pStudioHdr->pSeqdesc( iSequence ).flags & STUDIO_HIDDEN)
+ return true;
+
+ return false;
+}
+
+
+
+void StudioModel::GetSeqAnims( int iSequence, mstudioanimdesc_t *panim[4], float *weight )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return;
+
+ mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( iSequence );
+ Studio_SeqAnims( pStudioHdr, seqdesc, iSequence, m_poseparameter, panim, weight );
+}
+
+void StudioModel::GetSeqAnims( mstudioanimdesc_t *panim[4], float *weight )
+{
+ GetSeqAnims( m_sequence, panim, weight );
+}
+
+
+float StudioModel::SetController( int iController, float flValue )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return 0.0f;
+
+ return Studio_SetController( pStudioHdr, iController, flValue, m_controller[iController] );
+}
+
+
+
+int StudioModel::LookupPoseParameter( char const *szName )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return false;
+
+ for (int iParameter = 0; iParameter < pStudioHdr->GetNumPoseParameters(); iParameter++)
+ {
+ if (stricmp( szName, pStudioHdr->pPoseParameter( iParameter ).pszName() ) == 0)
+ {
+ return iParameter;
+ }
+ }
+ return -1;
+}
+
+float StudioModel::SetPoseParameter( char const *szName, float flValue )
+{
+ return SetPoseParameter( LookupPoseParameter( szName ), flValue );
+}
+
+float StudioModel::SetPoseParameter( int iParameter, float flValue )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return 0.0f;
+
+ return Studio_SetPoseParameter( pStudioHdr, iParameter, flValue, m_poseparameter[iParameter] );
+}
+
+float StudioModel::GetPoseParameter( char const *szName )
+{
+ return GetPoseParameter( LookupPoseParameter( szName ) );
+}
+
+float* StudioModel::GetPoseParameters()
+{
+ return m_poseparameter;
+}
+
+float StudioModel::GetPoseParameter( int iParameter )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return 0.0f;
+
+ return Studio_GetPoseParameter( pStudioHdr, iParameter, m_poseparameter[iParameter] );
+}
+
+bool StudioModel::GetPoseParameterRange( int iParameter, float *pflMin, float *pflMax )
+{
+ *pflMin = 0;
+ *pflMax = 0;
+
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return false;
+
+ if (iParameter < 0 || iParameter >= pStudioHdr->GetNumPoseParameters())
+ return false;
+
+ const mstudioposeparamdesc_t &Pose = pStudioHdr->pPoseParameter( iParameter );
+
+ *pflMin = Pose.start;
+ *pflMax = Pose.end;
+
+ return true;
+}
+
+int StudioModel::LookupAttachment( char const *szName )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if ( !pStudioHdr )
+ return -1;
+
+ for (int i = 0; i < pStudioHdr->GetNumAttachments(); i++)
+ {
+ if (stricmp( pStudioHdr->pAttachment( i ).pszName(), szName ) == 0)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+
+int StudioModel::SetBodygroup( int iGroup, int iValue /*= -1*/ )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return 0;
+
+ if (iGroup > pStudioHdr->numbodyparts())
+ return -1;
+
+ mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( iGroup );
+
+ int iCurrent = (m_bodynum / pbodypart->base) % pbodypart->nummodels;
+
+ // if the submodel index is not specified or out of range, just use the current value
+ if ( iValue < 0 || iValue >= pbodypart->nummodels )
+ return iCurrent;
+
+ m_bodynum = (m_bodynum - (iCurrent * pbodypart->base) + (iValue * pbodypart->base));
+
+ return iValue;
+}
+
+
+int StudioModel::SetSkin( int iValue )
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return 0;
+
+ if (iValue >= pStudioHdr->numskinfamilies())
+ {
+ return m_skinnum;
+ }
+
+ m_skinnum = iValue;
+
+ return iValue;
+}
+
+
+
+void StudioModel::scaleMeshes (float scale)
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return;
+
+ int i, j, k;
+
+ // manadatory to access correct verts
+ SetCurrentModel();
+
+ // scale verts
+ int tmp = m_bodynum;
+ for (i = 0; i < pStudioHdr->numbodyparts(); i++)
+ {
+ mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( i );
+ for (j = 0; j < pbodypart->nummodels; j++)
+ {
+ SetBodygroup (i, j);
+ SetupModel (i);
+
+ const mstudio_modelvertexdata_t *vertData = m_pmodel->GetVertexData();
+ Assert( vertData ); // This can only return NULL on X360 for now
+
+ for (k = 0; k < m_pmodel->numvertices; k++)
+ {
+ *vertData->Position(k) *= scale;
+ }
+ }
+ }
+
+ m_bodynum = tmp;
+
+ // scale complex hitboxes
+ int hitboxset = g_MDLViewer->GetCurrentHitboxSet();
+
+ mstudiobbox_t *pbboxes = pStudioHdr->pHitbox( 0, hitboxset );
+ for (i = 0; i < pStudioHdr->iHitboxCount( hitboxset ); i++)
+ {
+ VectorScale (pbboxes[i].bbmin, scale, pbboxes[i].bbmin);
+ VectorScale (pbboxes[i].bbmax, scale, pbboxes[i].bbmax);
+ }
+
+ // scale bounding boxes
+ for (i = 0; i < pStudioHdr->GetNumSeq(); i++)
+ {
+ mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( i );
+ Vector tmp;
+
+ tmp = seqdesc.bbmin;
+ VectorScale( tmp, scale, tmp );
+ seqdesc.bbmin = tmp;
+
+ tmp = seqdesc.bbmax;
+ VectorScale( tmp, scale, tmp );
+ seqdesc.bbmax = tmp;
+
+ }
+
+ // maybe scale exeposition, pivots, attachments
+}
+
+
+
+void StudioModel::scaleBones (float scale)
+{
+ CStudioHdr *pStudioHdr = GetStudioHdr();
+ if (!pStudioHdr)
+ return;
+
+ mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
+ for (int i = 0; i < pStudioHdr->numbones(); i++)
+ {
+ pbones[i].pos *= scale;
+ pbones[i].posscale *= scale;
+ }
+}
+
+int StudioModel::Physics_GetBoneCount( void )
+{
+ return m_pPhysics->Count();
+}
+
+
+const char *StudioModel::Physics_GetBoneName( int index )
+{
+ CPhysmesh *pmesh = m_pPhysics->GetMesh( index );
+
+ if ( !pmesh )
+ return NULL;
+
+ return pmesh->m_boneName;
+}
+
+
+void StudioModel::Physics_GetData( int boneIndex, hlmvsolid_t *psolid, constraint_ragdollparams_t *pConstraint ) const
+{
+ CPhysmesh *pMesh = m_pPhysics->GetMesh( boneIndex );
+
+ if ( !pMesh )
+ return;
+
+ if ( psolid )
+ {
+ memcpy( psolid, &pMesh->m_solid, sizeof(*psolid) );
+ }
+
+ if ( pConstraint )
+ {
+ *pConstraint = pMesh->m_constraint;
+ }
+}
+
+void StudioModel::Physics_SetData( int boneIndex, const hlmvsolid_t *psolid, const constraint_ragdollparams_t *pConstraint )
+{
+ CPhysmesh *pMesh = m_pPhysics->GetMesh( boneIndex );
+
+ if ( !pMesh )
+ return;
+
+ if ( psolid )
+ {
+ memcpy( &pMesh->m_solid, psolid, sizeof(*psolid) );
+ }
+
+ if ( pConstraint )
+ {
+ pMesh->m_constraint = *pConstraint;
+ }
+}
+
+
+float StudioModel::Physics_GetMass( void )
+{
+ return m_pPhysics->GetMass();
+}
+
+void StudioModel::Physics_SetMass( float mass )
+{
+ m_physMass = mass;
+}
+
+
+char *StudioModel::Physics_DumpQC( void )
+{
+ return m_pPhysics->DumpQC();
+}
+
+const vertexFileHeader_t * mstudiomodel_t::CacheVertexData( void * pModelData )
+{
+ Assert( pModelData == NULL );
+ Assert( g_pActiveModel );
+
+ return g_pStudioDataCache->CacheVertexData( g_pActiveModel->GetStudioRenderHdr() );
+}
+
+
+//-----------------------------------------------------------------------------
+// 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*)handle;
+ return g_pMDLCache->GetStudioHdr( handle );
+}
+
+virtualmodel_t *studiohdr_t::GetVirtualModel( void ) const
+{
+ return g_pMDLCache->GetVirtualModel( (MDLHandle_t)virtualModel );
+}
+
+byte *studiohdr_t::GetAnimBlock( int i ) const
+{
+ return g_pMDLCache->GetAnimBlock( (MDLHandle_t)virtualModel, i );
+}
+
+int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const
+{
+ return g_pMDLCache->GetAutoplayList( (MDLHandle_t)virtualModel, pOut );
+}
+
+const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const
+{
+ return g_pMDLCache->GetStudioHdr( (MDLHandle_t)cache );
+}