// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreTypes.h" #include "Templates/UnrealTemplate.h" #include "Misc/InlineValue.h" #include "KeyParams.h" #include "Concepts/EqualityComparable.h" #include "Channels/MovieSceneChannelProxy.h" #include "Channels/MovieSceneChannelTraits.h" struct FMovieSceneChannel; namespace UE::MovieScene { /** * Abstraction for interacting with a value on a specific channel, principally used for auto-key and keying operations in the Sequencer editor */ struct IChannelValue { virtual ~IChannelValue() {} /** * Retrieve the channel pointer that this value relates to */ virtual FMovieSceneChannel* RetrieveChannel(FMovieSceneChannelProxy& Proxy) const = 0; /** * Ask the channel whether the wrapped value already exists at the specified time */ virtual bool AlreadyExistsAtTime(const FMovieSceneChannel* InChannel, FFrameNumber InTime) const = 0; /** * Ask the channel whether the wrapped value is already the default */ virtual bool IsAlreadyDefault(const FMovieSceneChannel* Channel) const = 0; /** * Add a key at the specified time with a specified interpolation type */ virtual void AddKey(FMovieSceneChannel* Channel, FFrameNumber InTime, EMovieSceneKeyInterpolation InterpolationMode) const = 0; /** * Set this channel value as the channel's default */ virtual void SetDefault(FMovieSceneChannel* Channel) const = 0; }; template struct TChannelValue : IChannelValue { using ValueType = typename ChannelType::CurveValueType; template TChannelValue(U&& InValue) : Value(Forward(InValue)) {} virtual bool AlreadyExistsAtTime(const FMovieSceneChannel* InChannel, FFrameNumber InTime) const override { const ChannelType* TypedChannel = static_cast(InChannel); return ValueExistsAtTime(TypedChannel, InTime, Value); } virtual bool IsAlreadyDefault(const FMovieSceneChannel* InChannel) const override { using namespace UE::MovieScene; if constexpr (TModels_V) { const ChannelType* TypedChannel = static_cast(InChannel); ValueType DefaultValue; return GetChannelDefault(TypedChannel, DefaultValue) && DefaultValue == Value; } else { return false; } } virtual void AddKey(FMovieSceneChannel* InChannel, FFrameNumber InTime, EMovieSceneKeyInterpolation InterpolationMode) const override { ChannelType* TypedChannel = static_cast(InChannel); InterpolationMode = GetInterpolationMode(TypedChannel, InTime, InterpolationMode); AddKeyToChannel(TypedChannel, InTime, Value, InterpolationMode); } virtual void SetDefault(FMovieSceneChannel* InChannel) const override { ChannelType* TypedChannel = static_cast(InChannel); SetChannelDefault(TypedChannel, Value); } private: ValueType Value; }; template struct TIndexedChannelValue : TChannelValue { template TIndexedChannelValue(U&& InValue, int32 InChannelIndex) : TChannelValue(Forward(InValue)) , ChannelIndex(InChannelIndex) {} virtual FMovieSceneChannel* RetrieveChannel(FMovieSceneChannelProxy& Proxy) const { return Proxy.GetChannel(ChannelIndex); } private: int32 ChannelIndex; }; struct FUnpackedChannelValue { template FUnpackedChannelValue(TIndexedChannelValue&& InChannelValue, FName InPropertyPath) : PropertyPath(InPropertyPath) , ChannelValue(MoveTemp(InChannelValue)) {} const IChannelValue* operator->() const { return ChannelValue.GetPtr(); } FName GetPropertyPath() const { return PropertyPath; } private: FName PropertyPath; TInlineValue ChannelValue; }; #define UE_MOVIESCENE_UNPACKED_MEMBER(ChannelType, ChannelIndex, StructInstance, Member) \ FUnpackedChannelValue(TIndexedChannelValue(StructInstance.Member, ChannelIndex), FName(#Member)) /** * An array-like container of type-erased values for a collection of FMovieSceneChannels * This is used by track editors and property traits as a way of unpacking composite properties into their * constituent channels and values. */ struct FUnpackedChannelValues { /** * Add another value to this collection. * @note: Addition order is normally important for most properties since it * maps to the position of the channel in the channel list */ void Add(FUnpackedChannelValue&& InValue) { Values.Emplace(MoveTemp(InValue)); } /** * Return the total number of elements in this container */ int32 Num() const { return Values.Num(); } /** * Retrieve the value at the specified index. * @note: Index must be a valid index into this container */ const FUnpackedChannelValue& operator[](int32 Index) const { return Values[Index]; } /** * Remove and return the value at the specified index * @note: Every subsequent entry will be relocated to fill the resulting gap */ FUnpackedChannelValue StealAtIndex(int32 Index) { FUnpackedChannelValue Value = MoveTemp(Values[Index]); Values.RemoveAt(Index, 1, EAllowShrinking::No); return Value; } /** * Retrieve all channel values as a mutable array view */ TArrayView GetValues() { return Values; } private: /** Array storage of sequential values */ TArray> Values; }; } // namespace UE::MovieScene