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.
885 lines
28 KiB
885 lines
28 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//============================================================================= |
|
|
|
#include "cbase.h" |
|
#include "basemodel_panel.h" |
|
#include "activitylist.h" |
|
#include "animation.h" |
|
#include "vgui/IInput.h" |
|
#include "matsys_controls/manipulator.h" |
|
#include "bone_setup.h" |
|
|
|
using namespace vgui; |
|
extern float GetAutoPlayTime( void ); |
|
DECLARE_BUILD_FACTORY( CBaseModelPanel ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CBaseModelPanel::CBaseModelPanel( vgui::Panel *pParent, const char *pName ) |
|
: BaseClass( pParent, pName ) |
|
, m_nActiveSequence( ACT_INVALID ) |
|
, m_flActiveSequenceDuration( 0.f ) |
|
{ |
|
m_bForcePos = false; |
|
m_bMousePressed = false; |
|
m_bAllowRotation = false; |
|
m_bAllowPitch = false; |
|
m_bAllowFullManipulation = false; |
|
m_bApplyManipulators = false; |
|
m_bForcedCameraPosition = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CBaseModelPanel::~CBaseModelPanel() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Load in the model portion of the panel's resource file. |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::ApplySettings( KeyValues *inResourceData ) |
|
{ |
|
BaseClass::ApplySettings( inResourceData ); |
|
|
|
// Set whether we render to texture |
|
m_bRenderToTexture = inResourceData->GetBool( "render_texture", true ); |
|
m_bUseParticle = inResourceData->GetBool( "use_particle", false ); |
|
|
|
// Grab and set the camera FOV. |
|
float flFOV = GetCameraFOV(); |
|
m_BMPResData.m_flFOV = inResourceData->GetInt( "fov", flFOV ); |
|
SetCameraFOV( m_BMPResData.m_flFOV ); |
|
|
|
// Do we allow rotation on these panels. |
|
m_bAllowRotation = inResourceData->GetBool( "allow_rot", false ); |
|
m_bAllowPitch = inResourceData->GetBool( "allow_pitch", false ); |
|
|
|
// Do we allow full manipulation on these panels. |
|
m_bAllowFullManipulation = inResourceData->GetBool( "allow_manip", false ); |
|
|
|
// Parse our resource file and apply all necessary updates to the MDL. |
|
for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() ) |
|
{ |
|
if ( !Q_stricmp( pData->GetName(), "model" ) ) |
|
{ |
|
ParseModelResInfo( pData ); |
|
} |
|
} |
|
|
|
SetMouseInputEnabled( m_bAllowFullManipulation || m_bAllowRotation || m_bAllowPitch ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::ParseModelResInfo( KeyValues *inResourceData ) |
|
{ |
|
m_bForcePos = ( inResourceData->GetInt( "force_pos", 0 ) == 1 ); |
|
m_BMPResData.m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" ); |
|
m_BMPResData.m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" ); |
|
m_BMPResData.m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" ); |
|
m_BMPResData.m_angModelPoseRot.Init( inResourceData->GetFloat( "angles_x", 0.0f ), inResourceData->GetFloat( "angles_y", 0.0f ), inResourceData->GetFloat( "angles_z", 0.0f ) ); |
|
m_BMPResData.m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) ); |
|
m_BMPResData.m_vecFramedOriginOffset.Init( inResourceData->GetFloat( "frame_origin_x", 110.0 ), inResourceData->GetFloat( "frame_origin_y", 5.0 ), inResourceData->GetFloat( "frame_origin_z", 5.0 ) ); |
|
m_BMPResData.m_vecViewportOffset.Init(); |
|
m_BMPResData.m_nSkin = inResourceData->GetInt( "skin", -1 ); |
|
m_BMPResData.m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 ); |
|
|
|
m_angPlayer = m_BMPResData.m_angModelPoseRot; |
|
m_vecPlayerPos = m_BMPResData.m_vecOriginOffset; |
|
|
|
for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() ) |
|
{ |
|
if ( !Q_stricmp( pData->GetName(), "animation" ) ) |
|
{ |
|
ParseModelAnimInfo( pData ); |
|
} |
|
else if ( !Q_stricmp( pData->GetName(), "attached_model" ) ) |
|
{ |
|
ParseModelAttachInfo( pData ); |
|
} |
|
} |
|
|
|
SetupModelDefaults(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::ParseModelAnimInfo( KeyValues *inResourceData ) |
|
{ |
|
if ( !inResourceData ) |
|
return; |
|
|
|
int iAnim = m_BMPResData.m_aAnimations.AddToTail(); |
|
if ( iAnim == m_BMPResData.m_aAnimations.InvalidIndex() ) |
|
return; |
|
|
|
m_BMPResData.m_aAnimations[iAnim].m_pszName = ReadAndAllocStringValue( inResourceData, "name" ); |
|
m_BMPResData.m_aAnimations[iAnim].m_pszSequence = ReadAndAllocStringValue( inResourceData, "sequence" ); |
|
m_BMPResData.m_aAnimations[iAnim].m_pszActivity = ReadAndAllocStringValue( inResourceData, "activity" ); |
|
m_BMPResData.m_aAnimations[iAnim].m_bDefault = inResourceData->GetBool( "default" ); |
|
|
|
for ( KeyValues *pAnimData = inResourceData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() ) |
|
{ |
|
if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) ) |
|
{ |
|
m_BMPResData.m_aAnimations[iAnim].m_pPoseParameters = pAnimData->MakeCopy(); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::ParseModelAttachInfo( KeyValues *inResourceData ) |
|
{ |
|
if ( !inResourceData ) |
|
return; |
|
|
|
int iAttach = m_BMPResData.m_aAttachModels.AddToTail(); |
|
if ( iAttach == m_BMPResData.m_aAttachModels.InvalidIndex() ) |
|
return; |
|
|
|
m_BMPResData.m_aAttachModels[iAttach].m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" ); |
|
m_BMPResData.m_aAttachModels[iAttach].m_nSkin = inResourceData->GetInt( "skin", -1 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::SetupModelDefaults( void ) |
|
{ |
|
SetupModelAnimDefaults(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::SetupModelAnimDefaults( void ) |
|
{ |
|
// Set the move_x parameter so the run activity works |
|
SetPoseParameterByName( "move_x", 1.0f ); |
|
|
|
// Verify that we have animations for this model. |
|
int nAnimCount = m_BMPResData.m_aAnimations.Count(); |
|
if ( nAnimCount == 0 ) |
|
return; |
|
|
|
// Find the default animation if one exists. |
|
int iIndex = FindDefaultAnim(); |
|
if ( iIndex == -1 ) |
|
return; |
|
|
|
SetModelAnim( iIndex ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CBaseModelPanel::FindDefaultAnim( void ) |
|
{ |
|
int iIndex = -1; |
|
|
|
int nAnimCount = m_BMPResData.m_aAnimations.Count(); |
|
for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim ) |
|
{ |
|
if ( m_BMPResData.m_aAnimations[iAnim].m_bDefault ) |
|
return iAnim; |
|
} |
|
|
|
return iIndex; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CBaseModelPanel::FindAnimByName( const char *pszName ) |
|
{ |
|
int iIndex = -1; |
|
if ( !pszName ) |
|
return iIndex; |
|
|
|
int nAnimCount = m_BMPResData.m_aAnimations.Count(); |
|
for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim ) |
|
{ |
|
if ( !Q_stricmp( m_BMPResData.m_aAnimations[iAnim].m_pszName, pszName ) ) |
|
return iAnim; |
|
} |
|
|
|
return iIndex; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CBaseModelPanel::FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity ) |
|
{ |
|
if ( !pStudioHdr ) |
|
return -1; |
|
|
|
for ( int iSeq = 0; iSeq < pStudioHdr->GetNumSeq(); ++iSeq ) |
|
{ |
|
mstudioseqdesc_t &seqDesc = pStudioHdr->pSeqdesc( iSeq ); |
|
if ( !V_stricmp( seqDesc.pszActivityName(), pszActivity ) ) |
|
{ |
|
return iSeq; |
|
} |
|
} |
|
|
|
return -1; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::SetModelAnim( int iAnim ) |
|
{ |
|
int nAnimCount = m_BMPResData.m_aAnimations.Count(); |
|
if ( nAnimCount == 0 || !m_BMPResData.m_aAnimations.IsValidIndex( iAnim ) ) |
|
return; |
|
|
|
MDLCACHE_CRITICAL_SECTION(); |
|
|
|
// Get the studio header of the root model. |
|
studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr(); |
|
if ( !pStudioHdr ) |
|
return; |
|
|
|
CStudioHdr studioHdr( pStudioHdr, g_pMDLCache ); |
|
|
|
// Do we have an activity or a sequence? |
|
int iSequence = ACT_INVALID; |
|
if ( m_BMPResData.m_aAnimations[iAnim].m_pszActivity && m_BMPResData.m_aAnimations[iAnim].m_pszActivity[0] ) |
|
{ |
|
iSequence = FindSequenceFromActivity( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszActivity ); |
|
} |
|
else if ( m_BMPResData.m_aAnimations[iAnim].m_pszSequence && m_BMPResData.m_aAnimations[iAnim].m_pszSequence[0] ) |
|
{ |
|
iSequence = LookupSequence( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszSequence ); |
|
} |
|
|
|
if ( iSequence != ACT_INVALID ) |
|
{ |
|
SetSequence( iSequence, true ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::SetMDL( MDLHandle_t handle, void *pProxyData ) |
|
{ |
|
MDLCACHE_CRITICAL_SECTION(); |
|
studiohdr_t *pHdr = g_pMDLCache->GetStudioHdr( handle ); |
|
|
|
if ( pHdr ) |
|
{ |
|
// SetMDL will cause the base CMdl code to set our localtoglobal indices if they aren't set. |
|
// We set them up here so that they're left alone by that code. |
|
CStudioHdr studioHdr( pHdr, g_pMDLCache ); |
|
if (studioHdr.numflexcontrollers() > 0 && studioHdr.pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1) |
|
{ |
|
for (LocalFlexController_t i = LocalFlexController_t(0); i < studioHdr.numflexcontrollers(); i++) |
|
{ |
|
int j = C_BaseFlex::AddGlobalFlexController( studioHdr.pFlexcontroller( i )->pszName() ); |
|
studioHdr.pFlexcontroller( i )->localToGlobal = j; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
handle = MDLHANDLE_INVALID; |
|
} |
|
|
|
// Clear our current sequence |
|
SetSequence( ACT_IDLE ); |
|
|
|
BaseClass::SetMDL( handle, pProxyData ); |
|
|
|
SetupModelDefaults(); |
|
|
|
// Need to invalidate the layout so the panel will adjust is LookAt for the new model. |
|
InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos ) |
|
{ |
|
BaseClass::SetModelAnglesAndPosition( angRot, vecPos ); |
|
|
|
// Cache |
|
m_vecPlayerPos = vecPos; |
|
m_angPlayer = angRot; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::SetMDL( const char *pMDLName, void *pProxyData ) |
|
{ |
|
BaseClass::SetMDL( pMDLName, pProxyData ); |
|
|
|
// Need to invalidate the layout so the panel will adjust is LookAt for the new model. |
|
// InvalidateLayout(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::PerformLayout() |
|
{ |
|
BaseClass::PerformLayout(); |
|
|
|
if ( m_bForcedCameraPosition ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_bAllowFullManipulation ) |
|
{ |
|
// Set this to true if you want to keep the current rotation when changing models or poses |
|
const bool bPreserveManipulation = false; |
|
|
|
// Need to look at the target so we can rotate around it |
|
const Vector kVecFocalPoint( 0.0f, 0.0f, 60.0f ); |
|
ResetCameraPivot(); |
|
SetCameraOffset( -(m_vecPlayerPos + kVecFocalPoint) ); |
|
SetCameraPositionAndAngles( kVecFocalPoint, vec3_angle, !bPreserveManipulation ); |
|
|
|
// We want to move the player to the origin and facing the correct way, |
|
// but don't clobber m_angPlayer and m_vecPlayerPos, so use BaseClass. |
|
BaseClass::SetModelAnglesAndPosition( m_angPlayer, vec3_origin ); |
|
|
|
// Once a manual transform has been done we want to apply it |
|
if ( m_bApplyManipulators ) |
|
{ |
|
ApplyManipulation(); |
|
} |
|
else |
|
{ |
|
SyncManipulation(); |
|
} |
|
return; |
|
} |
|
|
|
if ( m_bForcePos ) |
|
{ |
|
ResetCameraPivot(); |
|
SetCameraOffset( Vector( 0.0f, 0.0f, 0.0f ) ); |
|
SetCameraPositionAndAngles( vec3_origin, vec3_angle ); |
|
SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos ); |
|
} |
|
|
|
// Center and fill the frame with the model? |
|
if ( m_bStartFramed ) |
|
{ |
|
Vector vecBoundsMin, vecBoundsMax; |
|
if ( GetBoundingBox( vecBoundsMin, vecBoundsMax ) ) |
|
{ |
|
LookAtBounds( vecBoundsMin, vecBoundsMax ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::OnTick() |
|
{ |
|
// Cycle stuff gets handled in mdlpanel::OnTick, so we want to fix up |
|
// what our sequence is before it gets called. |
|
|
|
// Check if we have a active sequence, and if it's expired and we need |
|
// to run our default |
|
if ( m_nActiveSequence != ACT_INVALID ) |
|
{ |
|
float flElapsedTime = GetAutoPlayTime() - m_RootMDL.m_flCycleStartTime; |
|
if ( flElapsedTime >= m_flActiveSequenceDuration ) |
|
{ |
|
m_nActiveSequence = ACT_INVALID; |
|
m_flActiveSequenceDuration = 0.f; |
|
|
|
SetupModelDefaults(); |
|
} |
|
} |
|
|
|
BaseClass::OnTick(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::OnKeyCodePressed ( vgui::KeyCode code ) |
|
{ |
|
if ( m_bAllowFullManipulation ) |
|
{ |
|
BaseClass::OnKeyCodePressed( code ); |
|
return; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::OnKeyCodeReleased( vgui::KeyCode code ) |
|
{ |
|
if ( m_bAllowFullManipulation ) |
|
{ |
|
BaseClass::OnKeyCodeReleased( code ); |
|
return; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::OnMousePressed ( vgui::MouseCode code ) |
|
{ |
|
if ( m_bAllowFullManipulation ) |
|
{ |
|
BaseClass::OnMousePressed( code ); |
|
return; |
|
} |
|
|
|
if ( !m_bAllowRotation && !m_bAllowPitch ) |
|
return; |
|
|
|
RequestFocus(); |
|
|
|
EnableMouseCapture( true, code ); |
|
|
|
// Save where they clicked |
|
input()->GetCursorPosition( m_nClickStartX, m_nClickStartY ); |
|
|
|
// Warp the mouse to the center of the screen |
|
int width, height; |
|
GetSize( width, height ); |
|
int x = width / 2; |
|
int y = height / 2; |
|
|
|
int xpos = x; |
|
int ypos = y; |
|
LocalToScreen( xpos, ypos ); |
|
input()->SetCursorPos( xpos, ypos ); |
|
|
|
m_nManipStartX = xpos; |
|
m_nManipStartY = ypos; |
|
|
|
m_bMousePressed = true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::OnMouseReleased( vgui::MouseCode code ) |
|
{ |
|
if ( m_bAllowFullManipulation ) |
|
{ |
|
BaseClass::OnMouseReleased( code ); |
|
return; |
|
} |
|
|
|
if ( !m_bAllowRotation && !m_bAllowPitch ) |
|
return; |
|
|
|
EnableMouseCapture( false ); |
|
m_bMousePressed = false; |
|
|
|
// Restore the cursor to where the clicked |
|
input()->SetCursorPos( m_nClickStartX, m_nClickStartY ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::OnCursorMoved( int x, int y ) |
|
{ |
|
if ( m_bAllowFullManipulation ) |
|
{ |
|
if ( m_pCurrentManip ) |
|
{ |
|
m_bApplyManipulators = true; |
|
} |
|
BaseClass::OnCursorMoved( x, y ); |
|
return; |
|
} |
|
|
|
if ( !m_bAllowRotation && !m_bAllowPitch ) |
|
return; |
|
|
|
if ( m_bMousePressed ) |
|
{ |
|
WarpMouse( x, y ); |
|
int xpos, ypos; |
|
input()->GetCursorPos( xpos, ypos ); |
|
|
|
if ( m_bAllowRotation ) |
|
{ |
|
// Only want the x delta. |
|
float flDelta = xpos - m_nManipStartX; |
|
|
|
|
|
// Apply the delta and rotate the player. |
|
RotateYaw( flDelta ); |
|
} |
|
|
|
if ( m_bAllowPitch ) |
|
{ |
|
// Only want the y delta. |
|
float flDelta = ypos - m_nManipStartY; |
|
|
|
|
|
// Apply the delta and rotate the player. |
|
RotatePitch( flDelta ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::RotateYaw( float flDelta ) |
|
{ |
|
m_angPlayer.y += flDelta; |
|
if ( m_angPlayer.y > 360.0f ) |
|
{ |
|
m_angPlayer.y = m_angPlayer.y - 360.0f; |
|
} |
|
else if ( m_angPlayer.y < -360.0f ) |
|
{ |
|
m_angPlayer.y = m_angPlayer.y + 360.0f; |
|
} |
|
|
|
SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::RotatePitch( float flDelta ) |
|
{ |
|
m_angPlayer.x += flDelta; |
|
if ( m_angPlayer.x > m_flMaxPitch ) |
|
{ |
|
m_angPlayer.x = m_flMaxPitch; |
|
} |
|
else if ( m_angPlayer.x < -m_flMaxPitch ) |
|
{ |
|
m_angPlayer.x = -m_flMaxPitch; |
|
} |
|
|
|
SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
Vector CBaseModelPanel::GetPlayerPos() const |
|
{ |
|
return m_vecPlayerPos; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
QAngle CBaseModelPanel::GetPlayerAngles() const |
|
{ |
|
return m_angPlayer; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::PlaySequence( const char *pszSequenceName ) |
|
{ |
|
CStudioHdr studioHDR( GetStudioHdr(), g_pMDLCache ); |
|
int iSeq = ::LookupSequence( &studioHDR, pszSequenceName ); |
|
if ( iSeq != ACT_INVALID ) |
|
{ |
|
m_nActiveSequence = iSeq; |
|
m_flActiveSequenceDuration = Studio_Duration( &studioHDR, iSeq, NULL ); |
|
SetSequence( m_nActiveSequence, true ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::OnMouseWheeled( int delta ) |
|
{ |
|
if ( m_bAllowFullManipulation ) |
|
{ |
|
BaseClass::OnMouseWheeled( delta ); |
|
return; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the camera to a distance that allows the object to fill the model panel. |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax ) |
|
{ |
|
// Get the model space render bounds. |
|
Vector vecMin = vecBoundsMin; |
|
Vector vecMax = vecBoundsMax; |
|
Vector vecCenter = ( vecMax + vecMin ) * 0.5f; |
|
vecMin -= vecCenter; |
|
vecMax -= vecCenter; |
|
|
|
// Get the bounds points and transform them by the desired model panel rotation. |
|
Vector aBoundsPoints[8]; |
|
aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z ); |
|
aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z ); |
|
aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z ); |
|
aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z ); |
|
aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z ); |
|
aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z ); |
|
aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z ); |
|
aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z ); |
|
|
|
// Translated center point (offset from camera center). |
|
Vector vecTranslateCenter = -vecCenter; |
|
|
|
// Build the rotation matrix. |
|
matrix3x4_t matRotation; |
|
AngleMatrix( m_BMPResData.m_angModelPoseRot, matRotation ); |
|
|
|
Vector aXFormPoints[8]; |
|
for ( int iPoint = 0; iPoint < 8; ++iPoint ) |
|
{ |
|
VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] ); |
|
} |
|
|
|
Vector vecXFormCenter; |
|
VectorTransform( -vecTranslateCenter, matRotation, vecXFormCenter ); |
|
|
|
int w, h; |
|
GetSize( w, h ); |
|
float flW = (float)w; |
|
float flH = (float)h; |
|
|
|
float flFOVx = DEG2RAD( m_BMPResData.m_flFOV * 0.5f ); |
|
float flFOVy = CalcFovY( ( m_BMPResData.m_flFOV * 0.5f ), flW/flH ); |
|
flFOVy = DEG2RAD( flFOVy ); |
|
|
|
float flTanFOVx = tan( flFOVx ); |
|
float flTanFOVy = tan( flFOVy ); |
|
|
|
// Find the max value of x, y, or z |
|
Vector2D dist[8]; |
|
float flDist = 0.0f; |
|
for ( int iPoint = 0; iPoint < 8; ++iPoint ) |
|
{ |
|
float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx ) - aXFormPoints[iPoint].x; |
|
float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy ) - aXFormPoints[iPoint].x; |
|
dist[iPoint].x = flDistY; |
|
dist[iPoint].y = flDistZ; |
|
float flTestDist = MAX( flDistZ, flDistY ); |
|
flDist = MAX( flDist, flTestDist ); |
|
} |
|
|
|
// Screen space points. |
|
Vector2D aScreenPoints[8]; |
|
Vector aCameraPoints[8]; |
|
for ( int iPoint = 0; iPoint < 8; ++iPoint ) |
|
{ |
|
aCameraPoints[iPoint] = aXFormPoints[iPoint]; |
|
aCameraPoints[iPoint].x += flDist; |
|
|
|
aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x ); |
|
aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x ); |
|
|
|
aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW; |
|
aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH; |
|
} |
|
|
|
// Find the min/max and center of the 2D bounding box of the object. |
|
Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f ); |
|
for ( int iPoint = 0; iPoint < 8; ++iPoint ) |
|
{ |
|
vecScreenMin.x = MIN( vecScreenMin.x, aScreenPoints[iPoint].x ); |
|
vecScreenMin.y = MIN( vecScreenMin.y, aScreenPoints[iPoint].y ); |
|
vecScreenMax.x = MAX( vecScreenMax.x, aScreenPoints[iPoint].x ); |
|
vecScreenMax.y = MAX( vecScreenMax.y, aScreenPoints[iPoint].y ); |
|
} |
|
|
|
// Offset the model to the be the correct distance away from the camera. |
|
Vector vecModelPos; |
|
vecModelPos.x = flDist - vecXFormCenter.x; |
|
vecModelPos.y = -vecXFormCenter.y; |
|
vecModelPos.z = -vecXFormCenter.z; |
|
SetModelAnglesAndPosition( m_BMPResData.m_angModelPoseRot, vecModelPos ); |
|
m_vecPlayerPos = vecModelPos; |
|
|
|
// Back project to figure out the camera offset to center the model. |
|
Vector2D vecPanelCenter( ( flW * 0.5f ), ( flH * 0.5f ) ); |
|
Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f; |
|
|
|
Vector2D vecPanelCenterCamera, vecScreenCenterCamera; |
|
vecPanelCenterCamera.x = ( ( vecPanelCenter.x / flW ) * 2.0f ) - 0.5f; |
|
vecPanelCenterCamera.y = ( ( vecPanelCenter.y / flH ) * 2.0f ) - 0.5f; |
|
vecPanelCenterCamera.x *= ( flTanFOVx * flDist ); |
|
vecPanelCenterCamera.y *= ( flTanFOVy * flDist ); |
|
vecScreenCenterCamera.x = ( ( vecScreenCenter.x / flW ) * 2.0f ) - 0.5f; |
|
vecScreenCenterCamera.y = ( ( vecScreenCenter.y / flH ) * 2.0f ) - 0.5f; |
|
vecScreenCenterCamera.x *= ( flTanFOVx * flDist ); |
|
vecScreenCenterCamera.y *= ( flTanFOVy * flDist ); |
|
|
|
Vector2D vecCameraOffset( 0.0f, 0.0f ); |
|
vecCameraOffset.x = vecPanelCenterCamera.x - vecScreenCenterCamera.x; |
|
vecCameraOffset.y = vecPanelCenterCamera.y - vecScreenCenterCamera.y; |
|
|
|
// Clear the camera pivot and set position matrix. |
|
ResetCameraPivot(); |
|
if (m_bAllowRotation || m_bAllowPitch ) |
|
{ |
|
vecCameraOffset.x = 0.0f; |
|
} |
|
SetCameraOffset( Vector( 0.0f, -vecCameraOffset.x, -vecCameraOffset.y ) ); |
|
UpdateCameraTransform(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CBaseModelPanel::particle_data_t::~particle_data_t() |
|
{ |
|
if ( m_pParticleSystem ) |
|
{ |
|
delete m_pParticleSystem; |
|
m_pParticleSystem = NULL; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Allocate particle data |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int >& vecAttachments, int iDefaultBone /*= 0*/, const Vector& vecParticleOffset /*= vec3_origin*/ ) |
|
{ |
|
if ( m_pParticleSystem ) |
|
{ |
|
// Update control points which is updating the position of the particles |
|
matrix3x4_t matAttachToWorld; |
|
Vector vecPosition, vecForward, vecRight, vecUp; |
|
if ( vecAttachments.Count() ) |
|
{ |
|
for ( int i = 0; i < vecAttachments.Count(); ++i ) |
|
{ |
|
const mstudioattachment_t& attach = pStudioHdr->pAttachment( vecAttachments[i] ); |
|
MatrixMultiply( pWorldMatrix[ attach.localbone ], attach.local, matAttachToWorld ); |
|
|
|
MatrixVectors( matAttachToWorld, &vecForward, &vecRight, &vecUp ); |
|
MatrixPosition( matAttachToWorld, vecPosition ); |
|
|
|
m_pParticleSystem->SetControlPointOrientation( i, vecForward, vecRight, vecUp ); |
|
m_pParticleSystem->SetControlPoint( i, vecPosition + vecParticleOffset ); |
|
} |
|
} |
|
else |
|
{ |
|
matAttachToWorld = pWorldMatrix[iDefaultBone]; |
|
MatrixVectors( matAttachToWorld, &vecForward, &vecRight, &vecUp ); |
|
MatrixPosition( matAttachToWorld, vecPosition ); |
|
|
|
m_pParticleSystem->SetControlPointOrientation( 0, vecForward, vecRight, vecUp ); |
|
m_pParticleSystem->SetControlPoint( 0, vecPosition + vecParticleOffset ); |
|
} |
|
} |
|
|
|
m_bIsUpdateToDate = true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Allocate particle data |
|
//----------------------------------------------------------------------------- |
|
CBaseModelPanel::particle_data_t *CBaseModelPanel::CreateParticleData( const char *pszParticleName ) |
|
{ |
|
Assert( m_bUseParticle ); |
|
if ( !m_bUseParticle ) |
|
return NULL; |
|
|
|
CParticleCollection *pParticle = g_pParticleSystemMgr->CreateParticleCollection( pszParticleName ); |
|
if ( !pParticle ) |
|
return NULL; |
|
|
|
particle_data_t *pData = new particle_data_t; |
|
pData->m_bIsUpdateToDate = false; |
|
pData->m_pParticleSystem = pParticle; |
|
|
|
m_particleList.AddToTail( pData ); |
|
|
|
return pData; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: remove and delete particle data |
|
//----------------------------------------------------------------------------- |
|
bool CBaseModelPanel::SafeDeleteParticleData( particle_data_t **pData ) |
|
{ |
|
if ( !m_bUseParticle ) |
|
return false; |
|
|
|
if ( *pData ) |
|
{ |
|
FOR_EACH_VEC( m_particleList, i ) |
|
{ |
|
if ( *pData == m_particleList[i] ) |
|
{ |
|
delete *pData; |
|
*pData = NULL; |
|
m_particleList.FastRemove( i ); |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::PrePaint3D( IMatRenderContext *pRenderContext ) |
|
{ |
|
if ( !m_bUseParticle ) |
|
return; |
|
|
|
// mark all effects need to be updated |
|
FOR_EACH_VEC( m_particleList, i ) |
|
{ |
|
m_particleList[i]->m_bIsUpdateToDate = false; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CBaseModelPanel::PostPaint3D( IMatRenderContext *pRenderContext ) |
|
{ |
|
if ( !m_bUseParticle ) |
|
return; |
|
|
|
// This needs calling to reset various counters. |
|
g_pParticleSystemMgr->SetLastSimulationTime( gpGlobals->curtime ); |
|
|
|
// Render Particles |
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->PushMatrix(); |
|
pRenderContext->LoadIdentity( ); |
|
|
|
FOR_EACH_VEC( m_particleList, i ) |
|
{ |
|
if ( m_particleList[i]->m_bIsUpdateToDate ) |
|
{ |
|
m_particleList[i]->m_pParticleSystem->Simulate( gpGlobals->frametime, false ); |
|
m_particleList[i]->m_pParticleSystem->Render( pRenderContext ); |
|
m_particleList[i]->m_bIsUpdateToDate = false; |
|
} |
|
} |
|
|
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->PopMatrix(); |
|
} |
|
|
|
|