diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vgui2/matsys_controls/mdlpanel.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'vgui2/matsys_controls/mdlpanel.cpp')
| -rw-r--r-- | vgui2/matsys_controls/mdlpanel.cpp | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/vgui2/matsys_controls/mdlpanel.cpp b/vgui2/matsys_controls/mdlpanel.cpp new file mode 100644 index 0000000..b99301d --- /dev/null +++ b/vgui2/matsys_controls/mdlpanel.cpp @@ -0,0 +1,902 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "matsys_controls/mdlpanel.h" +#include "materialsystem/imaterialsystem.h" +#include "materialsystem/imaterialsystemhardwareconfig.h" +#include "materialsystem/imesh.h" +#include "vgui/IVGui.h" +#include "tier1/KeyValues.h" +#include "vgui_controls/Frame.h" +#include "tier1/convar.h" +#include "tier0/dbg.h" +#include "tier1/fmtstr.h" +#include "istudiorender.h" +#include "matsys_controls/matsyscontrols.h" +#include "vcollide.h" +#include "vcollide_parse.h" +#include "bone_setup.h" +#include "vphysics_interface.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; + +DECLARE_BUILD_FACTORY( CMDLPanel ); + +static const int THUMBNAIL_SAFE_ZONE_SIZE = 512; +static const int THUMBNAIL_SAFE_ZONE_HEIGHT = 92; +static const float THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE = (float)THUMBNAIL_SAFE_ZONE_HEIGHT / THUMBNAIL_SAFE_ZONE_SIZE; + +//----------------------------------------------------------------------------- +// Purpose: Keeps a global clock to autoplay sequences to run from +// Also deals with speedScale changes +//----------------------------------------------------------------------------- +float GetAutoPlayTime( void ) +{ + static int g_prevTicks; + static float g_time; + + int ticks = Plat_MSTime(); + + // limit delta so that float time doesn't overflow + if (g_prevTicks == 0) + { + g_prevTicks = ticks; + } + + g_time += ( ticks - g_prevTicks ) / 1000.0f; + g_prevTicks = ticks; + + return g_time; +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CMDLPanel::CMDLPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName ) +{ + SetVisible( true ); + + // Used to poll input + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + // Deal with the default cubemap + ITexture *pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap", NULL, true ); + m_DefaultEnvCubemap.Init( pCubemapTexture ); + pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap.hdr", NULL, true ); + m_DefaultHDREnvCubemap.Init( pCubemapTexture ); + + SetIdentityMatrix( m_RootMDL.m_MDLToWorld ); + m_bDrawCollisionModel = false; + m_bWireFrame = false; + m_bGroundGrid = false; + m_bLockView = false; + m_bLookAtCamera = true; + m_bThumbnailSafeZone = false; + m_nNumSequenceLayers = 0; + ResetAnimationEventState( &m_EventState ); +} + +CMDLPanel::~CMDLPanel() +{ + m_aMergeMDLs.Purge(); + m_DefaultEnvCubemap.Shutdown( ); + m_DefaultHDREnvCubemap.Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Scheme settings +//----------------------------------------------------------------------------- +void CMDLPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + SetBackgroundColor( GetBgColor() ); + SetBorder( pScheme->GetBorder( "MenuBorder") ); +} + + +//----------------------------------------------------------------------------- +// Rendering options +//----------------------------------------------------------------------------- +void CMDLPanel::SetCollsionModel( bool bVisible ) +{ + m_bDrawCollisionModel = bVisible; +} + +void CMDLPanel::SetGroundGrid( bool bVisible ) +{ + m_bGroundGrid = bVisible; +} + +void CMDLPanel::SetWireFrame( bool bVisible ) +{ + m_bWireFrame = bVisible; +} + +void CMDLPanel::SetLockView( bool bLocked ) +{ + m_bLockView = bLocked; +} + +void CMDLPanel::SetLookAtCamera( bool bLookAtCamera ) +{ + m_bLookAtCamera = bLookAtCamera; +} + +void CMDLPanel::SetIgnoreDoubleClick( bool bState ) +{ + m_bIgnoreDoubleClick = bState; +} + +void CMDLPanel::SetThumbnailSafeZone( bool bVisible ) +{ + m_bThumbnailSafeZone = bVisible; +} + +//----------------------------------------------------------------------------- +// Stores the clip +//----------------------------------------------------------------------------- +void CMDLPanel::SetMDL( MDLHandle_t handle, void *pProxyData ) +{ + m_RootMDL.m_MDL.SetMDL( handle ); + m_RootMDL.m_MDL.m_pProxyData = pProxyData; + + Vector vecMins, vecMaxs; + GetMDLBoundingBox( &vecMins, &vecMaxs, handle, m_RootMDL.m_MDL.m_nSequence ); + + m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = false; + m_RootMDL.m_MDL.m_vecViewTarget.Init( 100.0f, 0.0f, vecMaxs.z ); + + m_RootMDL.m_flCycleStartTime = 0.f; + + // Set the pose parameters to the default for the mdl + SetPoseParameters( NULL, 0 ); + + // Clear any sequence layers + SetSequenceLayers( NULL, 0 ); + + ResetAnimationEventState( &m_EventState ); +} + +//----------------------------------------------------------------------------- +// An MDL was selected +//----------------------------------------------------------------------------- +void CMDLPanel::SetMDL( const char *pMDLName, void *pProxyData ) +{ + MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName ); + MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID; + if ( vgui::MDLCache()->IsErrorModel( hMDL ) ) + { + hMDL = MDLHANDLE_INVALID; + } + + SetMDL( hMDL, pProxyData ); + + // FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference. + int nRef = vgui::MDLCache()->Release( hMDLFindResult ); + (void)nRef; // Avoid unreferenced variable warning + AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMDL referenced a model that has a zero ref count." ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a model bounding box. +//----------------------------------------------------------------------------- +bool CMDLPanel::GetBoundingBox( Vector &vecBoundsMin, Vector &vecBoundsMax ) +{ + // Check to see if we have a valid model to look at. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return false; + + GetMDLBoundingBox( &vecBoundsMin, &vecBoundsMax, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a more accurate bounding sphere +//----------------------------------------------------------------------------- +bool CMDLPanel::GetBoundingSphere( Vector &vecCenter, float &flRadius ) +{ + // Check to see if we have a valid model to look at. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return false; + + Vector vecEngineCenter; + GetMDLBoundingSphere( &vecEngineCenter, &flRadius, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence ); + VectorTransform( vecEngineCenter, m_RootMDL.m_MDLToWorld, vecCenter ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos ) +{ + SetIdentityMatrix( m_RootMDL.m_MDLToWorld ); + AngleMatrix( angRot, vecPos, m_RootMDL.m_MDLToWorld ); +} + +//----------------------------------------------------------------------------- +// Sets the camera to look at the model +//----------------------------------------------------------------------------- +void CMDLPanel::LookAtMDL() +{ + // Check to see if we have a valid model to look at. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return; + + if ( m_bLockView ) + return; + + float flRadius; + Vector vecCenter; + GetBoundingSphere( vecCenter, flRadius ); + LookAt( vecCenter, flRadius ); +} + + +//----------------------------------------------------------------------------- +// FIXME: This should be moved into studiorender +//----------------------------------------------------------------------------- +static ConVar r_showenvcubemap( "r_showenvcubemap", "0", FCVAR_CHEAT ); +static ConVar r_eyegloss ( "r_eyegloss", "1", FCVAR_ARCHIVE ); // wet eyes +static ConVar r_eyemove ( "r_eyemove", "1", FCVAR_ARCHIVE ); // look around +static ConVar r_eyeshift_x ( "r_eyeshift_x", "0", FCVAR_ARCHIVE ); // eye X position +static ConVar r_eyeshift_y ( "r_eyeshift_y", "0", FCVAR_ARCHIVE ); // eye Y position +static ConVar r_eyeshift_z ( "r_eyeshift_z", "0", FCVAR_ARCHIVE ); // eye Z position +static ConVar r_eyesize ( "r_eyesize", "0", FCVAR_ARCHIVE ); // adjustment to iris textures +static ConVar mat_softwareskin( "mat_softwareskin", "0", FCVAR_CHEAT ); +static ConVar r_nohw ( "r_nohw", "0", FCVAR_CHEAT ); +static ConVar r_nosw ( "r_nosw", "0", FCVAR_CHEAT ); +static ConVar r_teeth ( "r_teeth", "1" ); +static ConVar r_drawentities ( "r_drawentities", "1", FCVAR_CHEAT ); +static ConVar r_flex ( "r_flex", "1" ); +static ConVar r_eyes ( "r_eyes", "1" ); +static ConVar r_skin ( "r_skin","0", FCVAR_CHEAT ); +static ConVar r_maxmodeldecal ( "r_maxmodeldecal", "50" ); +static ConVar r_modelwireframedecal ( "r_modelwireframedecal", "0", FCVAR_CHEAT ); +static ConVar mat_normals ( "mat_normals", "0", FCVAR_CHEAT ); +static ConVar r_eyeglintlodpixels ( "r_eyeglintlodpixels", "0", FCVAR_CHEAT ); +static ConVar r_rootlod ( "r_rootlod", "0" ); + +static StudioRenderConfig_t s_StudioRenderConfig; + +void CMDLPanel::UpdateStudioRenderConfig( void ) +{ + memset( &s_StudioRenderConfig, 0, sizeof(s_StudioRenderConfig) ); + + s_StudioRenderConfig.bEyeMove = !!r_eyemove.GetInt(); + s_StudioRenderConfig.fEyeShiftX = r_eyeshift_x.GetFloat(); + s_StudioRenderConfig.fEyeShiftY = r_eyeshift_y.GetFloat(); + s_StudioRenderConfig.fEyeShiftZ = r_eyeshift_z.GetFloat(); + s_StudioRenderConfig.fEyeSize = r_eyesize.GetFloat(); + if( mat_softwareskin.GetInt() || m_bWireFrame ) + { + s_StudioRenderConfig.bSoftwareSkin = true; + } + else + { + s_StudioRenderConfig.bSoftwareSkin = false; + } + s_StudioRenderConfig.bNoHardware = !!r_nohw.GetInt(); + s_StudioRenderConfig.bNoSoftware = !!r_nosw.GetInt(); + s_StudioRenderConfig.bTeeth = !!r_teeth.GetInt(); + s_StudioRenderConfig.drawEntities = r_drawentities.GetInt(); + s_StudioRenderConfig.bFlex = !!r_flex.GetInt(); + s_StudioRenderConfig.bEyes = !!r_eyes.GetInt(); + s_StudioRenderConfig.bWireframe = m_bWireFrame; + s_StudioRenderConfig.bDrawNormals = mat_normals.GetBool(); + s_StudioRenderConfig.skin = r_skin.GetInt(); + s_StudioRenderConfig.maxDecalsPerModel = r_maxmodeldecal.GetInt(); + s_StudioRenderConfig.bWireframeDecals = r_modelwireframedecal.GetInt() != 0; + + s_StudioRenderConfig.fullbright = false; + s_StudioRenderConfig.bSoftwareLighting = false; + + s_StudioRenderConfig.bShowEnvCubemapOnly = r_showenvcubemap.GetInt() ? true : false; + s_StudioRenderConfig.fEyeGlintPixelWidthLODThreshold = r_eyeglintlodpixels.GetFloat(); + + StudioRender()->UpdateConfig( s_StudioRenderConfig ); +} + +void CMDLPanel::DrawCollisionModel() +{ + vcollide_t *pCollide = MDLCache()->GetVCollide( m_RootMDL.m_MDL.GetMDL() ); + + if ( !pCollide || pCollide->solidCount <= 0 ) + return; + + static color32 color = {255,0,0,0}; + + IVPhysicsKeyParser *pParser = g_pPhysicsCollision->VPhysicsKeyParserCreate( pCollide->pKeyValues ); + CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache ); + + matrix3x4_t pBoneToWorld[MAXSTUDIOBONES]; + m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, MAXSTUDIOBONES, pBoneToWorld ); + + // PERFORMANCE: Just parse the script each frame. It's fast enough for tools. If you need + // this to go faster then cache off the bone index mapping in an array like HLMV does + while ( !pParser->Finished() ) + { + const char *pBlock = pParser->GetCurrentBlockName(); + if ( !stricmp( pBlock, "solid" ) ) + { + solid_t solid; + + pParser->ParseSolid( &solid, NULL ); + int boneIndex = Studio_BoneIndexByName( &studioHdr, solid.name ); + Vector *outVerts; + int vertCount = g_pPhysicsCollision->CreateDebugMesh( pCollide->solids[solid.index], &outVerts ); + + if ( vertCount ) + { + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); + // NOTE: assumes these have been set up already by the model render code + // So this is a little bit of a back door to a cache of the bones + // this code wouldn't work unless you draw the model this frame before calling + // this routine. CMDLPanel always does this, but it's worth noting. + // A better solution would be to move the ragdoll visulization into the CDmeMdl + // and either draw it there or make it queryable and query/draw here. + matrix3x4_t xform; + SetIdentityMatrix( xform ); + if ( boneIndex >= 0 ) + { + MatrixCopy( pBoneToWorld[ boneIndex ], xform ); + } + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_Wireframe ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, vertCount/3 ); + + for ( int j = 0; j < vertCount; j++ ) + { + Vector out; + VectorTransform( outVerts[j].Base(), xform, out.Base() ); + meshBuilder.Position3fv( out.Base() ); + meshBuilder.Color4ub( color.r, color.g, color.b, color.a ); + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.AdvanceVertex(); + } + meshBuilder.End(); + pMesh->Draw(); + } + + g_pPhysicsCollision->DestroyDebugMesh( vertCount, outVerts ); + } + else + { + pParser->SkipBlock(); + } + } + g_pPhysicsCollision->VPhysicsKeyParserDestroy( pParser ); +} + +void CMDLPanel::SetupRenderState( int nDisplayWidth, int nDisplayHeight ) +{ + int iWidth = nDisplayWidth; + int iHeight = nDisplayHeight; + if ( m_bThumbnailSafeZone ) + { + iWidth = THUMBNAIL_SAFE_ZONE_SIZE; + iHeight = THUMBNAIL_SAFE_ZONE_SIZE; + } + BaseClass::SetupRenderState( iWidth, iHeight ); +} + +//----------------------------------------------------------------------------- +// paint it! +//----------------------------------------------------------------------------- +void CMDLPanel::OnPaint3D() +{ + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return; + + // FIXME: Move this call into DrawModel in StudioRender + StudioRenderConfig_t oldStudioRenderConfig; + StudioRender()->GetCurrentConfig( oldStudioRenderConfig ); + + UpdateStudioRenderConfig(); + + CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() ); + if ( vgui::MaterialSystemHardwareConfig()->GetHDRType() == HDR_TYPE_NONE ) + { + ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( false ) : m_DefaultEnvCubemap; + pRenderContext->BindLocalCubemap( pMyCube ); + } + else + { + ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( true ) : m_DefaultHDREnvCubemap; + pRenderContext->BindLocalCubemap( pMyCube ); + } + + PrePaint3D( pRenderContext ); + + if ( m_bGroundGrid ) + { + DrawGrid(); + } + + if ( m_bLookAtCamera ) + { + matrix3x4_t worldToCamera; + ComputeCameraTransform( &worldToCamera ); + + Vector vecPosition; + MatrixGetColumn( worldToCamera, 3, vecPosition ); + m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = true; + m_RootMDL.m_MDL.m_vecViewTarget = vecPosition; + } + + // Draw the MDL + CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache ); + + SetupFlexWeights(); + + matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() ); + m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, studioHdr.numbones(), pBoneToWorld, m_PoseParameters, m_SequenceLayers, m_nNumSequenceLayers ); + g_pStudioRender->UnlockBoneMatrices(); + + IMaterial* pOverrideMaterial = GetOverrideMaterial( m_RootMDL.m_MDL.GetMDL() ); + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial ); + + m_RootMDL.m_MDL.Draw( m_RootMDL.m_MDLToWorld, pBoneToWorld ); + + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( NULL ); + + pOverrideMaterial = NULL; + + // Draw the merge MDLs. + matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES]; + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_bDisabled ) + continue; + + // Get the merge studio header. + studiohdr_t *pStudioHdr = g_pMDLCache->GetStudioHdr( m_aMergeMDLs[iMerge].m_MDL.GetMDL() ); + matrix3x4_t *pMergeBoneToWorld = &matMergeBoneToWorld[0]; + + // If we have a valid mesh, bonemerge it. If we have an invalid mesh we can't bonemerge because + // it'll crash trying to pull data from the missing header. + if ( pStudioHdr != NULL ) + { + CStudioHdr mergeHdr( pStudioHdr, g_pMDLCache ); + m_aMergeMDLs[iMerge].m_MDL.SetupBonesWithBoneMerge( &mergeHdr, pMergeBoneToWorld, &studioHdr, pBoneToWorld, m_RootMDL.m_MDLToWorld ); + + pOverrideMaterial = GetOverrideMaterial( m_aMergeMDLs[iMerge].m_MDL.GetMDL() ); + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial ); + + m_aMergeMDLs[iMerge].m_MDL.Draw( m_aMergeMDLs[iMerge].m_MDLToWorld, pMergeBoneToWorld ); + + if ( pOverrideMaterial != NULL ) + g_pStudioRender->ForcedMaterialOverride( NULL ); + + // Notify of model render + RenderingMergedModel( pRenderContext, &mergeHdr, m_aMergeMDLs[iMerge].m_MDL.GetMDL(), pMergeBoneToWorld ); + } + } + + RenderingRootModel( pRenderContext, &studioHdr, m_RootMDL.m_MDL.GetMDL(), pBoneToWorld ); + + PostPaint3D( pRenderContext ); + + if ( m_bDrawCollisionModel ) + { + DrawCollisionModel(); + } + + pRenderContext->Flush(); + StudioRender()->UpdateConfig( oldStudioRenderConfig ); +} + + +//----------------------------------------------------------------------------- +// Sets the current LOD +//----------------------------------------------------------------------------- +void CMDLPanel::SetLOD( int nLOD ) +{ + m_RootMDL.m_MDL.m_nLOD = nLOD; + + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + m_aMergeMDLs[iMerge].m_MDL.m_nLOD = nLOD; + } +} + + +//----------------------------------------------------------------------------- +// Sets the current sequence +//----------------------------------------------------------------------------- +void CMDLPanel::SetSequence( int nSequence, bool bResetSequence ) +{ + m_RootMDL.m_MDL.m_nSequence = nSequence; + + if ( bResetSequence ) + { + m_RootMDL.m_flCycleStartTime = GetAutoPlayTime(); + } +} + + +//----------------------------------------------------------------------------- +// Set the current pose parameters. If NULL the pose parameters will be reset +// to the default values. +//----------------------------------------------------------------------------- +void CMDLPanel::SetPoseParameters( const float *pPoseParameters, int nCount ) +{ + if ( pPoseParameters ) + { + int nParameters = MIN( MAXSTUDIOPOSEPARAM, nCount ); + for ( int iParam = 0; iParam < nParameters; ++iParam ) + { + m_PoseParameters[ iParam ] = pPoseParameters[ iParam ]; + } + } + else if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID ) + { + CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache ); + Studio_CalcDefaultPoseParameters( &studioHdr, m_PoseParameters, MAXSTUDIOPOSEPARAM ); + } +} + + +//----------------------------------------------------------------------------- +// Set a pose parameter by name +//----------------------------------------------------------------------------- +bool CMDLPanel::SetPoseParameterByName( const char *pszName, float fValue ) +{ + CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache ); + int nPoseCount = studioHdr.GetNumPoseParameters(); + + for ( int i = 0; i < nPoseCount; ++i ) + { + const mstudioposeparamdesc_t &Pose = studioHdr.pPoseParameter( i ); + if ( V_strcasecmp( pszName, Pose.pszName() ) == 0 ) + { + m_PoseParameters[ i ] = fValue; + return true; + } + } + return false; +} + + +//----------------------------------------------------------------------------- +// Set the overlay sequence layers +//----------------------------------------------------------------------------- +void CMDLPanel::SetSequenceLayers( const MDLSquenceLayer_t *pSequenceLayers, int nCount ) +{ + if ( pSequenceLayers ) + { + m_nNumSequenceLayers = MIN( MAX_SEQUENCE_LAYERS, nCount ); + for ( int iLayer = 0; iLayer < m_nNumSequenceLayers; ++iLayer ) + { + m_SequenceLayers[ iLayer ] = pSequenceLayers[ iLayer ]; + ResetAnimationEventState( &m_SequenceLayerEventState[ iLayer ] ); + } + } + else + { + m_nNumSequenceLayers = 0; + V_memset( m_SequenceLayers, 0, sizeof( m_SequenceLayers ) ); + } +} + +//----------------------------------------------------------------------------- +// Set the current skin +//----------------------------------------------------------------------------- +void CMDLPanel::SetSkin( int nSkin ) +{ + m_RootMDL.m_MDL.m_nSkin = nSkin; +} + +//----------------------------------------------------------------------------- +// called when we're ticked... +//----------------------------------------------------------------------------- +void CMDLPanel::OnTick() +{ + BaseClass::OnTick(); + if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID ) + { + m_RootMDL.m_MDL.m_flTime = ( GetAutoPlayTime() - m_RootMDL.m_flCycleStartTime ); + + DoAnimationEvents(); + } +} + +void CMDLPanel::Paint() +{ + BaseClass::Paint(); + + if ( m_bThumbnailSafeZone ) + { + int iWidth, iHeight; + GetSize( iWidth, iHeight ); + + CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() ); + + IMaterial *safezone = materials->FindMaterial( "vgui/thumbnails_safezone", TEXTURE_GROUP_VGUI, true ); + if ( safezone ) + { + safezone->IncrementReferenceCount(); + } + + int screenposx = 0; + int screenposy = 0; + LocalToScreen( screenposx, screenposy ); + + int iScaledHeight = THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE * iHeight; + int iRemappedHeight = RemapVal( iScaledHeight, 0, THUMBNAIL_SAFE_ZONE_HEIGHT, 0, iScaledHeight ); + + pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight, + 0, 0, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE ); + + screenposx = 0; + screenposy = iHeight - iRemappedHeight; + LocalToScreen( screenposx, screenposy ); + pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight, + 0, 0, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT, + THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE ); + + if ( safezone ) + { + safezone->DecrementReferenceCount(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::DoAnimationEvents() +{ + CStudioHdr studioHdr( g_pMDLCache->GetStudioHdr( m_RootMDL.m_MDL.GetMDL() ), g_pMDLCache ); + + // If we don't have any sequences, don't do anything + if ( studioHdr.GetNumSeq() < 1 ) + { + Assert( studioHdr.GetNumSeq() >= 1 ); + return; + } + + DoAnimationEvents( &studioHdr, m_RootMDL.m_MDL.m_nSequence, m_RootMDL.m_MDL.m_flTime, false, &m_EventState ); + + for ( int i = 0; i < m_nNumSequenceLayers; ++i ) + { + float flTime = m_RootMDL.m_MDL.m_flTime - m_SequenceLayers[ i ].m_flCycleBeganAt; + //Plat_DebugString( CFmtStr("Animation: time = %f, started = %f, delta = %f\n",m_RootMDL.m_MDL.m_flTime,m_SequenceLayers[ i ].m_flCycleBeganAt,flTime ) ); + DoAnimationEvents( &studioHdr, m_SequenceLayers[ i ].m_nSequenceIndex, flTime, m_SequenceLayers[ i ].m_bNoLoop, &m_SequenceLayerEventState[ i ] ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::DoAnimationEvents( CStudioHdr *pStudioHdr, int nSeqNum, float flTime, bool bNoLoop, MDLAnimEventState_t *pEventState ) +{ + if ( nSeqNum < 0 || nSeqNum >= pStudioHdr->GetNumSeq() ) + { + return; + } + + mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSeqNum ); + if ( seqdesc.numevents == 0 ) + { + return; + } + + mstudioevent_t *pevent = seqdesc.pEvent( 0 ); + + int nFrameCount = Studio_MaxFrame( pStudioHdr, nSeqNum, m_PoseParameters ); + if ( nFrameCount == 0 ) + { + nFrameCount = 1; + } + float flEventCycle = ( flTime * m_RootMDL.m_MDL.m_flPlaybackRate ) / nFrameCount; + //Plat_DebugString( CFmtStr("Event cycle: %f, playback rate: %f, frame count: %d\n", flEventCycle, m_RootMDL.m_MDL.m_flPlaybackRate, nFrameCount ) ); + if ( bNoLoop ) + { + flEventCycle = MIN(flEventCycle, 1.0f); + } + else + { + flEventCycle -= (int)(flEventCycle); + } + + if ( pEventState->m_nEventSequence != nSeqNum ) + { + pEventState->m_nEventSequence = nSeqNum; + flEventCycle = 0.0f; + pEventState->m_flPrevEventCycle = -0.01f; // back up to get 0'th frame animations + } + + if ( flEventCycle == pEventState->m_flPrevEventCycle ) + { + return; + } + + // check for looping + BOOL bLooped = (flEventCycle < pEventState->m_flPrevEventCycle); + + // This makes sure events that occur at the end of a sequence occur are + // sent before events that occur at the beginning of a sequence. + if (bLooped) + { + for (int i = 0; i < (int)seqdesc.numevents; i++) + { + if ( pevent[i].cycle <= pEventState->m_flPrevEventCycle ) + continue; + + FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() ); + } + + // Necessary to get the next loop working + pEventState->m_flPrevEventCycle = -0.01f; + } + + for (int i = 0; i < (int)seqdesc.numevents; i++) + { + if ( (pevent[i].cycle > pEventState->m_flPrevEventCycle && pevent[i].cycle <= flEventCycle) ) + { + FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() ); + } + } + + pEventState->m_flPrevEventCycle = flEventCycle; +} + +void CMDLPanel::FireEvent( const char *pszEventName, const char *pszEventOptions ) +{ + KeyValues* pKVEvent = new KeyValues( "AnimEvent" ); + pKVEvent->SetString( "name", pszEventName ); + pKVEvent->SetString( "options", pszEventOptions ); + PostActionSignal( pKVEvent ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::ResetAnimationEventState( MDLAnimEventState_t *pEventState ) +{ + pEventState->m_nEventSequence = -1; + pEventState->m_flPrevEventCycle = -0.01f; +} + +//----------------------------------------------------------------------------- +// input +//----------------------------------------------------------------------------- +void CMDLPanel::OnMouseDoublePressed( vgui::MouseCode code ) +{ + if ( m_bIgnoreDoubleClick ) + return; + + float flRadius; + Vector vecCenter; + GetBoundingSphere( vecCenter, flRadius ); + LookAt( vecCenter, flRadius ); + + BaseClass::OnMouseDoublePressed( code ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::SetMergeMDL( MDLHandle_t handle, void *pProxyData, int nSkin /*= -1 */ ) +{ + // Verify that we have a root model to merge to. + if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID ) + return; + + int iIndex = m_aMergeMDLs.AddToTail(); + if ( !m_aMergeMDLs.IsValidIndex( iIndex ) ) + return; + + m_aMergeMDLs[iIndex].m_MDL.SetMDL( handle ); + + if ( nSkin != -1 ) + { + m_aMergeMDLs[iIndex].m_MDL.m_nSkin = nSkin; + } + + m_aMergeMDLs[iIndex].m_MDL.m_nLOD = m_RootMDL.m_MDL.m_nLOD; + + m_aMergeMDLs[iIndex].m_MDL.m_pProxyData = pProxyData; + SetIdentityMatrix( m_aMergeMDLs[iIndex].m_MDLToWorld ); + + m_aMergeMDLs[iIndex].m_bDisabled = false; + + // Need to invalidate the layout so the panel will adjust is LookAt for the new model. + InvalidateLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +MDLHandle_t CMDLPanel::SetMergeMDL( const char *pMDLName, void *pProxyData, int nSkin /*= -1 */ ) +{ + MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName ); + MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID; + if ( vgui::MDLCache()->IsErrorModel( hMDL ) ) + { + hMDL = MDLHANDLE_INVALID; + } + + SetMergeMDL( hMDL, pProxyData, nSkin ); + + // FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference. + int nRef = vgui::MDLCache()->Release( hMDLFindResult ); + (void)nRef; // Avoid unreferenced variable warning + AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMergeMDL referenced a model that has a zero ref count." ); + + return hMDL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CMDLPanel::GetMergeMDLIndex( void *pProxyData ) +{ + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_MDL.m_pProxyData == pProxyData ) + return iMerge; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CMDLPanel::GetMergeMDLIndex( MDLHandle_t handle ) +{ + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle ) + return iMerge; + } + + return -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMDL *CMDLPanel::GetMergeMDL( MDLHandle_t handle ) +{ + int nMergeCount = m_aMergeMDLs.Count(); + for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge ) + { + if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle ) + return (&m_aMergeMDLs[iMerge].m_MDL); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMDLPanel::ClearMergeMDLs( void ) +{ + m_aMergeMDLs.Purge(); +} |