// Copyright Pacificao. All Rights Reserved. #include "AgrarianDemoNoticeWidget.h" #include "Engine/World.h" #include "Rendering/DrawElements.h" #include "Styling/CoreStyle.h" namespace { struct FAgrarianCreditCard { const TCHAR* Name; const TCHAR* Role; FLinearColor AccentColor; int32 IllustrationIndex; float HoldSeconds; }; const FAgrarianCreditCard CreditCards[] = { { TEXT("Nathan Slaven"), TEXT("Lead Developer"), FLinearColor(0.70f, 0.90f, 0.46f, 1.0f), 0, 2.05f }, { TEXT("Hunter Slaven"), TEXT("Junior Developer"), FLinearColor(0.36f, 0.72f, 0.96f, 1.0f), 1, 2.05f }, { TEXT("Lisa Reiley"), TEXT("Quality Control"), FLinearColor(0.95f, 0.72f, 0.42f, 1.0f), 2, 2.05f }, { TEXT("River Slaven"), TEXT("Alpha Game Tester"), FLinearColor(0.56f, 0.82f, 0.66f, 1.0f), 3, 2.05f }, { TEXT("Fisher Slaven"), TEXT("Beta Game Tester"), FLinearColor(0.56f, 0.62f, 0.98f, 1.0f), 4, 2.05f }, { TEXT("Funding"), TEXT("Cherished individuals, Pacificao seed funding, and Lina Family Investment Funds"), FLinearColor(0.92f, 0.84f, 0.54f, 1.0f), 5, 3.0f }, }; float SmoothStep(float Value) { const float ClampedValue = FMath::Clamp(Value, 0.0f, 1.0f); return ClampedValue * ClampedValue * (3.0f - (2.0f * ClampedValue)); } } void UAgrarianDemoNoticeWidget::NativeConstruct() { Super::NativeConstruct(); CreditsStartTimeSeconds = GetWorld() ? GetWorld()->GetTimeSeconds() : 0.0f; } int32 UAgrarianDemoNoticeWidget::NativePaint( const FPaintArgs& Args, const FGeometry& AllottedGeometry, const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements, int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const { LayerId = Super::NativePaint(Args, AllottedGeometry, MyCullingRect, OutDrawElements, LayerId, InWidgetStyle, bParentEnabled); const FVector2D Size = AllottedGeometry.GetLocalSize(); const float PanelWidth = FMath::Min(860.0f, FMath::Max(320.0f, Size.X - 96.0f)); const float PanelHeight = 210.0f; const FVector2D PanelPosition((Size.X - PanelWidth) * 0.5f, 42.0f); FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(PanelWidth, PanelHeight), FSlateLayoutTransform(FVector2f(PanelPosition))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, FLinearColor(0.02f, 0.03f, 0.025f, 0.82f)); FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(PanelWidth, 3.0f), FSlateLayoutTransform(FVector2f(PanelPosition))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, FLinearColor(0.45f, 0.72f, 0.40f, 1.0f)); const FSlateFontInfo MottoFont = FCoreStyle::GetDefaultFontStyle("Bold", 30); const FSlateFontInfo VersionFont = FCoreStyle::GetDefaultFontStyle("Regular", 18); const FSlateFontInfo NoticeFont = FCoreStyle::GetDefaultFontStyle("Regular", 16); DrawCenteredText(OutDrawElements, LayerId, AllottedGeometry, Motto, PanelPosition.Y + 34.0f, MottoFont, FLinearColor(0.86f, 0.94f, 0.78f, 1.0f)); DrawCenteredText(OutDrawElements, LayerId, AllottedGeometry, VersionLabel, PanelPosition.Y + 94.0f, VersionFont, FLinearColor(0.82f, 0.86f, 0.78f, 1.0f)); DrawCenteredText(OutDrawElements, LayerId, AllottedGeometry, DemoNotice, PanelPosition.Y + 126.0f, NoticeFont, FLinearColor(0.78f, 0.82f, 0.75f, 1.0f)); DrawCenteredText(OutDrawElements, LayerId, AllottedGeometry, CopyrightNotice, PanelPosition.Y + 158.0f, NoticeFont, FLinearColor(0.66f, 0.70f, 0.64f, 1.0f)); DrawCinematicCredits(OutDrawElements, LayerId, AllottedGeometry); return LayerId; } void UAgrarianDemoNoticeWidget::DrawCenteredText( FSlateWindowElementList& OutDrawElements, int32& LayerId, const FGeometry& AllottedGeometry, const FText& Text, float Y, const FSlateFontInfo& Font, const FLinearColor& Color) const { const FVector2D Size = AllottedGeometry.GetLocalSize(); const FString TextString = Text.ToString(); const float EstimatedWidth = FMath::Min(Size.X - 96.0f, static_cast(TextString.Len()) * Font.Size * 0.52f); const FVector2D TextPosition((Size.X - EstimatedWidth) * 0.5f, Y); FSlateDrawElement::MakeText( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(EstimatedWidth, Font.Size + 12.0f), FSlateLayoutTransform(FVector2f(TextPosition))), Text, Font, ESlateDrawEffect::None, Color); } void UAgrarianDemoNoticeWidget::DrawTextAt( FSlateWindowElementList& OutDrawElements, int32& LayerId, const FGeometry& AllottedGeometry, const FText& Text, const FVector2D& Position, float Width, const FSlateFontInfo& Font, const FLinearColor& Color) const { FSlateDrawElement::MakeText( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(FMath::Max(96.0f, Width), Font.Size + 18.0f), FSlateLayoutTransform(FVector2f(Position))), Text, Font, ESlateDrawEffect::None, Color); } void UAgrarianDemoNoticeWidget::DrawCinematicCredits( FSlateWindowElementList& OutDrawElements, int32& LayerId, const FGeometry& AllottedGeometry) const { const UWorld* World = GetWorld(); if (!World) { return; } const FVector2D Size = AllottedGeometry.GetLocalSize(); const float Elapsed = World->GetTimeSeconds() - CreditsStartTimeSeconds; const float IntroDelay = 0.55f; const float SlamSeconds = 0.28f; const float ExitSeconds = 0.48f; const float GapSeconds = 0.16f; float Cursor = IntroDelay; int32 ActiveIndex = INDEX_NONE; float LocalTime = 0.0f; for (int32 Index = 0; Index < UE_ARRAY_COUNT(CreditCards); ++Index) { const float CardDuration = SlamSeconds + CreditCards[Index].HoldSeconds + ExitSeconds + GapSeconds; if (Elapsed >= Cursor && Elapsed < Cursor + CardDuration) { ActiveIndex = Index; LocalTime = Elapsed - Cursor; break; } Cursor += CardDuration; } if (ActiveIndex == INDEX_NONE) { return; } const FAgrarianCreditCard& Card = CreditCards[ActiveIndex]; const bool bEntering = LocalTime < SlamSeconds; const bool bExiting = LocalTime > SlamSeconds + Card.HoldSeconds; const float EnterAlpha = bEntering ? SmoothStep(LocalTime / SlamSeconds) : 1.0f; const float ExitAlpha = bExiting ? 1.0f - SmoothStep((LocalTime - SlamSeconds - Card.HoldSeconds) / ExitSeconds) : 1.0f; const float Alpha = FMath::Clamp(EnterAlpha * ExitAlpha, 0.0f, 1.0f); const float ImpactOvershoot = bEntering ? FMath::Sin((LocalTime / SlamSeconds) * PI) * 28.0f : 0.0f; const float PanelWidth = FMath::Min(1120.0f, FMath::Max(420.0f, Size.X - 112.0f)); const float PanelHeight = FMath::Min(330.0f, FMath::Max(220.0f, Size.Y - 340.0f)); const FVector2D TargetPosition((Size.X - PanelWidth) * 0.5f, FMath::Max(275.0f, (Size.Y - PanelHeight) * 0.5f + 72.0f)); const float EnterOffset = bEntering ? FMath::Lerp(-Size.X * 0.85f, ImpactOvershoot, SmoothStep(LocalTime / SlamSeconds)) : 0.0f; const float ExitOffset = bExiting ? FMath::Lerp(0.0f, Size.X * 0.9f, SmoothStep((LocalTime - SlamSeconds - Card.HoldSeconds) / ExitSeconds)) : 0.0f; const FVector2D PanelPosition(TargetPosition.X + EnterOffset + ExitOffset, TargetPosition.Y); FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(Size), FSlateLayoutTransform(FVector2f::ZeroVector)), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, FLinearColor(0.0f, 0.0f, 0.0f, 0.34f * Alpha)); FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(PanelWidth, PanelHeight), FSlateLayoutTransform(FVector2f(PanelPosition))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, FLinearColor(0.015f, 0.018f, 0.014f, 0.92f * Alpha)); FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(PanelWidth, 5.0f), FSlateLayoutTransform(FVector2f(PanelPosition))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, FLinearColor(Card.AccentColor.R, Card.AccentColor.G, Card.AccentColor.B, Alpha)); const FVector2D ArtSize(FMath::Min(275.0f, PanelWidth * 0.32f), PanelHeight - 64.0f); const FVector2D ArtPosition(PanelPosition.X + 32.0f, PanelPosition.Y + 32.0f); DrawCreditIllustration(OutDrawElements, LayerId, AllottedGeometry, ArtPosition, ArtSize, Card.IllustrationIndex, Card.AccentColor, Alpha); const float TextX = ArtPosition.X + ArtSize.X + 42.0f; const float TextWidth = PanelPosition.X + PanelWidth - TextX - 36.0f; const FSlateFontInfo NameFont = FCoreStyle::GetDefaultFontStyle("Bold", ActiveIndex == 5 ? 46 : 56); const FSlateFontInfo RoleFont = FCoreStyle::GetDefaultFontStyle("Regular", ActiveIndex == 5 ? 22 : 28); const FSlateFontInfo LabelFont = FCoreStyle::GetDefaultFontStyle("Regular", 16); const float NameY = PanelPosition.Y + (ActiveIndex == 5 ? 76.0f : 92.0f); DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(Card.Name), FVector2D(TextX, NameY), TextWidth, NameFont, FLinearColor(0.94f, 0.98f, 0.88f, Alpha)); DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(Card.Role), FVector2D(TextX + 4.0f, NameY + 76.0f), TextWidth, RoleFont, FLinearColor(Card.AccentColor.R, Card.AccentColor.G, Card.AccentColor.B, Alpha)); DrawTextAt(OutDrawElements, LayerId, AllottedGeometry, FText::FromString(TEXT("Agrarian startup credits")), FVector2D(TextX + 6.0f, PanelPosition.Y + PanelHeight - 58.0f), TextWidth, LabelFont, FLinearColor(0.64f, 0.70f, 0.60f, 0.82f * Alpha)); } void UAgrarianDemoNoticeWidget::DrawCreditIllustration( FSlateWindowElementList& OutDrawElements, int32& LayerId, const FGeometry& AllottedGeometry, const FVector2D& Position, const FVector2D& Size, int32 IllustrationIndex, const FLinearColor& AccentColor, float Alpha) const { FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(Size), FSlateLayoutTransform(FVector2f(Position))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, FLinearColor(0.07f, 0.08f, 0.065f, 0.96f * Alpha)); const FVector2D Center = Position + (Size * 0.5f); const FLinearColor SoftAccent(AccentColor.R, AccentColor.G, AccentColor.B, 0.28f * Alpha); const FLinearColor StrongAccent(AccentColor.R, AccentColor.G, AccentColor.B, Alpha); auto DrawBox = [&](const FVector2D& BoxPosition, const FVector2D& BoxSize, const FLinearColor& Color) { FSlateDrawElement::MakeBox( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(FVector2f(BoxSize), FSlateLayoutTransform(FVector2f(BoxPosition))), FCoreStyle::Get().GetBrush(TEXT("WhiteBrush")), ESlateDrawEffect::None, Color); }; auto DrawLine = [&](const TArray& Points, const FLinearColor& Color, float Thickness) { FSlateDrawElement::MakeLines( OutDrawElements, ++LayerId, AllottedGeometry.ToPaintGeometry(), Points, ESlateDrawEffect::None, Color, true, Thickness); }; DrawBox(Position + FVector2D(16.0f, 16.0f), FVector2D(Size.X - 32.0f, Size.Y - 32.0f), FLinearColor(0.0f, 0.0f, 0.0f, 0.22f * Alpha)); if (IllustrationIndex == 0) { DrawBox(Center + FVector2D(-72.0f, -46.0f), FVector2D(144.0f, 82.0f), SoftAccent); DrawBox(Center + FVector2D(-62.0f, -36.0f), FVector2D(124.0f, 62.0f), FLinearColor(0.02f, 0.03f, 0.025f, Alpha)); DrawLine({ FVector2f(Center.X - 42.0f, Center.Y - 8.0f), FVector2f(Center.X - 8.0f, Center.Y - 28.0f), FVector2f(Center.X + 42.0f, Center.Y + 18.0f) }, StrongAccent, 4.0f); DrawBox(Center + FVector2D(-34.0f, 48.0f), FVector2D(68.0f, 10.0f), StrongAccent); } else if (IllustrationIndex == 1) { DrawLine({ FVector2f(Center.X, Center.Y + 58.0f), FVector2f(Center.X, Center.Y - 48.0f) }, StrongAccent, 5.0f); DrawLine({ FVector2f(Center.X, Center.Y - 8.0f), FVector2f(Center.X - 48.0f, Center.Y - 42.0f), FVector2f(Center.X - 74.0f, Center.Y - 20.0f) }, StrongAccent, 5.0f); DrawLine({ FVector2f(Center.X, Center.Y + 2.0f), FVector2f(Center.X + 52.0f, Center.Y - 34.0f), FVector2f(Center.X + 80.0f, Center.Y - 10.0f) }, StrongAccent, 5.0f); DrawBox(Center + FVector2D(-84.0f, 64.0f), FVector2D(168.0f, 8.0f), SoftAccent); } else if (IllustrationIndex == 2) { DrawBox(Center + FVector2D(-58.0f, -74.0f), FVector2D(116.0f, 148.0f), FLinearColor(0.93f, 0.88f, 0.72f, 0.22f * Alpha)); DrawBox(Center + FVector2D(-34.0f, -88.0f), FVector2D(68.0f, 20.0f), StrongAccent); DrawLine({ FVector2f(Center.X - 32.0f, Center.Y - 26.0f), FVector2f(Center.X - 12.0f, Center.Y - 6.0f), FVector2f(Center.X + 42.0f, Center.Y - 48.0f) }, StrongAccent, 5.0f); DrawBox(Center + FVector2D(-34.0f, 28.0f), FVector2D(68.0f, 5.0f), StrongAccent); } else if (IllustrationIndex == 3) { DrawBox(Center + FVector2D(-72.0f, -28.0f), FVector2D(144.0f, 56.0f), SoftAccent); DrawLine({ FVector2f(Center.X - 70.0f, Center.Y), FVector2f(Center.X - 18.0f, Center.Y - 58.0f), FVector2f(Center.X + 32.0f, Center.Y + 44.0f), FVector2f(Center.X + 78.0f, Center.Y - 18.0f) }, StrongAccent, 5.0f); DrawBox(Center + FVector2D(-16.0f, -16.0f), FVector2D(32.0f, 32.0f), FLinearColor(0.92f, 0.96f, 0.86f, 0.80f * Alpha)); } else if (IllustrationIndex == 4) { DrawBox(Center + FVector2D(-64.0f, -58.0f), FVector2D(128.0f, 116.0f), SoftAccent); DrawLine({ FVector2f(Center.X - 44.0f, Center.Y - 8.0f), FVector2f(Center.X - 8.0f, Center.Y + 28.0f), FVector2f(Center.X + 54.0f, Center.Y - 36.0f) }, StrongAccent, 5.0f); DrawBox(Center + FVector2D(-74.0f, 74.0f), FVector2D(148.0f, 8.0f), StrongAccent); DrawBox(Center + FVector2D(-74.0f, -82.0f), FVector2D(148.0f, 8.0f), StrongAccent); } else { DrawLine({ FVector2f(Center.X, Center.Y + 72.0f), FVector2f(Center.X, Center.Y - 36.0f) }, StrongAccent, 5.0f); DrawLine({ FVector2f(Center.X, Center.Y - 12.0f), FVector2f(Center.X - 52.0f, Center.Y - 50.0f), FVector2f(Center.X - 80.0f, Center.Y - 28.0f) }, StrongAccent, 5.0f); DrawLine({ FVector2f(Center.X, Center.Y - 6.0f), FVector2f(Center.X + 52.0f, Center.Y - 54.0f), FVector2f(Center.X + 84.0f, Center.Y - 28.0f) }, StrongAccent, 5.0f); DrawBox(Center + FVector2D(-92.0f, 78.0f), FVector2D(184.0f, 8.0f), SoftAccent); DrawBox(Center + FVector2D(-48.0f, 56.0f), FVector2D(96.0f, 8.0f), StrongAccent); } }