📄 ramptool.cpp
字号:
#include <stdio.h>
#include "hlfaceposer.h"
#include "RampTool.h"
#include "mdlviewer.h"
#include "choreowidgetdrawhelper.h"
#include "TimelineItem.h"
#include "expressions.h"
#include "expclass.h"
#include "choreoevent.h"
#include "StudioModel.h"
#include "choreoscene.h"
#include "choreoactor.h"
#include "choreochannel.h"
#include "ChoreoView.h"
#include "InputProperties.h"
#include "ControlPanel.h"
#include "FlexPanel.h"
#include "mxExpressionTray.h"
#include "ExpressionProperties.h"
#include "vstdlib/strtools.h"
#include "faceposer_models.h"
#include "UtlBuffer.h"
#include "FileSystem.h"
#include "cmdlib.h"
#include "scriplib.h"
#include "iscenetokenprocessor.h"
#include "choreoviewcolors.h"
#include "MatSysWin.h"
RampTool *g_pRampTool = 0;
#define TRAY_HEIGHT 20
#define TRAY_ITEM_INSET 10
#define TAG_TOP ( TRAY_HEIGHT + 12 )
#define TAG_BOTTOM ( TAG_TOP + 20 )
#define MAX_TIME_ZOOM 1000
// 10% per step
#define TIME_ZOOM_STEP 2
float SnapTime( float input, float granularity );
StudioModel *FindAssociatedModel( CChoreoScene *scene, CChoreoActor *a );
RampTool::RampTool( mxWindow *parent )
: IFacePoserToolWindow( "RampTool", "Ramp" ), mxWindow( parent, 0, 0, 0, 0 )
{
m_bSuppressLayout = false;
SetAutoProcess( true );
m_szEvent[0] = 0;
m_flScrub = 0.0f;
m_flScrubTarget = 0.0f;
m_nDragType = DRAGTYPE_NONE;
m_nClickedX = 0;
m_nClickedY = 0;
m_hPrevCursor = 0;
m_nStartX = 0;
m_nStartY = 0;
m_pLastEvent = NULL;
m_nMousePos[ 0 ] = m_nMousePos[ 1 ] = 0;
m_nMinX = 0;
m_nMaxX = 0;
m_bUseBounds = false;
m_bLayoutIsValid = false;
m_flPixelsPerSecond = 500.0f;
m_flLastDuration = 0.0f;
m_nTimeZoom = 100;
m_nScrollbarHeight = 12;
m_nLeftOffset = 0;
m_nLastHPixelsNeeded = -1;
m_pHorzScrollBar = new mxScrollbar( this, 0, 0, 18, 100, IDC_RAMPHSCROLL, mxScrollbar::Horizontal );
m_pHorzScrollBar->setVisible( false );
m_bInSetEvent = false;
m_flScrubberTimeOffset = 0.0f;
}
RampTool::~RampTool( void )
{
}
void RampTool::SetEvent( CChoreoEvent *event )
{
if ( m_bInSetEvent )
return;
m_bInSetEvent = true;
if ( event == m_pLastEvent )
{
if ( event && event->GetDuration() != m_flLastDuration )
{
m_flLastDuration = event->GetDuration();
m_nLastHPixelsNeeded = -1;
m_nLeftOffset = 0;
InvalidateLayout();
}
m_bInSetEvent = false;
return;
}
m_pLastEvent = event;
m_szEvent[ 0 ] = 0;
if ( event )
{
strcpy( m_szEvent, event->GetName() );
}
if ( event )
{
m_flLastDuration = event->GetDuration();
}
else
{
m_flLastDuration = 0.0f;
}
m_nLeftOffset = 0;
m_nLastHPixelsNeeded = -1;
InvalidateLayout();
m_bInSetEvent = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CChoreoEvent *RampTool::GetSafeEvent( void )
{
if ( !g_pChoreoView )
return NULL;
CChoreoScene *scene = g_pChoreoView->GetScene();
if ( !scene )
return NULL;
// Find event by name
for ( int i = 0; i < scene->GetNumEvents() ; i++ )
{
CChoreoEvent *e = scene->GetEvent( i );
if ( !e || !e->HasEndTime() )
continue;
if ( !stricmp( m_szEvent, e->GetName() ) )
{
return e;
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : rcHandle -
//-----------------------------------------------------------------------------
void RampTool::GetScrubHandleRect( RECT& rcHandle, float scrub, bool clipped )
{
float pixel = 0.0f;
if ( w2() > 0 )
{
pixel = GetPixelForTimeValue( scrub );
if ( clipped )
{
pixel = clamp( pixel, SCRUBBER_HANDLE_WIDTH / 2, w2() - SCRUBBER_HANDLE_WIDTH / 2 );
}
}
rcHandle.left = pixel- SCRUBBER_HANDLE_WIDTH / 2;
rcHandle.right = pixel + SCRUBBER_HANDLE_WIDTH / 2;
rcHandle.top = 2 + GetCaptionHeight();
rcHandle.bottom = rcHandle.top + SCRUBBER_HANDLE_HEIGHT;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : drawHelper -
// rcHandle -
//-----------------------------------------------------------------------------
void RampTool::DrawScrubHandle( CChoreoWidgetDrawHelper& drawHelper, RECT& rcHandle, float scrub, bool reference )
{
HBRUSH br = CreateSolidBrush( reference ? RGB( 150, 0, 0 ) : RGB( 0, 150, 100 ) );
COLORREF areaBorder = RGB( 230, 230, 220 );
drawHelper.DrawColoredLine( areaBorder,
PS_SOLID, 1, 0, rcHandle.top, w2(), rcHandle.top );
drawHelper.DrawColoredLine( areaBorder,
PS_SOLID, 1, 0, rcHandle.bottom, w2(), rcHandle.bottom );
drawHelper.DrawFilledRect( br, rcHandle );
//
char sz[ 32 ];
sprintf( sz, "%.3f", scrub );
CChoreoEvent *ev = GetSafeEvent();
if ( ev )
{
float st, ed;
st = ev->GetStartTime();
ed = ev->GetEndTime();
float dt = ed - st;
if ( dt > 0.0f )
{
sprintf( sz, "%.3f", st + scrub );
}
}
int len = drawHelper.CalcTextWidth( "Arial", 9, 500, sz );
RECT rcText = rcHandle;
int textw = rcText.right - rcText.left;
rcText.left += ( textw - len ) / 2;
drawHelper.DrawColoredText( "Arial", 9, 500, RGB( 255, 255, 255 ), rcText, sz );
DeleteObject( br );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *event -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool RampTool::IsMouseOverScrubHandle( mxEvent *event )
{
RECT rcHandle;
GetScrubHandleRect( rcHandle, m_flScrub, true );
InflateRect( &rcHandle, 2, 2 );
POINT pt;
pt.x = (short)event->x;
pt.y = (short)event->y;
if ( PtInRect( &rcHandle, pt ) )
{
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool RampTool::IsProcessing( void )
{
if ( !GetSafeEvent() )
return false;
if ( m_flScrub != m_flScrubTarget )
return true;
return false;
}
bool RampTool::IsScrubbing( void ) const
{
bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
return scrubbing;
}
void RampTool::SetScrubTime( float t )
{
m_flScrub = t;
CChoreoEvent *e = GetSafeEvent();
if ( e && e->GetDuration() )
{
float realtime = e->GetStartTime() + m_flScrub;
g_pChoreoView->SetScrubTime( realtime );
g_pChoreoView->DrawScrubHandle();
}
}
void RampTool::SetScrubTargetTime( float t )
{
m_flScrubTarget = t;
CChoreoEvent *e = GetSafeEvent();
if ( e && e->GetDuration() )
{
float realtime = e->GetStartTime() + m_flScrubTarget;
g_pChoreoView->SetScrubTargetTime( realtime );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : dt -
//-----------------------------------------------------------------------------
void RampTool::Think( float dt )
{
CChoreoEvent *event = GetSafeEvent();
if ( !event )
return;
bool scrubbing = IsScrubbing();
ScrubThink( dt, scrubbing );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : dt -
//-----------------------------------------------------------------------------
void RampTool::ScrubThink( float dt, bool scrubbing )
{
CChoreoEvent *event = GetSafeEvent();
if ( !event )
return;
if ( m_flScrubTarget == m_flScrub && !scrubbing )
return;
float d = m_flScrubTarget - m_flScrub;
int sign = d > 0.0f ? 1 : -1;
float maxmove = dt;
if ( sign > 0 )
{
if ( d < maxmove )
{
SetScrubTime( m_flScrubTarget );
}
else
{
SetScrubTime( m_flScrub + maxmove );
}
}
else
{
if ( -d < maxmove )
{
SetScrubTime( m_flScrubTarget );
}
else
{
SetScrubTime( m_flScrub - maxmove );
}
}
if ( scrubbing )
{
g_pMatSysWindow->Frame();
}
}
void RampTool::DrawScrubHandles()
{
RECT rcTray;
RECT rcHandle;
GetScrubHandleRect( rcHandle, m_flScrub, true );
rcTray = rcHandle;
rcTray.left = 0;
rcTray.right = w2();
CChoreoWidgetDrawHelper drawHelper( this, rcTray );
DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
}
void RampTool::redraw()
{
if ( !ToolCanDraw() )
return;
CChoreoWidgetDrawHelper drawHelper( this );
HandleToolRedraw( drawHelper );
RECT rc;
drawHelper.GetClientRect( rc );
CChoreoEvent *ev = GetSafeEvent();
if ( ev )
{
RECT rcText;
drawHelper.GetClientRect( rcText );
rcText.top += GetCaptionHeight()+1;
rcText.bottom = rcText.top + 13;
rcText.left += 5;
rcText.right -= 5;
OffsetRect( &rcText, 0, 12 );
int current, total;
g_pChoreoView->GetUndoLevels( current, total );
if ( total > 0 )
{
RECT rcUndo = rcText;
OffsetRect( &rcUndo, 0, 2 );
drawHelper.DrawColoredText( "Small Fonts", 8, FW_NORMAL, RGB( 0, 100, 0 ), rcUndo,
"Undo: %i/%i", current, total );
}
rcText.left += 60;
// Found it, write out description
//
RECT rcTextLine = rcText;
drawHelper.DrawColoredText( "Arial", 11, 900, RGB( 200, 0, 0 ), rcTextLine,
"Event: %s",
ev->GetName() );
RECT rcTimeLine;
drawHelper.GetClientRect( rcTimeLine );
rcTimeLine.left = 0;
rcTimeLine.right = w2();
rcTimeLine.top += ( GetCaptionHeight() + 50 );
float lefttime = GetTimeValueForMouse( 0 );
float righttime = GetTimeValueForMouse( w2() );
DrawTimeLine( drawHelper, rcTimeLine, lefttime, righttime );
OffsetRect( &rcText, 0, 28 );
rcText.left = 5;
RECT timeRect = rcText;
timeRect.right = timeRect.left + 100;
char sz[ 32 ];
Q_snprintf( sz, sizeof( sz ), "%.2f", lefttime + ev->GetStartTime() );
drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
timeRect = rcText;
Q_snprintf( sz, sizeof( sz ), "%.2f", righttime + ev->GetStartTime() );
int textW = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
timeRect.right = w2() - 10;
timeRect.left = timeRect.right - textW;
drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 0, 0, 0 ), timeRect, sz );
}
RECT rcHandle;
GetScrubHandleRect( rcHandle, m_flScrub, true );
DrawScrubHandle( drawHelper, rcHandle, m_flScrub, false );
RECT rcSamples;
GetSampleTrayRect( rcSamples );
DrawSamples( drawHelper, rcSamples );
DrawEventEnd( drawHelper );
RECT rcTags = rc;
rcTags.top = TAG_TOP + GetCaptionHeight();
rcTags.bottom = TAG_BOTTOM + GetCaptionHeight();
DrawTimingTags( drawHelper, rcTags );
RECT rcPos;
GetMouseOverPosRect( rcPos );
DrawMouseOverPos( drawHelper, rcPos );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void RampTool::ShowContextMenu( mxEvent *event, bool include_track_menus )
{
// Construct main menu
mxPopupMenu *pop = new mxPopupMenu();
int current, total;
g_pChoreoView->GetUndoLevels( current, total );
if ( total > 0 )
{
if ( current > 0 )
{
pop->add( va( "Undo %s", g_pChoreoView->GetUndoDescription() ), IDC_UNDO_RT );
}
if ( current <= total - 1 )
{
pop->add( va( "Redo %s", g_pChoreoView->GetRedoDescription() ), IDC_REDO_RT );
}
pop->addSeparator();
}
CChoreoEvent *e = GetSafeEvent();
if ( e )
{
if ( CountSelectedSamples() > 0 )
{
pop->add( va( "Delete" ), IDC_RT_DELETE );
pop->add( "Deselect all", IDC_RT_DESELECT );
}
pop->add( "Select all", IDC_RT_SELECTALL );
}
pop->add( va( "Change scale..." ), IDC_RT_CHANGESCALE );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -