|
|
//====== Copyright 1996-2008, 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"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
using namespace vgui; DECLARE_BUILD_FACTORY( CBaseModelPanel );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseModelPanel::CBaseModelPanel( vgui::Panel *pParent, const char *pName ): BaseClass( pParent, pName ) { m_bForcePos = false; m_bMousePressed = false; m_bAllowRotation = false;
vgui::SETUP_PANEL( this ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseModelPanel::~CBaseModelPanel() { }
//-----------------------------------------------------------------------------
// Purpose: Load in the model portion of the panel's resource file.
//-----------------------------------------------------------------------------
void CBaseModelPanel::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData );
// 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->GetInt( "allow_rot", 0 ) == 1 );
// 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_bAllowRotation ); }
//-----------------------------------------------------------------------------
// 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_BMPResData.m_pszModelCameraAttachment = ReadAndAllocStringValue( inResourceData, "model_camera_attachment" );
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 ); } } }
//-----------------------------------------------------------------------------
// 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->GetInt( "default", 0 ) == 1 );
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();
// if the res file wants the model to control the camera position, apply that setting
// now that the model is loaded and attachments are available.
if ( m_BMPResData.m_pszModelCameraAttachment != NULL && m_BMPResData.m_pszModelCameraAttachment[0] ) { SetCameraAttachment( m_BMPResData.m_pszModelCameraAttachment ); }
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetupModelAnimDefaults( void ) { // 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, true ); }
//-----------------------------------------------------------------------------
// 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;
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 || !pszActivity ) return -1;
for ( int iSeq = 0; iSeq < pStudioHdr->GetNumSeq(); ++iSeq ) { mstudioseqdesc_t &seqDesc = pStudioHdr->pSeqdesc( iSeq ); if ( !stricmp( seqDesc.pszActivityName(), pszActivity ) ) { return iSeq; } }
return -1; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetModelAnim( int iAnim, bool bUseSequencePlaybackFPS ) { int nAnimCount = m_BMPResData.m_aAnimations.Count(); if ( nAnimCount == 0 || !m_BMPResData.m_aAnimations.IsValidIndex( iAnim ) ) return;
// Do we have an activity or a sequence?
if ( m_BMPResData.m_aAnimations[iAnim].m_pszActivity && m_BMPResData.m_aAnimations[iAnim].m_pszActivity[0] ) { SetModelAnim( m_BMPResData.m_aAnimations[iAnim].m_pszActivity, bUseSequencePlaybackFPS ); } else if ( m_BMPResData.m_aAnimations[iAnim].m_pszSequence && m_BMPResData.m_aAnimations[iAnim].m_pszSequence[0] ) { SetModelAnim( m_BMPResData.m_aAnimations[iAnim].m_pszSequence, bUseSequencePlaybackFPS ); } }
void CBaseModelPanel::SetMdlSkinIndex( int nNewSkinIndex ) { MDLCACHE_CRITICAL_SECTION();
CMDL *pMDL = &m_RootMDL.m_MDL;
if ( !pMDL ) return;
pMDL->m_nSkin = nNewSkinIndex;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetModelAnim( const char *pszName, bool bUseSequencePlaybackFPS ) { MDLCACHE_CRITICAL_SECTION();
if ( !pszName ) return;
// Get the studio header of the root model.
studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr(); if ( !pStudioHdr ) return;
CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );
int iSequence = ACT_INVALID;
iSequence = FindSequenceFromActivity( &studioHdr, pszName );
if ( iSequence == ACT_INVALID ) { iSequence = LookupSequence( &studioHdr, pszName ); }
if ( iSequence != ACT_INVALID ) { SetSequence( iSequence, bUseSequencePlaybackFPS ); } }
void CBaseModelPanel::ClearModelAnimFollowLoop() { ClearSequenceFollowLoop(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::AddModelAnimFollowLoop( const char *pszName, bool bUseSequencePlaybackFPS ) { MDLCACHE_CRITICAL_SECTION();
if ( !pszName ) return;
// Get the studio header of the root model.
studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr(); if ( !pStudioHdr ) return;
CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );
int iSequence = ACT_INVALID;
iSequence = FindSequenceFromActivity( &studioHdr, pszName );
if ( iSequence == ACT_INVALID ) { iSequence = LookupSequence( &studioHdr, pszName ); }
if ( iSequence != ACT_INVALID ) { AddSequenceFollowLoop( iSequence, bUseSequencePlaybackFPS ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetMDL( MDLHandle_t handle, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData ) { BaseClass::SetMDL( handle, pCustomMaterialOwner, pProxyData );
SetupModelDefaults();
// Need to invalidate the layout so the panel will adjust is LookAt for the new model.
InvalidateLayout(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseModelPanel::SetMDL( const char *pMDLName, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData ) { SetSequence( 0, true );
BaseClass::SetMDL( pMDLName, pCustomMaterialOwner, 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_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::OnKeyCodePressed ( vgui::KeyCode code ) { return; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnKeyCodeReleased( vgui::KeyCode code ) { return; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnMousePressed ( vgui::MouseCode code ) { if ( !m_bAllowRotation ) return;
RequestFocus();
EnableMouseCapture( true, code );
// 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_bAllowRotation ) return;
EnableMouseCapture( false ); m_bMousePressed = false; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseModelPanel::OnCursorMoved( int x, int y ) { if ( !m_bAllowRotation ) return;
if ( m_bMousePressed ) { WarpMouse( x, y );
int xpos, ypos; input()->GetCursorPos( xpos, ypos );
// Only want the x delta.
float flDelta = xpos - m_nManipStartX;
// Apply the delta and rotate the player.
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::OnMouseWheeled( int delta ) { return; }
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
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 ); }
//-----------------------------------------------------------------------------
// 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 );
// 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( vecCenter, 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 );
// 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(); SetCameraOffset( Vector( 0.0f, -vecCameraOffset.x, -vecCameraOffset.y ) ); UpdateCameraTransform(); }
|