void UMovieSceneParticleTrack::AddNewParticleSystem(float KeyTime, bool bTrigger) { EParticleKey::Type KeyType = bTrigger ? EParticleKey::Trigger : EParticleKey::Toggle; // @todo Instead of a 0.1 second event, this should be 0 seconds, requires handling 0 size sections float Duration = KeyType == EParticleKey::Trigger ? 0.1f : 1.f; UMovieSceneParticleSection* NewSection = NewObject<UMovieSceneParticleSection>(this); NewSection->InitialPlacement(ParticleSections, KeyTime, KeyTime + Duration, SupportsMultipleRows()); NewSection->SetKeyType(KeyType); ParticleSections.Add(NewSection); }
FVector2D FParticleSection::GetKeyBrushOrigin( FKeyHandle KeyHandle ) const { UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section ); if ( ParticleSection != nullptr ) { FIntegralKey ParticleKey = ParticleSection->GetParticleCurve().GetKey(KeyHandle); if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Activate ) { return FVector2D(-1.0f, 1.0f); } else if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Deactivate ) { return FVector2D(1.0f, 1.0f); } } return FVector2D(0.0f, 0.0f); }
const FSlateBrush* FParticleSection::GetKeyBrush( FKeyHandle KeyHandle ) const { UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section ); if ( ParticleSection != nullptr ) { FIntegralKey ParticleKey = ParticleSection->GetParticleCurve().GetKey(KeyHandle); if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Activate ) { return LeftKeyBrush; } else if ( (EParticleKey::Type)ParticleKey.Value == EParticleKey::Deactivate ) { return RightKeyBrush; } } return nullptr; }
void FMatineeImportTools::CopyInterpParticleTrack( TSharedRef<ISequencer> Sequencer, UInterpTrackToggle* MatineeToggleTrack, UMovieSceneParticleTrack* ParticleTrack ) { const FScopedTransaction Transaction( NSLOCTEXT( "Sequencer", "PasteMatineeParticleTrack", "Paste Matinee particle track" ) ); bool bSectionCreated = false; ParticleTrack->Modify(); float KeyTime = MatineeToggleTrack->GetKeyframeTime( 0 ); UMovieSceneParticleSection* Section = Cast<UMovieSceneParticleSection>( MovieSceneHelpers::FindSectionAtTime( ParticleTrack->GetAllSections(), KeyTime ) ); if ( Section == nullptr ) { Section = Cast<UMovieSceneParticleSection>( ParticleTrack->CreateNewSection() ); ParticleTrack->AddSection( *Section ); bSectionCreated = true; } if (Section->TryModify()) { float SectionMin = Section->GetStartTime(); float SectionMax = Section->GetEndTime(); FIntegralCurve& ParticleCurve = Section->GetParticleCurve(); for ( const auto& Key : MatineeToggleTrack->ToggleTrack ) { EParticleKey::Type ParticleKey; if ( TryConvertMatineeToggleToOutParticleKey( Key.ToggleAction, ParticleKey ) ) { ParticleCurve.AddKey( Key.Time, (int32)ParticleKey, ParticleCurve.FindKey( Key.Time ) ); } SectionMin = FMath::Min( SectionMin, Key.Time ); SectionMax = FMath::Max( SectionMax, Key.Time ); } Section->SetStartTime( SectionMin ); Section->SetEndTime( SectionMax ); if ( bSectionCreated ) { Sequencer->NotifyMovieSceneDataChanged(); } } }
void FMovieSceneParticleTrackInstance::Update( float Position, float LastPosition, const TArray<UObject*>& RuntimeObjects, class IMovieScenePlayer& Player ) { // @todo Sequencer We need something analagous to Matinee 1's particle replay tracks // What we have here is simple toggling/triggering if (Position > LastPosition && Player.GetPlaybackStatus() == EMovieScenePlayerStatus::Playing) { bool bTrigger = false, bOn = false, bOff = false; const TArray<UMovieSceneSection*> Sections = ParticleTrack->GetAllParticleSections(); for (int32 i = 0; i < Sections.Num(); ++i) { UMovieSceneParticleSection* Section = Cast<UMovieSceneParticleSection>(Sections[i]); if (Section->GetKeyType() == EParticleKey::Trigger) { if (Position > Section->GetStartTime() && LastPosition < Section->GetStartTime()) { bTrigger = true; } } else if (Section->GetKeyType() == EParticleKey::Toggle) { if (Position >= Section->GetStartTime() && Position <= Section->GetEndTime()) { bOn = true; } else if (Position >= Section->GetEndTime() && LastPosition < Section->GetEndTime()) { bOff = true; } } } if (bTrigger || bOn || bOff) { for (int32 i = 0; i < RuntimeObjects.Num(); ++i) { AEmitter* Emitter = Cast<AEmitter>(RuntimeObjects[i]); if (Emitter) { if (bTrigger) { Emitter->ToggleActive(); } else if (bOn) { Emitter->Activate(); } else if (bOff) { Emitter->Deactivate(); } } } } } else { for (int32 i = 0; i < RuntimeObjects.Num(); ++i) { AEmitter* Emitter = Cast<AEmitter>(RuntimeObjects[i]); if (Emitter) { Emitter->Deactivate(); } } } }
int32 FParticleSection::OnPaintSection( FSequencerSectionPainter& InPainter ) const { TSharedPtr<ISequencer> OwningSequencer = OwningSequencerPtr.Pin(); if (!OwningSequencer.IsValid()) { return InPainter.LayerId + 1; } const ESlateDrawEffect::Type DrawEffects = InPainter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; UMovieSceneParticleSection* AnimSection = Cast<UMovieSceneParticleSection>( &Section ); const FTimeToPixel& TimeToPixelConverter = InPainter.GetTimeConverter(); FLinearColor TrackColor; // @todo Sequencer - These values should be cached and then refreshed only when the particle system changes. bool bIsLooping = false; float LastEmitterEndTime = 0; UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section ); if ( ParticleSection != nullptr ) { UMovieSceneParticleTrack* ParentTrack = Cast<UMovieSceneParticleTrack>( ParticleSection->GetOuter() ); if ( ParentTrack != nullptr ) { TrackColor = ParentTrack->GetColorTint(); FGuid ObjectHandle; for ( const FMovieSceneBinding& Binding : OwningSequencer->GetFocusedMovieSceneSequence()->GetMovieScene()->GetBindings() ) { if ( Binding.GetTracks().Contains( ParentTrack ) ) { ObjectHandle = Binding.GetObjectGuid(); break; } } if ( ObjectHandle.IsValid() ) { UObject* BoundObject = OwningSequencer->GetFocusedMovieSceneSequenceInstance()->FindObject( ObjectHandle, *OwningSequencer ); UParticleSystemComponent* ParticleSystemComponent = Cast<UParticleSystemComponent>(BoundObject); if(AEmitter* ParticleSystemActor = Cast<AEmitter>(BoundObject)) { ParticleSystemComponent = ParticleSystemActor->GetParticleSystemComponent(); } if ( ParticleSystemComponent != nullptr && ParticleSystemComponent->Template != nullptr ) { for ( UParticleEmitter* Emitter : ParticleSystemComponent->Template->Emitters ) { UParticleModuleRequired* RequiredModule = Emitter->GetLODLevel( 0 )->RequiredModule; bIsLooping |= RequiredModule->EmitterLoops == 0; LastEmitterEndTime = FMath::Max( LastEmitterEndTime, RequiredModule->EmitterDelay + RequiredModule->EmitterDuration ); } } } } } // @todo Sequencer - This should only draw the visible ranges. TArray<TRange<float>> DrawRanges; TOptional<float> CurrentRangeStart; for ( auto KeyIterator = ParticleSection->GetParticleCurve().GetKeyIterator(); KeyIterator; ++KeyIterator ) { FIntegralKey Key = *KeyIterator; if ( (EParticleKey::Type)Key.Value == EParticleKey::Activate ) { if ( CurrentRangeStart.IsSet() == false ) { CurrentRangeStart = Key.Time; } else { if ( bIsLooping == false ) { if ( Key.Time > CurrentRangeStart.GetValue() + LastEmitterEndTime ) { DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), CurrentRangeStart.GetValue() + LastEmitterEndTime ) ); } else { DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), Key.Time ) ); } CurrentRangeStart = Key.Time; } } } if ( (EParticleKey::Type)Key.Value == EParticleKey::Deactivate ) { if ( CurrentRangeStart.IsSet() ) { if (bIsLooping) { DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), Key.Time ) ); } else { if ( Key.Time > CurrentRangeStart.GetValue() + LastEmitterEndTime ) { DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), CurrentRangeStart.GetValue() + LastEmitterEndTime ) ); } else { DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), Key.Time ) ); } } CurrentRangeStart.Reset(); } } } if ( CurrentRangeStart.IsSet() ) { if ( bIsLooping ) { DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), OwningSequencer->GetViewRange().GetUpperBoundValue() ) ); } else { DrawRanges.Add( TRange<float>( CurrentRangeStart.GetValue(), CurrentRangeStart.GetValue() + LastEmitterEndTime ) ); } } for ( const TRange<float>& DrawRange : DrawRanges ) { float XOffset = TimeToPixelConverter.TimeToPixel(DrawRange.GetLowerBoundValue()); float XSize = TimeToPixelConverter.TimeToPixel(DrawRange.GetUpperBoundValue()) - XOffset; FSlateDrawElement::MakeBox( InPainter.DrawElements, InPainter.LayerId, InPainter.SectionGeometry.ToPaintGeometry( FVector2D( XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2 ), FVector2D( XSize, SequencerSectionConstants::KeySize.Y ) ), FEditorStyle::GetBrush( "Sequencer.Section.Background" ), InPainter.SectionClippingRect, DrawEffects ); FSlateDrawElement::MakeBox( InPainter.DrawElements, InPainter.LayerId, InPainter.SectionGeometry.ToPaintGeometry( FVector2D( XOffset, (InPainter.SectionGeometry.GetLocalSize().Y - SequencerSectionConstants::KeySize.Y) / 2 ), FVector2D( XSize, SequencerSectionConstants::KeySize.Y ) ), FEditorStyle::GetBrush( "Sequencer.Section.BackgroundTint" ), InPainter.SectionClippingRect, DrawEffects, TrackColor ); } return InPainter.LayerId+1; }
void FParticleSection::GenerateSectionLayout( class ISectionLayoutBuilder& LayoutBuilder ) const { UMovieSceneParticleSection* ParticleSection = Cast<UMovieSceneParticleSection>( &Section ); LayoutBuilder.SetSectionAsKeyArea( MakeShareable( new FEnumKeyArea( ParticleSection->GetParticleCurve(), ParticleSection, ParticleKeyEnum ) ) ); }