|
|
//========= Copyright � 1996-2005, 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"
#include "mathlib/softbodyenvironment.h"
#include "mathlib/femodeldesc.h"
extern char g_appTitle[]; Vector *StudioModel::m_AmbientLightColors; CSoftbodyEnvironment g_SoftbodyEnvironment;
#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]; mergemodelbonepair_t g_MergeModelBonePairs[ HLMV_MAX_MERGED_MODELS ]; WidgetControl *g_pWidgetControl;
WidgetControl::WidgetControl( void ) { m_WidgetType = WIDGET_ROTATE; m_WidgetState = WIDGET_STATE_NONE; m_vecValue.Init(); m_vecWidgetMouseDownCoord.Init(); m_vecWidgetDeltaCoord.Init();
const char *szWidgetModelPaths[WIDGET_NUM_WIDGET_TYPES] = { "models/tools/rotate_widget.mdl", "models/tools/translate_widget.mdl" };
for ( int i=0; i<WIDGET_NUM_WIDGET_TYPES; i++ ) { m_pWidgetModel[i] = new StudioModel; if ( m_pWidgetModel[i]->LoadModel( szWidgetModelPaths[i] ) ) m_pWidgetModel[i]->PostLoadModel( szWidgetModelPaths[i] );
} }
WidgetControl::~WidgetControl( void ) { for ( int i=0; i<WIDGET_NUM_WIDGET_TYPES; i++ ) { if ( m_pWidgetModel[i] ) { m_pWidgetModel[i]->ReleaseStudioModel(); } } }
void WidgetControl::SetStateUsingInputColor( Color inputColor ) { m_WidgetState = WIDGET_STATE_NONE;
if ( inputColor.r() > 250 && inputColor.g() < 5 && inputColor.b() < 5 ) { m_WidgetState = WIDGET_CHANGE_X; } else if ( inputColor.r() < 5 && inputColor.g() > 250 && inputColor.b() < 5 ) { m_WidgetState = WIDGET_CHANGE_Y; } else if ( inputColor.r() < 5 && inputColor.g() < 5 && inputColor.b() > 250 ) { m_WidgetState = WIDGET_CHANGE_Z; } }
void WidgetControl::WidgetMouseDown( int x, int y ) { m_WidgetState = WIDGET_STATE_NONE; m_vecWidgetMouseDownCoord.x = x; m_vecWidgetMouseDownCoord.y = y; m_vecWidgetDeltaCoord.Init(); }
void WidgetControl::WidgetMouseDrag( int x, int y ) { m_vecWidgetDeltaCoord.x = x - m_vecWidgetMouseDownCoord.x; m_vecWidgetDeltaCoord.y = y - m_vecWidgetMouseDownCoord.y; }
bool WidgetControl::HasStoredValue( void ) { return ( m_WidgetState == WIDGET_STATE_NONE && m_vecValue.Length() > 0 ); }
StudioModel *WidgetControl::GetWidgetModel( void ) { return m_pWidgetModel[m_WidgetType]; }
StudioModel::StudioModel() { m_MDLHandle = MDLHANDLE_INVALID; ClearLookTargets(); m_pBoneToWorld = (matrix3x4a_t *)MemAlloc_AllocAligned( sizeof( matrix3x4_t ) * MAXSTUDIOBONES, 16 ); }
StudioModel::~StudioModel() { MemAlloc_FreeAligned( m_pBoneToWorld ); }
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 ) { m_pStudioHdr->FreeSoftbody(); 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 );
void *pMem = MemAlloc_AllocAligned( stAllocateBlock, __alignof( StudioModel ) ); memset( pMem, 0x00, stAllocateBlock ); return pMem; }
void StudioModel::operator delete( void *pMem ) { // get the engine to free the memory
MemAlloc_FreeAligned( pMem ); }
void* StudioModel::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine ) { // call into engine to get memory
Assert( stAllocateBlock != 0 ); void *pMem = MemAlloc_AllocAlignedFileLine( stAllocateBlock, __alignof( StudioModel ), pFileName, nLine ); memset( pMem, 0x00, stAllocateBlock ); return pMem; }
void StudioModel::operator delete( void* pMem, int nBlockUse, const char *pFileName, int nLine ) { // get the engine to free the memory
MemAlloc_FreeAligned( 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) { m_pStudioHdr->FreeSoftbody(); delete m_pStudioHdr; } m_pStudioHdr = new CStudioHdr( g_pMDLCache->GetStudioHdr( m_MDLHandle ), g_pMDLCache ); m_pStudioHdr->InitSoftbody( &g_SoftbodyEnvironment);
// 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 ) { const 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; }
void StudioModel::SetSoftbodyOrientation( ) { if ( m_pStudioHdr ) { CSoftbody *pSoftbody = m_pStudioHdr->GetSoftbody(); if ( pSoftbody ) { pSoftbody->SetAbsOrigin( g_pStudioModel->m_origin, true ); pSoftbody->SetAbsAngles( g_pStudioModel->m_angles, true ); } } }
bool StudioModel::PostLoadModel( const char *modelname ) { MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
CStudioHdr *pStudioHdr = GetStudioHdr(); if (pStudioHdr == NULL) return false;
pStudioHdr->InitSoftbody( &g_SoftbodyEnvironment);
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 was loaded
//------------------------------------------------------------------------------
bool StudioModel::HasModel() { CStudioHdr *pStudioHdr = GetStudioHdr(); if ( !pStudioHdr ) return false; return true; }
//------------------------------------------------------------------------------
// Returns true if the model has at least one body part with model data, false if not.
//------------------------------------------------------------------------------
bool StudioModel::HasMesh() { 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 (iLayer < 0 || iLayer >= MAXSTUDIOANIMLAYERS) { Assert(0); return 0; }
if (iSequence < 0 || iSequence >= pStudioHdr->GetNumSeq()) iSequence = 0;
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 ) { CStudioHdr *pStudioHdr = GetStudioHdr(); if ( !pStudioHdr ) return -1;
return pStudioHdr->LookupSequence( szSequence ); }
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 || iController < 0) 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 || iParameter < 0) 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 || iParameter < 0) 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::GetBodygroup( int iGroup ) { CStudioHdr *pstudiohdr = GetStudioHdr(); if (! pstudiohdr) return 0;
if (iGroup >= pstudiohdr->numbodyparts()) return 0;
mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
if (pbodypart->nummodels <= 1) return 0;
int iCurrent = (m_bodynum / pbodypart->base) % pbodypart->nummodels;
return iCurrent; }
void StudioModel::SetBodygroupPreset( char const *szName ) { CStudioHdr *pStudioHdr = GetStudioHdr(); if (!pStudioHdr) return;
for ( int i=0; i<pStudioHdr->GetNumBodyGroupPresets(); i++ ) { const mstudiobodygrouppreset_t *pBodygroupPreset = pStudioHdr->GetBodyGroupPreset( i ); if ( !V_strcmp( szName, pBodygroupPreset->pszName() ) ) {
for ( int j=0; j<pStudioHdr->numbodyparts(); j++ ) { mstudiobodyparts_t *pbodypart = pStudioHdr->pBodypart( j );
int iMask = (pBodygroupPreset->iMask / pbodypart->base) % pbodypart->nummodels; if ( iMask == 1 ) { int iCurrent = (m_bodynum / pbodypart->base) % pbodypart->nummodels; int iValCurrent = (pBodygroupPreset->iValue / pbodypart->base) % pbodypart->nummodels;
m_bodynum = (m_bodynum - (iCurrent * pbodypart->base) + (iValCurrent * pbodypart->base)); }
} break; } } }
int StudioModel::SetBodygroup( int iGroup, int iValue ) { 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 (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 = (mstudiobone_t *)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( VoidPtrToMDLHandle( VirtualModel() ) ); }
byte *studiohdr_t::GetAnimBlock( int i, bool preloadIfMissing ) const { return g_pMDLCache->GetAnimBlock( VoidPtrToMDLHandle( VirtualModel() ), i, preloadIfMissing ); }
bool studiohdr_t::hasAnimBlockBeenPreloaded( int i ) const { return g_pMDLCache->HasAnimBlockBeenPreloaded( VoidPtrToMDLHandle( VirtualModel() ), i ); }
int studiohdr_t::GetAutoplayList( unsigned short **pOut ) const { return g_pMDLCache->GetAutoplayList( VoidPtrToMDLHandle( VirtualModel() ), pOut ); }
const studiohdr_t *virtualgroup_t::GetStudioHdr( void ) const { return g_pMDLCache->GetStudioHdr( VoidPtrToMDLHandle( cache ) ); }
|