// Copyright (c), Firelight Technologies Pty, Ltd. 2012-2020. #include "FMODEventControlTrackEditor.h" #include "Rendering/DrawElements.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "Curves/IntegralCurve.h" #include "SequencerSectionPainter.h" #include "EditorStyleSet.h" #include "Editor/UnrealEdEngine.h" #include "Sequencer/FMODEventControlSection.h" #include "Sequencer/FMODEventControlTrack.h" #include "ISectionLayoutBuilder.h" #include "FMODAmbientSound.h" #include "CommonMovieSceneTools.h" #include "Channels/MovieSceneChannelProxy.h" #include "Channels/MovieSceneChannelEditorData.h" #define LOCTEXT_NAMESPACE "FFMODEventControlTrackEditor" FFMODEventControlSection::FFMODEventControlSection(UMovieSceneSection &InSection, TSharedRef InOwningSequencer) : Section(InSection) , OwningSequencerPtr(InOwningSequencer) { } UMovieSceneSection *FFMODEventControlSection::GetSectionObject() { return &Section; } float FFMODEventControlSection::GetSectionHeight() const { static const float SectionHeight = 20.f; return SectionHeight; } int32 FFMODEventControlSection::OnPaintSection(FSequencerSectionPainter &InPainter) const { TSharedPtr OwningSequencer = OwningSequencerPtr.Pin(); if (!OwningSequencer.IsValid()) { return InPainter.LayerId + 1; } const ESlateDrawEffect DrawEffects = InPainter.bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect; const FTimeToPixel &TimeToPixelConverter = InPainter.GetTimeConverter(); FLinearColor TrackColor; // TODO: Set / clip stop time based on event length UFMODEventControlSection *ControlSection = Cast(&Section); if (IsValid(ControlSection)) { UFMODEventControlTrack *ParentTrack = Cast(ControlSection->GetOuter()); if (IsValid(ParentTrack)) { TrackColor = ParentTrack->GetColorTint(); } } // TODO: This should only draw the visible ranges. TArray> DrawRanges; TOptional CurrentRangeStart; if (ControlSection != nullptr) { TMovieSceneChannelData ChannelData = ControlSection->ControlKeys.GetData(); TArrayView Times = ChannelData.GetTimes(); TArrayView Values = ChannelData.GetValues(); for (int32 Index = 0; Index < Times.Num(); ++Index) { const double Time = Times[Index] / TimeToPixelConverter.GetTickResolution(); const EFMODEventControlKey Value = (EFMODEventControlKey)Values[Index]; if (Value == EFMODEventControlKey::Play) { if (CurrentRangeStart.IsSet() == false) { CurrentRangeStart = Time; } } if (Value == EFMODEventControlKey::Stop) { if (CurrentRangeStart.IsSet()) { DrawRanges.Add(TRange(CurrentRangeStart.GetValue(), Time)); CurrentRangeStart.Reset(); } } } } if (CurrentRangeStart.IsSet()) { DrawRanges.Add(TRange(CurrentRangeStart.GetValue(), OwningSequencer->GetViewRange().GetUpperBoundValue())); } for (const TRange &DrawRange : DrawRanges) { float XOffset = TimeToPixelConverter.SecondsToPixel(DrawRange.GetLowerBoundValue()); float XSize = TimeToPixelConverter.SecondsToPixel(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"), 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"), DrawEffects, TrackColor); } return InPainter.LayerId + 1; } FFMODEventControlTrackEditor::FFMODEventControlTrackEditor(TSharedRef InSequencer) : FMovieSceneTrackEditor(InSequencer) { } TSharedRef FFMODEventControlTrackEditor::CreateTrackEditor(TSharedRef InSequencer) { return MakeShareable(new FFMODEventControlTrackEditor(InSequencer)); } bool FFMODEventControlTrackEditor::SupportsType(TSubclassOf Type) const { return Type == UFMODEventControlTrack::StaticClass(); } TSharedRef FFMODEventControlTrackEditor::MakeSectionInterface( UMovieSceneSection &SectionObject, UMovieSceneTrack &Track, FGuid ObjectBinding) { check(SupportsType(SectionObject.GetOuter()->GetClass())); const TSharedPtr OwningSequencer = GetSequencer(); return MakeShareable(new FFMODEventControlSection(SectionObject, OwningSequencer.ToSharedRef())); } void FFMODEventControlTrackEditor::BuildObjectBindingTrackMenu(FMenuBuilder &MenuBuilder, const TArray &ObjectBindings, const UClass *ObjectClass) { if (ObjectClass->IsChildOf(AFMODAmbientSound::StaticClass()) || ObjectClass->IsChildOf(UFMODAudioComponent::StaticClass())) { const TSharedPtr ParentSequencer = GetSequencer(); MenuBuilder.AddMenuEntry(LOCTEXT("AddFMODEventControlTrack", "FMOD Event Control Track"), LOCTEXT("FMODEventControlTooltip", "Adds a track for controlling FMOD event."), FSlateIcon(), FUIAction(FExecuteAction::CreateSP(this, &FFMODEventControlTrackEditor::AddControlKey, ObjectBindings[0]))); } } void FFMODEventControlTrackEditor::AddControlKey(const FGuid ObjectGuid) { TSharedPtr SequencerPtr = GetSequencer(); UObject *Object = SequencerPtr.IsValid() ? SequencerPtr->FindSpawnedObjectOrTemplate(ObjectGuid) : nullptr; if (IsValid(Object)) { AnimatablePropertyChanged(FOnKeyProperty::CreateRaw(this, &FFMODEventControlTrackEditor::AddKeyInternal, Object)); } } FKeyPropertyResult FFMODEventControlTrackEditor::AddKeyInternal(FFrameNumber KeyTime, UObject *Object) { FKeyPropertyResult KeyPropertyResult; FFindOrCreateHandleResult HandleResult = FindOrCreateHandleToObject(Object); FGuid ObjectHandle = HandleResult.Handle; KeyPropertyResult.bHandleCreated |= HandleResult.bWasCreated; if (ObjectHandle.IsValid()) { FFindOrCreateTrackResult TrackResult = FindOrCreateTrackForObject(ObjectHandle, UFMODEventControlTrack::StaticClass()); UMovieSceneTrack *Track = TrackResult.Track; KeyPropertyResult.bTrackCreated |= TrackResult.bWasCreated; if (KeyPropertyResult.bTrackCreated && ensure(Track)) { UFMODEventControlTrack *EventTrack = Cast(Track); EventTrack->AddNewSection(KeyTime); EventTrack->SetDisplayName(LOCTEXT("TrackName", "FMOD Event")); } } return KeyPropertyResult; } #undef LOCTEXT_NAMESPACE