Files
UnrealEngine/Engine/Source/Editor/MovieSceneTools/Private/Sections/ComponentMaterialParameterSection.cpp
2025-05-18 13:04:45 +08:00

281 lines
10 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Sections/ComponentMaterialParameterSection.h"
#include "Channels/MovieSceneChannelEditorData.h"
#include "Channels/MovieSceneChannelHandle.h"
#include "Channels/MovieSceneFloatChannel.h"
#include "HAL/PlatformCrt.h"
#include "IKeyArea.h"
#include "Internationalization/Internationalization.h"
#include "Internationalization/Text.h"
#include "ISequencer.h"
#include "Layout/Geometry.h"
#include "Layout/PaintGeometry.h"
#include "Math/Color.h"
#include "Math/Vector2D.h"
#include "Misc/Optional.h"
#include "MovieSceneSection.h"
#include "MVVM/ViewModels/CategoryModel.h"
#include "MVVM/ViewModels/ChannelModel.h"
#include "MVVM/Views/SChannelView.h"
#include "MVVM/Views/STrackLane.h"
#include "MVVM/Views/STrackAreaView.h"
#include "Rendering/DrawElementPayloads.h"
#include "Rendering/DrawElements.h"
#include "Rendering/RenderingCommon.h"
#include "ScopedTransaction.h"
#include "Sections/MovieSceneComponentMaterialParameterSection.h"
#include "Sections/MovieSceneSectionHelpers.h"
#include "SequencerSectionPainter.h"
#include "Styling/AppStyle.h"
#include "Templates/Casts.h"
#include "Templates/SharedPointer.h"
#include "Templates/Tuple.h"
#include "TimeToPixel.h"
#include "Types/SlateEnums.h"
#include "UObject/WeakObjectPtrTemplates.h"
class FName;
struct FKeyHandle;
#define LOCTEXT_NAMESPACE "ParameterSection"
namespace UE::Sequencer
{
class SMaterialColorStripView : public SChannelView
{
SLATE_BEGIN_ARGS(SMaterialColorStripView) {}
SLATE_END_ARGS()
void Construct(const FArguments& InArgs, const FViewModelPtr& InViewModel, TSharedPtr<STrackAreaView> InTrackAreaView)
{
WeakModel = InViewModel;
WeakTrackAreaView = InTrackAreaView;
SChannelView::Construct(SChannelView::FArguments(), InViewModel, InTrackAreaView);
}
int32 OnPaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override
{
FViewModelPtr OwningModel = WeakModel.Pin();
if (!OwningModel)
{
return LayerId;
}
bool bIsExpanded = false;
if (TSharedPtr<FLinkedOutlinerExtension> LinkedOutlinerExtension = OwningModel.ImplicitCast())
{
TSharedPtr<IOutlinerExtension> OutlinerItem = LinkedOutlinerExtension ? LinkedOutlinerExtension->GetLinkedOutlinerItem() : nullptr;
if (OutlinerItem)
{
bIsExpanded = OutlinerItem->IsExpanded();
}
}
const FMovieSceneFloatChannel* ColorChannels[4] = { };
for (TViewModelPtr<FChannelModel> ChildChannel : OwningModel->GetChildrenOfType<FChannelModel>())
{
FMovieSceneChannelHandle ChannelHandle = ChildChannel->GetKeyArea()->GetChannel();
FText DisplayText = ChannelHandle.GetMetaData()->DisplayText;
if (ChannelHandle.GetMetaData()->DisplayText.EqualTo(FCommonChannelData::ChannelR))
{
ColorChannels[0] = ChannelHandle.Cast<FMovieSceneFloatChannel>().Get();
}
if (ChannelHandle.GetMetaData()->DisplayText.EqualTo(FCommonChannelData::ChannelG))
{
ColorChannels[1] = ChannelHandle.Cast<FMovieSceneFloatChannel>().Get();
}
if (ChannelHandle.GetMetaData()->DisplayText.EqualTo(FCommonChannelData::ChannelB))
{
ColorChannels[2] = ChannelHandle.Cast<FMovieSceneFloatChannel>().Get();
}
if (ChannelHandle.GetMetaData()->DisplayText.EqualTo(FCommonChannelData::ChannelA))
{
ColorChannels[3] = ChannelHandle.Cast<FMovieSceneFloatChannel>().Get();
}
}
if (ColorChannels[0] && ColorChannels[1] && ColorChannels[2] && ColorChannels[3])
{
const ESlateDrawEffect DrawEffects = bParentEnabled ? ESlateDrawEffect::None : ESlateDrawEffect::DisabledEffect;
FTimeToPixel RelativeTimeToPixel = *WeakTrackAreaView->GetTimeToPixel();
TSharedPtr<ITrackLaneExtension> TrackLaneExtension = WeakModel.ImplicitPin();
if (TrackLaneExtension)
{
FTrackLaneVirtualAlignment VirtualAlignment = TrackLaneExtension->ArrangeVirtualTrackLaneView();
if (VirtualAlignment.Range.GetLowerBound().IsClosed())
{
RelativeTimeToPixel = RelativeTimeToPixel.RelativeTo(VirtualAlignment.Range.GetLowerBoundValue());
}
}
const float StartTime = RelativeTimeToPixel.PixelToSeconds(0.f);
const float EndTime = RelativeTimeToPixel.PixelToSeconds(AllottedGeometry.GetLocalSize().X);
const float SectionDuration = EndTime - StartTime;
FVector2D GradientSize = AllottedGeometry.GetLocalSize() - FVector2D(2.f, 0.f);
if (GradientSize.X >= 1.f)
{
FPaintGeometry PaintGeometry = AllottedGeometry.ToPaintGeometry(GradientSize, FSlateLayoutTransform(FVector2D(1.f, 1.f)));
// If we are showing a background pattern and the colors is transparent, draw a checker pattern
FSlateDrawElement::MakeBox(
OutDrawElements,
LayerId,
PaintGeometry,
FAppStyle::GetBrush("Checker"),
DrawEffects);
FLinearColor DefaultColor = FLinearColor::Black;
DefaultColor.R = ColorChannels[0]->GetDefault().IsSet() ? ColorChannels[0]->GetDefault().GetValue() : 0.f;
DefaultColor.G = ColorChannels[1]->GetDefault().IsSet() ? ColorChannels[1]->GetDefault().GetValue() : 0.f;
DefaultColor.B = ColorChannels[2]->GetDefault().IsSet() ? ColorChannels[2]->GetDefault().GetValue() : 0.f;
DefaultColor.A = ColorChannels[3]->GetDefault().IsSet() ? ColorChannels[3]->GetDefault().GetValue() : 0.f;
TArray< TTuple<float, FLinearColor> > ColorKeys;
MovieSceneSectionHelpers::ConsolidateColorCurves(ColorKeys, DefaultColor, ColorChannels, RelativeTimeToPixel);
TArray<FSlateGradientStop> GradientStops;
for (const TTuple<float, FLinearColor>& ColorStop : ColorKeys)
{
const float Time = ColorStop.Get<0>();
// HACK: The color is converted to SRgb and then reinterpreted as linear here because gradients are converted to FColor
// without the SRgb conversion before being passed to the renderer for some reason.
const FLinearColor Color = ColorStop.Get<1>().ToFColor(true).ReinterpretAsLinear();
float TimeFraction = (Time - StartTime) / SectionDuration;
GradientStops.Add(FSlateGradientStop(FVector2D(TimeFraction * GradientSize.X, 0), Color));
}
if (GradientStops.Num() > 0)
{
FSlateDrawElement::MakeGradient(
OutDrawElements,
LayerId + 1,
PaintGeometry,
GradientStops,
Orient_Vertical,
DrawEffects
);
}
}
}
LayerId += 2;
return SChannelView::OnPaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled);
}
FVector2D ComputeDesiredSize(float) const override
{
return FVector2D();
}
FWeakViewModelPtr WeakModel;
TSharedPtr<STrackAreaView> WeakTrackAreaView;
};
}
FReply FComponentMaterialParameterSection::OnKeyDoubleClicked(const TArray<FKeyHandle>& KeyHandles)
{
UMovieSceneComponentMaterialParameterSection* ParameterSection = Cast<UMovieSceneComponentMaterialParameterSection>(WeakSection.Get());
if (!ParameterSection)
{
return FReply::Handled();
}
for (FColorMaterialParameterInfoAndCurves& NameAndCurve : ParameterSection->ColorParameterInfosAndCurves)
{
FMovieSceneKeyColorPicker KeyColorPicker(ParameterSection, &NameAndCurve.RedCurve, &NameAndCurve.GreenCurve, &NameAndCurve.BlueCurve, &NameAndCurve.AlphaCurve, KeyHandles, WeakSequencer);
}
return FReply::Handled();
}
TSharedPtr<UE::Sequencer::FCategoryModel> FComponentMaterialParameterSection::ConstructCategoryModel(FName InCategoryName, const FText& InDisplayText, TArrayView<const FChannelData> Channels) const
{
using namespace UE::Sequencer;
// Only construct the color category if it has all the channels
uint8 ColorChannelMask = 0;
for (const FChannelData& Channel : Channels)
{
if (Channel.MetaData.DisplayText.EqualTo(FCommonChannelData::ChannelR))
{
ColorChannelMask |= 1 << 0;
}
else if (Channel.MetaData.DisplayText.EqualTo(FCommonChannelData::ChannelG))
{
ColorChannelMask |= 1 << 1;
}
else if (Channel.MetaData.DisplayText.EqualTo(FCommonChannelData::ChannelB))
{
ColorChannelMask |= 1 << 2;
}
else if (Channel.MetaData.DisplayText.EqualTo(FCommonChannelData::ChannelA))
{
ColorChannelMask |= 1 << 3;
}
}
if (ColorChannelMask == 0b1111)
{
class FMaterialColorCategory : public FCategoryModel
{
public:
FMaterialColorCategory(FName InCategoryName, const FText& InDisplayText)
: FCategoryModel(InCategoryName)
{}
TSharedPtr<ITrackLaneWidget> CreateTrackLaneView(const FCreateTrackLaneViewParams& InParams) override
{
return SNew(SMaterialColorStripView, SharedThis(this), InParams.OwningTrackLane->GetTrackAreaView());
}
};
return MakeShared<FMaterialColorCategory>(InCategoryName, InDisplayText);
}
return nullptr;
}
bool FComponentMaterialParameterSection::RequestDeleteCategory(const TArray<FName>& CategoryNamePath)
{
const FScopedTransaction Transaction(LOCTEXT("DeleteParameter", "Delete parameter"));
UMovieSceneComponentMaterialParameterSection* ParameterSection = Cast<UMovieSceneComponentMaterialParameterSection>(WeakSection.Get());
if (ParameterSection->Modify())
{
const bool bColorParameterDeleted = ParameterSection->RemoveColorParameter(CategoryNamePath[0]);
const bool bScalarParameterDeleted = ParameterSection->RemoveScalarParameter(CategoryNamePath[0]);
return bColorParameterDeleted || bScalarParameterDeleted;
}
return false;
}
bool FComponentMaterialParameterSection::RequestDeleteKeyArea(const TArray<FName>& KeyAreaNamePath)
{
// Only handle paths with a single name, in all other cases the user is deleting a component of a vector parameter.
if (KeyAreaNamePath.Num() == 1)
{
const FScopedTransaction Transaction(LOCTEXT("DeleteParameter", "Delete parameter"));
UMovieSceneComponentMaterialParameterSection* ParameterSection = Cast<UMovieSceneComponentMaterialParameterSection>(WeakSection.Get());
if (ParameterSection->TryModify())
{
const bool bColorParameterDeleted = ParameterSection->RemoveColorParameter(KeyAreaNamePath[0]);
const bool bScalarParameterDeleted = ParameterSection->RemoveScalarParameter(KeyAreaNamePath[0]);
return bColorParameterDeleted || bScalarParameterDeleted;
}
}
return false;
}
#undef LOCTEXT_NAMESPACE