diff options
Diffstat (limited to 'movieobjects/dmechannel.cpp')
| -rw-r--r-- | movieobjects/dmechannel.cpp | 1007 |
1 files changed, 1007 insertions, 0 deletions
diff --git a/movieobjects/dmechannel.cpp b/movieobjects/dmechannel.cpp new file mode 100644 index 0000000..81e5e9d --- /dev/null +++ b/movieobjects/dmechannel.cpp @@ -0,0 +1,1007 @@ +//========= 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; +} + |