|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "movieobjects/dmechannel.h"
#include "movieobjects/dmelog.h"
#include "movieobjects/dmeclip.h"
#include "datamodel/dmelementfactoryhelper.h"
#include "datamodel/dmehandle.h"
#include "datamodel/dmattribute.h"
#include "tier0/vprof.h"
#include "tier1/KeyValues.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//-----------------------------------------------------------------------------
//
// CDmeChannelRecordingMgr
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Globals
//-----------------------------------------------------------------------------
static CDmeChannelRecordingMgr s_ChannelRecordingMgr; CDmeChannelRecordingMgr *g_pChannelRecordingMgr = &s_ChannelRecordingMgr;
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CDmeChannelRecordingMgr::CDmeChannelRecordingMgr() { m_bActive = false; m_bSavedUndoState = false; m_bUseTimeSelection = false; m_nRevealType = PROCEDURAL_PRESET_NOT; m_pRevealTarget = NULL; }
//-----------------------------------------------------------------------------
// Activates, deactivates layer recording.
//-----------------------------------------------------------------------------
void CDmeChannelRecordingMgr::StartLayerRecording( const char *pUndoRedoDesc, const DmeLog_TimeSelection_t *pTimeSelection ) { g_pDataModel->StartUndo( pUndoRedoDesc, pUndoRedoDesc ); m_bSavedUndoState = g_pDataModel->IsUndoEnabled(); g_pDataModel->SetUndoEnabled( false );
Assert( !m_bActive ); Assert( m_LayerChannels.Count() == 0 ); m_LayerChannels.Purge(); m_bActive = true; m_bUseTimeSelection = ( pTimeSelection != NULL ); if ( pTimeSelection ) { m_TimeSelection = *pTimeSelection; } else { // Slam to default value
m_TimeSelection = DmeLog_TimeSelection_t(); } m_TimeSelection.ResetTimeAdvancing(); }
void CDmeChannelRecordingMgr::FinishLayerRecording( float flThreshhold, bool bFlattenLayers /*=true*/ ) { Assert( m_bActive );
RemoveAllChannelsFromRecordingLayer(); m_bUseTimeSelection = false; m_TimeSelection.ResetTimeAdvancing();
g_pDataModel->SetUndoEnabled( m_bSavedUndoState ); if ( bFlattenLayers ) { FlattenLayers( flThreshhold ); } g_pDataModel->FinishUndo();
m_bActive = false; m_LayerChannels.Purge(); m_nRevealType = PROCEDURAL_PRESET_NOT; m_pRevealTarget = NULL; m_PasteTarget.RemoveAll(); }
//-----------------------------------------------------------------------------
// Adds a channel to the recording layer
//-----------------------------------------------------------------------------
void CDmeChannelRecordingMgr::AddChannelToRecordingLayer( CDmeChannel *pChannel, CDmeClip *pRoot, CDmeClip *pShot ) { Assert( pChannel->m_nRecordLayerIndex == -1 );
CDmeLog *pLog = pChannel->GetLog(); if ( !pLog ) return;
int nRecordLayerIndex = m_LayerChannels.AddToTail(); LayerChannelInfo_t& info = m_LayerChannels[nRecordLayerIndex]; info.m_Channel = pChannel; if ( pRoot ) { if ( !pChannel->BuildClipStack( &info.m_ClipStack, pRoot, pShot ) ) { m_LayerChannels.Remove( nRecordLayerIndex ); return; } }
pChannel->m_nRecordLayerIndex = nRecordLayerIndex;
// This operation is undoable
CEnableUndoScopeGuard guard; pLog->AddNewLayer(); pChannel->SetMode( CM_RECORD ); }
//-----------------------------------------------------------------------------
// Removes all channels from the recording layer
//-----------------------------------------------------------------------------
void CDmeChannelRecordingMgr::RemoveAllChannelsFromRecordingLayer( ) { int c = m_LayerChannels.Count(); for ( int i = 0 ; i < c; ++i ) { CDmeChannel *pChannel = m_LayerChannels[ i ].m_Channel.Get(); if ( !pChannel ) continue;
CDmeLog *pLog = pChannel->GetLog(); if ( pLog && IsUsingTimeSelection() ) { // Computes local times for the time selection
DmeLog_TimeSelection_t timeSelection; GetLocalTimeSelection( timeSelection, pChannel->m_nRecordLayerIndex ); pLog->FinishTimeSelection( pChannel->GetCurrentTime(), timeSelection ); } pChannel->m_nRecordLayerIndex = -1; pChannel->SetMode( CM_PLAY ); } }
//-----------------------------------------------------------------------------
// Flattens recorded layers into the base layer
//-----------------------------------------------------------------------------
void CDmeChannelRecordingMgr::FlattenLayers( float flThreshhold ) { int nFlags = 0; if ( IsUsingDetachedTimeSelection() && IsTimeAdvancing() ) { nFlags |= CDmeLog::FLATTEN_NODISCONTINUITY_FIXUP; }
int c = m_LayerChannels.Count(); for ( int i = 0 ; i < c; ++i ) { CDmeChannel *pChannel = m_LayerChannels[ i ].m_Channel.Get(); if ( !pChannel ) continue;
CDmeLog *pLog = pChannel->GetLog(); Assert( pLog ); if ( !pLog ) continue;
pLog->FlattenLayers( flThreshhold, nFlags ); } }
//-----------------------------------------------------------------------------
// Used to iterate over all channels currently being recorded
//-----------------------------------------------------------------------------
int CDmeChannelRecordingMgr::GetLayerRecordingChannelCount() { return m_LayerChannels.Count(); }
CDmeChannel* CDmeChannelRecordingMgr::GetLayerRecordingChannel( int nIndex ) { return m_LayerChannels[nIndex].m_Channel.Get(); }
//-----------------------------------------------------------------------------
// Computes time selection info in log time for a particular recorded channel
//-----------------------------------------------------------------------------
void CDmeChannelRecordingMgr::GetLocalTimeSelection( DmeLog_TimeSelection_t& selection, int nIndex ) { Assert( m_bUseTimeSelection ); LayerChannelInfo_t& info = m_LayerChannels[nIndex]; selection = m_TimeSelection; for ( int i = 0; i < TS_TIME_COUNT; ++i ) { selection.m_nTimes[i] = CDmeClip::ToChildMediaTime( info.m_ClipStack, selection.m_nTimes[i], false ); } selection.m_pPresetValue = info.m_pPresetValue; }
//-----------------------------------------------------------------------------
// Methods which control various aspects of recording
//-----------------------------------------------------------------------------
void CDmeChannelRecordingMgr::UpdateTimeAdvancing( bool bPaused, DmeTime_t tCurTime ) { Assert( m_bActive && m_bUseTimeSelection ); if ( !bPaused && !m_TimeSelection.IsTimeAdvancing() ) { m_TimeSelection.StartTimeAdvancing();
// blow away logs after curtime
int nCount = m_LayerChannels.Count(); for ( int i = 0; i < nCount; ++i ) { LayerChannelInfo_t& info = m_LayerChannels[i]; DmeTime_t t = CDmeClip::ToChildMediaTime( info.m_ClipStack, tCurTime, false ); info.m_Channel->GetLog()->RemoveKeys( t, DMETIME_MAXTIME ); } } }
void CDmeChannelRecordingMgr::UpdateRecordingTimeSelectionTimes( const DmeLog_TimeSelection_t& timeSelection ) { Assert( m_bActive ); for ( int i = 0; i < TS_TIME_COUNT; ++i ) { m_TimeSelection.m_nTimes[i] = timeSelection.m_nTimes[i]; } m_TimeSelection.m_nResampleInterval = timeSelection.m_nResampleInterval; }
void CDmeChannelRecordingMgr::SetIntensityOnAllLayers( float flIntensity ) { m_TimeSelection.m_flIntensity = flIntensity; }
void CDmeChannelRecordingMgr::SetRecordingMode( RecordingMode_t mode ) { m_TimeSelection.SetRecordingMode( mode ); }
void CDmeChannelRecordingMgr::SetPresetValue( CDmeChannel* pChannel, CDmAttribute *pPresetValue ) { Assert( pChannel->m_nRecordLayerIndex != -1 ); m_LayerChannels[ pChannel->m_nRecordLayerIndex ].m_pPresetValue = pPresetValue; }
//-----------------------------------------------------------------------------
// Methods to query aspects of recording
//-----------------------------------------------------------------------------
bool CDmeChannelRecordingMgr::IsUsingDetachedTimeSelection() const { Assert( m_bActive ); return !m_TimeSelection.m_bAttachedMode; }
bool CDmeChannelRecordingMgr::IsTimeAdvancing() const { Assert( m_bActive ); return m_TimeSelection.IsTimeAdvancing(); }
bool CDmeChannelRecordingMgr::IsUsingTimeSelection() const { return m_bUseTimeSelection; }
bool CDmeChannelRecordingMgr::ShouldRecordUsingTimeSelection() const { return m_bUseTimeSelection && m_bActive; }
void CDmeChannelRecordingMgr::SetProceduralTarget( int nProceduralMode, const CDmAttribute *pTarget ) { m_nRevealType = nProceduralMode; m_pRevealTarget = pTarget; m_PasteTarget.RemoveAll(); }
void CDmeChannelRecordingMgr::SetProceduralTarget( int nProceduralMode, const CUtlVector< KeyValues * >& list ) { m_nRevealType = nProceduralMode; m_pRevealTarget = NULL; m_PasteTarget.RemoveAll(); for ( int i = 0; i < list.Count(); ++i ) { m_PasteTarget.AddToTail( list[ i ] ); } }
int CDmeChannelRecordingMgr::GetProceduralType() const { return m_nRevealType; }
const CDmAttribute *CDmeChannelRecordingMgr::GetProceduralTarget() const { Assert( m_pRevealTarget ); return m_pRevealTarget; }
const CUtlVector< KeyValues * > &CDmeChannelRecordingMgr::GetPasteTarget() const { return m_PasteTarget; }
//-----------------------------------------------------------------------------
// Expose this class to the scene database
//-----------------------------------------------------------------------------
IMPLEMENT_ELEMENT_FACTORY( DmeChannel, CDmeChannel );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CDmeChannel::OnConstruction() { m_nRecordLayerIndex = -1; m_nNextCurveType = CURVE_DEFAULT; m_tCurrentTime = DMETIME_INVALID; m_tPreviousTime = DMETIME_INVALID; m_timeOutsideTimeframe = DMETIME_INVALID;
m_fromElement .Init( this, "fromElement", FATTRIB_HAS_CALLBACK | FATTRIB_NEVERCOPY ); m_fromAttribute .Init( this, "fromAttribute", FATTRIB_TOPOLOGICAL | FATTRIB_HAS_CALLBACK ); m_fromIndex .Init( this, "fromIndex", FATTRIB_TOPOLOGICAL ); m_toElement .Init( this, "toElement", FATTRIB_HAS_CALLBACK | FATTRIB_NEVERCOPY ); m_toAttribute .Init( this, "toAttribute", FATTRIB_TOPOLOGICAL | FATTRIB_HAS_CALLBACK ); m_toIndex .Init( this, "toIndex", FATTRIB_TOPOLOGICAL ); m_mode .InitAndSet( this, "mode", (int)CM_PASS ); m_log .Init( this, "log" ); m_FromAttributeHandle = DMATTRIBUTE_HANDLE_INVALID; m_ToAttributeHandle = DMATTRIBUTE_HANDLE_INVALID; }
void CDmeChannel::OnDestruction() { }
int CDmeChannel::GetFromArrayIndex() const { return m_fromIndex; }
int CDmeChannel::GetToArrayIndex() const { return m_toIndex; }
void CDmeChannel::Play() { CDmAttribute *pToAttr = GetToAttribute();
if ( pToAttr == NULL ) return;
CDmeLog *pLog = GetLog(); if ( !pLog ) return;
DmeTime_t time = GetCurrentTime();
DmeTime_t t0 = pLog->GetBeginTime(); DmeTime_t tn = pLog->GetEndTime();
PlayMode_t pmode = PM_HOLD; switch ( pmode ) { case PM_HOLD: time = clamp( time, t0, tn ); break;
case PM_LOOP: if ( tn == t0 ) { time = t0; } else { time -= t0; time = time % ( tn - t0 ); time += t0; } break; }
// We might not want to do it this way, but this makes empty logs not get in the way if there is a valid pFromAttr
#if 1
if ( pLog->IsEmpty() && !pLog->HasDefaultValue() && GetFromAttribute() != NULL ) { Pass(); return; } #endif
pLog->GetValue( time, pToAttr, m_toIndex.Get() ); }
void CDmeChannel::Pass() { CDmAttribute *pFromAttr = GetFromAttribute(); CDmAttribute *pToAttr = GetToAttribute(); if ( !pFromAttr || !pToAttr ) return;
if ( pFromAttr == pToAttr ) return;
DmAttributeType_t type = pFromAttr->GetType(); const void *pValue = NULL; if ( IsArrayType( type ) ) { CDmrGenericArray array( pFromAttr ); pValue = array.GetUntyped( m_fromIndex.Get() ); type = ArrayTypeToValueType( type ); } else { pValue = pFromAttr->GetValueUntyped(); }
if ( IsArrayType( pToAttr->GetType() ) ) { CDmrGenericArray array( pToAttr ); array.Set( m_toIndex.Get(), type, pValue ); } else { pToAttr->SetValue( type, pValue ); } }
//-----------------------------------------------------------------------------
// IsDirty - ie needs to operate
//-----------------------------------------------------------------------------
bool CDmeChannel::IsDirty() { if ( BaseClass::IsDirty() ) return true;
switch( GetMode() ) { case CM_PLAY: return true;
case CM_RECORD: if ( m_nRecordLayerIndex != -1 ) return true;
// NOTE: Fall through!
case CM_PASS: { CDmAttribute *pFromAttr = GetFromAttribute(); if ( pFromAttr && pFromAttr->IsFlagSet( FATTRIB_OPERATOR_DIRTY ) ) return true; } break;
default: break; } return false; }
void CDmeChannel::Operate() { VPROF( "CDmeChannel::Operate" );
switch ( GetMode() ) { case CM_OFF: return;
case CM_PLAY: Play(); return;
case CM_RECORD: Record(); return;
case CM_PASS: Pass(); return; } }
void CDmeChannel::GetInputAttributes( CUtlVector< CDmAttribute * > &attrs ) { ChannelMode_t mode = GetMode(); if ( mode == CM_OFF || mode == CM_PLAY ) return; // off and play ignore inputs
CDmAttribute *pAttr = GetFromAttribute(); if ( pAttr != NULL ) { attrs.AddToTail( pAttr ); } }
void CDmeChannel::GetOutputAttributes( CUtlVector< CDmAttribute * > &attrs ) { ChannelMode_t mode = GetMode(); if ( mode == CM_OFF ) return; // off ignores inputs
if ( mode == CM_RECORD || mode == CM_PASS ) { if ( GetFromAttribute() == GetToAttribute() ) return; // record/pass from and to the same attribute doesn't write anything
}
CDmAttribute *pAttr = GetToAttribute(); if ( pAttr != NULL ) { attrs.AddToTail( pAttr ); } }
//-----------------------------------------------------------------------------
// accessors
//-----------------------------------------------------------------------------
CDmElement *CDmeChannel::GetFromElement() const { return m_fromElement; }
CDmElement *CDmeChannel::GetToElement() const { return m_toElement; }
void CDmeChannel::SetLog( CDmeLog *pLog ) { m_log = pLog; }
CDmeLog *CDmeChannel::CreateLog( DmAttributeType_t type ) { CDmeLog *log = CDmeLog::CreateLog( type, GetFileId() ); m_log.Set( log ); return log; }
// HACK: This is an evil hack since the element and attribute change sequentially, but they really need to change in lockstep or else you're looking
// up an attribute from some other element or vice versa.
void CDmeChannel::SetInput( CDmElement* pElement, const char* pAttribute, int index ) { m_fromElement.Set( pElement ); m_fromAttribute.Set( pAttribute ); m_fromIndex.Set( index ); SetupFromAttribute(); }
void CDmeChannel::SetOutput( CDmElement* pElement, const char* pAttribute, int index ) { m_toElement.Set( pElement ); m_toAttribute.Set( pAttribute ); m_toIndex.Set( index ); SetupToAttribute(); }
void CDmeChannel::SetInput( CDmAttribute *pAttribute, int index ) { if ( pAttribute ) { SetInput( pAttribute->GetOwner(), pAttribute->GetName(), index ); } else { SetInput( NULL, "", index ); } }
void CDmeChannel::SetOutput( CDmAttribute *pAttribute, int index ) { if ( pAttribute ) { SetOutput( pAttribute->GetOwner(), pAttribute->GetName(), index ); } else { SetOutput( NULL, "", index ); } }
ChannelMode_t CDmeChannel::GetMode() { return static_cast< ChannelMode_t >( m_mode.Get() ); }
void CDmeChannel::SetMode( ChannelMode_t mode ) { if ( mode != m_mode ) { m_mode.Set( static_cast< int >( mode ) ); m_tPreviousTime = DMETIME_INVALID; } }
void CDmeChannel::ClearLog() { GetLog()->ClearKeys(); }
CDmeLog *CDmeChannel::GetLog() { if ( !m_log.GetElement() && ( m_FromAttributeHandle == DMATTRIBUTE_HANDLE_INVALID ) ) { // NOTE: This will generate a new log based on the from attribute
SetupFromAttribute(); } return m_log.GetElement(); }
//-----------------------------------------------------------------------------
// Used to cache off handles to attributes
//-----------------------------------------------------------------------------
CDmAttribute *CDmeChannel::SetupFromAttribute() { m_FromAttributeHandle = DMATTRIBUTE_HANDLE_INVALID;
CDmElement *pObject = m_fromElement.GetElement(); const char *pName = m_fromAttribute.Get(); if ( pObject == NULL || pName == NULL || !pName[0] ) return NULL;
CDmAttribute *pAttr = pObject->GetAttribute( pName ); if ( !pAttr ) return NULL;
m_FromAttributeHandle = pAttr->GetHandle();
DmAttributeType_t fromType = pAttr->GetType(); if ( IsArrayType( fromType ) ) { fromType = ArrayTypeToValueType( fromType ); }
CDmeLog *pLog = m_log.GetElement(); if ( pLog == NULL ) { CreateLog( fromType ); return pAttr; }
DmAttributeType_t logType = pLog->GetDataType(); if ( IsArrayType( logType ) ) { logType = ArrayTypeToValueType( logType ); }
if ( logType != fromType ) { // NOTE: This will release the current log
CreateLog( fromType ); }
return pAttr; }
CDmAttribute *CDmeChannel::SetupToAttribute() { m_ToAttributeHandle = DMATTRIBUTE_HANDLE_INVALID;
CDmElement *pObject = m_toElement.GetElement(); const char *pName = m_toAttribute.Get(); if ( pObject == NULL || pName == NULL || !pName[0] ) return NULL;
CDmAttribute *pAttr = pObject->GetAttribute( pName ); if ( !pAttr ) return NULL;
m_ToAttributeHandle = pAttr->GetHandle(); return pAttr; }
//-----------------------------------------------------------------------------
// This function gets called whenever an attribute changes
//-----------------------------------------------------------------------------
void CDmeChannel::OnAttributeChanged( CDmAttribute *pAttribute ) { if ( ( pAttribute == m_fromElement .GetAttribute() ) || ( pAttribute == m_fromAttribute.GetAttribute() ) ) { // NOTE: This will force a recache of the attribute handle
m_FromAttributeHandle = DMATTRIBUTE_HANDLE_INVALID; return; }
if ( ( pAttribute == m_toElement .GetAttribute() ) || ( pAttribute == m_toAttribute.GetAttribute() ) ) { m_ToAttributeHandle = DMATTRIBUTE_HANDLE_INVALID; return; }
BaseClass::OnAttributeChanged( pAttribute ); }
DmeTime_t CDmeChannel::GetCurrentTime() const { return m_tCurrentTime; }
//-----------------------------------------------------------------------------
// Simple version. Only works if multiple active channels clips
// do not reference the same channels
//-----------------------------------------------------------------------------
void CDmeChannel::SetCurrentTime( DmeTime_t time ) { m_tPreviousTime = m_tCurrentTime; m_tCurrentTime = time; m_timeOutsideTimeframe = DMETIME_ZERO; }
//-----------------------------------------------------------------------------
// SetCurrentTime sets the current time on the clip,
// choosing the time closest to (and after) a timeframe if multiple sets in a frame
//-----------------------------------------------------------------------------
void CDmeChannel::SetCurrentTime( DmeTime_t time, DmeTime_t start, DmeTime_t end ) { m_tPreviousTime = m_tCurrentTime;
DmeTime_t dt( 0 ); if ( time < start ) { dt = time - start; time = start; } else if ( time >= end ) { dt = time - end; time = end; } DmeTime_t totf = m_timeOutsideTimeframe;
const DmeTime_t t0( 0 ); if ( ( dt < t0 && totf < t0 && dt < totf ) || // both prior to clip, old totf closer
( dt < t0 && totf >= t0 ) || // new dt prior to clip, old totf in or after
( dt >= t0 && totf >= t0 && dt > totf ) ) // both after clip, old totf closer
return; // if old todt is a better match, don't update channel time
m_tCurrentTime = time; m_timeOutsideTimeframe = dt; }
//-----------------------------------------------------------------------------
// ClearTimeMetric marks m_timeOutsideTimeframe invalid (-inf is the worst possible match)
//-----------------------------------------------------------------------------
void CDmeChannel::ClearTimeMetric() { m_timeOutsideTimeframe = DmeTime_t::MinTime(); }
void CDmeChannel::SetChannelToPlayToSelf( const char *outputAttributeName, float defaultValue, bool force /*= false*/ ) { if ( !HasAttribute( outputAttributeName ) ) { AddAttribute( outputAttributeName, AT_FLOAT ); }
CDmeTypedLog< bool > *log = static_cast< CDmeTypedLog< bool >* >( GetLog() ); // Usually we won't put it into playback if it's empty, we'll just read the default value continously
if ( force || ( log && !log->IsEmpty() && !log->HasDefaultValue() ) ) { SetMode( CM_PLAY ); SetOutput( this, outputAttributeName ); } SetValue( outputAttributeName, defaultValue ); }
void CDmeChannel::SetNextKeyCurveType( int nCurveType ) { m_nNextCurveType = nCurveType; }
CDmeLogLayer *FindLayerInSnapshot( const CDmrElementArray<CDmElement>& snapshotArray, CDmeLog *origLog ) { if ( !snapshotArray.IsValid() ) return NULL;
int c = snapshotArray.Count(); for ( int i = 0; i < c; ++i ) { CDmeLogLayer *layer = CastElement< CDmeLogLayer >( snapshotArray[ i ] ); if ( !layer ) continue;
CDmeLog *pLog = layer->GetValueElement< CDmeLog >( "origLog" ); if ( !pLog ) { Assert( 0 ); continue; }
if ( pLog == origLog ) return layer; }
return NULL; }
KeyValues *FindLayerInPasteData( const CUtlVector< KeyValues * > &list, CDmeLog *log ) { int c = list.Count(); for ( int i = 0; i < c; ++i ) { CDisableUndoScopeGuard noundo;
KeyValues *kv = list[ i ]; Assert( kv );
if ( Q_stricmp( kv->GetName(), "ControlLayers" ) ) continue;
LayerSelectionData_t *data = reinterpret_cast< LayerSelectionData_t * >( kv->GetPtr( "LayerData" ) ); if ( !data ) continue;
CDmeChannel *ch = data->m_hChannel; if ( !ch ) continue;
CDmeLog *chLog = ch->GetLog(); if ( chLog == log ) return kv; }
return NULL; }
static int FindSpanningLayerAndSetIntensity( DmeLog_TimeSelection_t &ts, LayerSelectionData_t *data ) { Assert( data->m_vecData.Count() >= 2 );
float frac = ts.m_flIntensity; int i = 0; for ( ; i < data->m_vecData.Count() - 1; ++i ) { LayerSelectionData_t::DataLayer_t *current = &data->m_vecData[ i ]; LayerSelectionData_t::DataLayer_t *next = &data->m_vecData[ i + 1 ];
if ( frac >= current->m_flStartFraction && frac <= next->m_flStartFraction ) { frac = RemapVal( frac, current->m_flStartFraction, next->m_flStartFraction, 0.0f, 1.0f ); ts.m_flIntensity = frac; break; } }
return i; }
void CDmeChannel::Record() { VPROF( "CDmeChannel::Record" );
CDmAttribute *pFromAttr = GetFromAttribute(); if ( pFromAttr == NULL ) return; // or clear out the log?
CDmeLog *pLog = GetLog(); DmeTime_t time = GetCurrentTime(); if ( m_tPreviousTime == DMETIME_INVALID ) { m_tPreviousTime = time; }
if ( g_pChannelRecordingMgr->ShouldRecordUsingTimeSelection() ) { Assert( m_nRecordLayerIndex != -1 );
// Computes local times for the time selection
DmeLog_TimeSelection_t timeSelection; g_pChannelRecordingMgr->GetLocalTimeSelection( timeSelection, m_nRecordLayerIndex );
int nType = g_pChannelRecordingMgr->GetProceduralType(); switch ( nType ) { default: case PROCEDURAL_PRESET_NOT: { pLog->StampKeyAtHead( time, m_tPreviousTime, timeSelection, pFromAttr, m_fromIndex.Get() ); } break; case PROCEDURAL_PRESET_REVEAL: { // Find the matching layer in the "target" data array
const CDmrElementArray<CDmElement> snapshotArray = const_cast< CDmAttribute * >( g_pChannelRecordingMgr->GetProceduralTarget() ); CDmeLogLayer *snapshotLayer = FindLayerInSnapshot( snapshotArray, pLog ); if ( snapshotLayer ) { Assert( pLog ); pLog->RevealUsingTimeSelection( timeSelection, snapshotLayer ); } } break; case PROCEDURAL_PRESET_JITTER: case PROCEDURAL_PRESET_SMOOTH: case PROCEDURAL_PRESET_SHARPEN: case PROCEDURAL_PRESET_SOFTEN: case PROCEDURAL_PRESET_STAGGER: case PROCEDURAL_PRESET_PASTE: { const CUtlVector< KeyValues * > &pasteTarget = g_pChannelRecordingMgr->GetPasteTarget(); KeyValues *layer = FindLayerInPasteData( pasteTarget, pLog ); if ( layer ) { LayerSelectionData_t *data = reinterpret_cast< LayerSelectionData_t * >( layer->GetPtr( "LayerData" ) ); Assert( data );
int iSourceLayer = FindSpanningLayerAndSetIntensity( timeSelection, data );
CDmeLogLayer *sourceLayer = data->m_vecData[ iSourceLayer ].m_hData.Get(); CDmeLogLayer *targetLayer = data->m_vecData[ iSourceLayer + 1 ].m_hData.Get(); if ( sourceLayer && sourceLayer->GetKeyCount() > 0 && targetLayer && targetLayer->GetKeyCount() > 0 && sourceLayer->GetKeyCount() == targetLayer->GetKeyCount() ) { Assert( pLog->GetNumLayers() >= 2 ); CDmeLogLayer *outputLayer = pLog->GetLayer( pLog->GetTopmostLayer() ); if ( nType == PROCEDURAL_PRESET_STAGGER ) { pLog->BlendTimesUsingTimeSelection( sourceLayer, targetLayer, outputLayer, timeSelection, data->m_tStartOffset ); } else { pLog->BlendLayersUsingTimeSelection( sourceLayer, targetLayer, outputLayer, timeSelection, false, data->m_tStartOffset ); } } } } break; } } else { if ( m_tPreviousTime != time ) { pLog->SetDuplicateKeyAtTime( m_tPreviousTime ); } pLog->SetKey( time, pFromAttr, m_fromIndex.Get(), m_nNextCurveType ); m_nNextCurveType = CURVE_DEFAULT; }
// Output the data that's in the log
Play(); }
//-----------------------------------------------------------------------------
// Builds a clip stack that passes through root + shot
// Returns true if it succeeded
//-----------------------------------------------------------------------------
bool CDmeChannel::BuildClipStack( DmeClipStack_t *pClipStack, CDmeClip *pRoot, CDmeClip *pShot ) { DmAttributeReferenceIterator_t it; for ( it = g_pDataModel->FirstAttributeReferencingElement( GetHandle() ); it != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID; it = g_pDataModel->NextAttributeReferencingElement( it ) ) { CDmAttribute *pAttribute = g_pDataModel->GetAttribute( it ); CDmElement *pElement = pAttribute->GetOwner(); CDmeChannelsClip *pChannelsClip = CastElement< CDmeChannelsClip >( pElement ); if ( !pChannelsClip ) continue;
if ( pChannelsClip->BuildClipStack( pClipStack, pRoot, pShot ) ) return true; } return false; }
//-----------------------------------------------------------------------------
// Finds the owner clip for a channel which passes through the root
//-----------------------------------------------------------------------------
CDmeClip* CDmeChannel::FindOwnerClipForChannel( CDmeClip *pRoot ) { DmeClipStack_t stack; if ( BuildClipStack( &stack, pRoot, pRoot ) ) return stack[ stack.Count() - 1 ]; return NULL; }
|