Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1224 lines
27 KiB

//========= 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 );
}