123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "UiFaderComponent.h"
- #include "RenderGraph.h"
- #include <LyShine/IDraw2d.h>
- #include <AzCore/Math/Crc.h>
- #include <AzCore/Math/MathUtils.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzCore/Serialization/EditContext.h>
- #include <AzCore/RTTI/BehaviorContext.h>
- #include <Atom/RPI.Public/Image/AttachmentImage.h>
- #include <AtomCore/Instance/Instance.h>
- #include <LyShine/Bus/UiElementBus.h>
- #include <LyShine/Bus/UiRenderBus.h>
- #include <LyShine/Bus/UiCanvasBus.h>
- #include <LyShine/IRenderGraph.h>
- #include "UiSerialize.h"
- #include "RenderToTextureBus.h"
- // BehaviorContext UiFaderNotificationBus forwarder
- class BehaviorUiFaderNotificationBusHandler
- : public UiFaderNotificationBus::Handler
- , public AZ::BehaviorEBusHandler
- {
- public:
- AZ_EBUS_BEHAVIOR_BINDER(BehaviorUiFaderNotificationBusHandler, "{CAD44770-3D5E-4E67-8F05-D2A89E8C501A}", AZ::SystemAllocator,
- OnFadeComplete, OnFadeInterrupted, OnFaderDestroyed);
- void OnFadeComplete() override
- {
- Call(FN_OnFadeComplete);
- }
- void OnFadeInterrupted() override
- {
- Call(FN_OnFadeInterrupted);
- }
- void OnFaderDestroyed() override
- {
- Call(FN_OnFaderDestroyed);
- }
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // PUBLIC MEMBER FUNCTIONS
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- UiFaderComponent::UiFaderComponent()
- : m_fade(1.0f)
- , m_isFading(false)
- , m_fadeTarget(1.0f)
- , m_fadeSpeedInSeconds(1.0f)
- {
- m_cachedPrimitive.m_vertices = nullptr;
- m_cachedPrimitive.m_numVertices = 0;
- m_cachedPrimitive.m_indices = nullptr;
- m_cachedPrimitive.m_numIndices = 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- UiFaderComponent::~UiFaderComponent()
- {
- if (m_isFading && m_entity)
- {
- UiFaderNotificationBus::Event(GetEntityId(), &UiFaderNotificationBus::Events::OnFaderDestroyed);
- }
- DestroyRenderTarget();
- // We only deallocate the vertices on destruction rather than every time we recreate the render
- // target. Changing the size of the element requires recreating render target but doesn't change
- // the number of vertices. Note this may be nullptr which is fine for delete.
- delete [] m_cachedPrimitive.m_vertices;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::Update(float deltaTime)
- {
- if (!m_isFading)
- {
- return;
- }
- // Update fade
- SetFadeValueInternal(m_fade + m_fadeSpeedInSeconds * deltaTime);
- // Check for completion
- if (m_fadeSpeedInSeconds == 0 ||
- m_fadeSpeedInSeconds > 0 && m_fade >= m_fadeTarget ||
- m_fadeSpeedInSeconds < 0 && m_fade <= m_fadeTarget)
- {
- CompleteFade();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::Render(LyShine::IRenderGraph* renderGraph, UiElementInterface* elementInterface,
- UiRenderInterface* renderInterface, int numChildren, bool isInGame)
- {
- static const float epsilon = 1.0f / 255.0f; // less than this value means alpha will be zero when converted to a uint8
- // if the fader is at (or close to) zero then do not render this element or its children at all
- if (m_fade < epsilon)
- {
- return;
- }
- if (GetUseRenderToTexture())
- {
- AZ::Vector2 pixelAlignedTopLeft, pixelAlignedBottomRight;
- ComputePixelAlignedBounds(pixelAlignedTopLeft, pixelAlignedBottomRight);
- AZ::Vector2 renderTargetSize = pixelAlignedBottomRight - pixelAlignedTopLeft;
- bool needsResize = static_cast<int>(renderTargetSize.GetX()) != m_renderTargetWidth || static_cast<int>(renderTargetSize.GetY()) != m_renderTargetHeight;
- if (m_attachmentImageId.IsEmpty() || needsResize)
- {
- // We delay first creation of the render target until render time since size is not known in Activate
- // We also call this if the size has changed
- CreateOrResizeRenderTarget(pixelAlignedTopLeft, pixelAlignedBottomRight);
- }
- // if the render target failed to be created (zero size for example) we don't render the element at all
- if (m_attachmentImageId.IsEmpty())
- {
- return;
- }
- // Do render-to-texture fade, this renders this element and its children to a render target, then renders that
- RenderRttFader(renderGraph, elementInterface, renderInterface, numChildren, isInGame);
- }
- else
- {
- // destroy previous render target, if exists
- if (!m_attachmentImageId.IsEmpty())
- {
- DestroyRenderTarget();
- }
- // do standard (non-render-to-texture) fade, this renders this element and its children
- RenderStandardFader(renderGraph, elementInterface, renderInterface, numChildren, isInGame);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- float UiFaderComponent::GetFadeValue()
- {
- return m_fade;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::SetFadeValue(float fade)
- {
- if (m_isFading)
- {
- UiFaderNotificationBus::Event(GetEntityId(), &UiFaderNotificationBus::Events::OnFadeInterrupted);
- m_isFading = false;
- }
- SetFadeValueInternal(fade);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::Fade(float targetValue, float speed)
- {
- if (m_isFading)
- {
- UiFaderNotificationBus::Event(GetEntityId(), &UiFaderNotificationBus::Events::OnFadeInterrupted);
- }
- // Connect to UpdateBus for updates while fading
- if (!UiCanvasUpdateNotificationBus::Handler::BusIsConnected())
- {
- AZ::EntityId canvasEntityId;
- UiElementBus::EventResult(canvasEntityId, GetEntityId(), &UiElementBus::Events::GetCanvasEntityId);
- // if this element has not been fixed up then canvasEntityId will be invalid. We handle this
- // in OnUiElementFixup
- if (canvasEntityId.IsValid())
- {
- UiCanvasUpdateNotificationBus::Handler::BusConnect(canvasEntityId);
- }
- }
- m_isFading = true;
- m_fadeTarget = clamp_tpl(targetValue, 0.0f, 1.0f);
- // Give speed a direction
- float fadeChange = m_fadeTarget - m_fade;
- float fadeDirection = fadeChange >= 0.0f ? 1.0f : -1.0f;
- m_fadeSpeedInSeconds = fadeDirection * speed;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- bool UiFaderComponent::IsFading()
- {
- return m_isFading;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- bool UiFaderComponent::GetUseRenderToTexture()
- {
- return m_useRenderToTexture;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::SetUseRenderToTexture(bool useRenderToTexture)
- {
- if (GetUseRenderToTexture() != useRenderToTexture)
- {
- m_useRenderToTexture = useRenderToTexture;
- OnRenderTargetChange();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::PropertyValuesChanged()
- {
- MarkRenderGraphDirty();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::OnUiElementFixup(AZ::EntityId canvasEntityId, [[maybe_unused]] AZ::EntityId parentEntityId)
- {
- // If we are fading but not already connected to UpdateBus for updates then connect
- // This would only happen if Fade was called during activate (before fixup)
- if (m_isFading && !UiCanvasUpdateNotificationBus::Handler::BusIsConnected())
- {
- UiCanvasUpdateNotificationBus::Handler::BusConnect(canvasEntityId);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::OnCanvasSpaceRectChanged(AZ::EntityId /*entityId*/, const UiTransformInterface::Rect& /*oldRect*/, const UiTransformInterface::Rect& /*newRect*/)
- {
- // we only listen for this if using render target, if rect changed recreate render target
- OnRenderTargetChange();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::OnTransformToViewportChanged()
- {
- // we only listen for this if using render target, if transform changed recreate render target
- OnRenderTargetChange();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // PUBLIC STATIC MEMBER FUNCTIONS
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::Reflect(AZ::ReflectContext* context)
- {
- AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
- if (serializeContext)
- {
- serializeContext->Class<UiFaderComponent, AZ::Component>()
- ->Version(1)
- ->Field("Fade", &UiFaderComponent::m_fade)
- ->Field("UseRenderToTexture", &UiFaderComponent::m_useRenderToTexture);
- AZ::EditContext* ec = serializeContext->GetEditContext();
- if (ec)
- {
- auto editInfo = ec->Class<UiFaderComponent>("Fader", "A component that can fade its element and all its child elements");
- editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "")
- ->Attribute(AZ::Edit::Attributes::Category, "UI")
- ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiFader.png")
- ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiFader.png")
- ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("UI"))
- ->Attribute(AZ::Edit::Attributes::AutoExpand, true);
- editInfo->DataElement(AZ::Edit::UIHandlers::Slider, &UiFaderComponent::m_fade, "Fade", "The initial fade value")
- ->Attribute(AZ::Edit::Attributes::Step, 0.01f)
- ->Attribute(AZ::Edit::Attributes::Min, 0.0f)
- ->Attribute(AZ::Edit::Attributes::Max, 1.0f)
- ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiFaderComponent::OnFadeValueChanged);
-
- editInfo->DataElement(0, &UiFaderComponent::m_useRenderToTexture, "Use render to texture",
- "If true, this element and all children are rendered to a separate render target\n"
- "and then that target is rendered to the screen. This avoids child elements\n"
- "blending with each other as they fade. But it is more expensive.")
- ->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiFaderComponent::OnRenderTargetChange);
- }
- }
- AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
- if (behaviorContext)
- {
- behaviorContext->EBus<UiFaderBus>("UiFaderBus")
- ->Event("GetFadeValue", &UiFaderBus::Events::GetFadeValue)
- ->Event("SetFadeValue", &UiFaderBus::Events::SetFadeValue)
- ->Event("Fade", &UiFaderBus::Events::Fade)
- ->Event("IsFading", &UiFaderBus::Events::IsFading)
- ->Event("GetUseRenderToTexture", &UiFaderBus::Events::GetUseRenderToTexture)
- ->Event("SetUseRenderToTexture", &UiFaderBus::Events::SetUseRenderToTexture)
- ->VirtualProperty("Fade", "GetFadeValue", "SetFadeValue");
- behaviorContext->Class<UiFaderComponent>()->RequestBus("UiFaderBus");
- behaviorContext->EBus<UiFaderNotificationBus>("UiFaderNotificationBus")
- ->Handler<BehaviorUiFaderNotificationBusHandler>();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- // PROTECTED MEMBER FUNCTIONS
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::Activate()
- {
- UiRenderControlBus::Handler::BusConnect(GetEntityId());
- UiFaderBus::Handler::BusConnect(GetEntityId());
- UiAnimateEntityBus::Handler::BusConnect(GetEntityId());
- UiElementNotificationBus::Handler::BusConnect(GetEntityId());
- if (GetUseRenderToTexture())
- {
- UiTransformChangeNotificationBus::Handler::BusConnect(m_entity->GetId());
- }
- // The first time the component is activated we don't want to connect to the update bus. However if
- // the element starts a fade and then we deactivate and reactivate we need to reconnect to the
- // update bus.
- if (m_isFading)
- {
- AZ::EntityId canvasEntityId;
- UiElementBus::EventResult(canvasEntityId, GetEntityId(), &UiElementBus::Events::GetCanvasEntityId);
- if (canvasEntityId.IsValid())
- {
- UiCanvasUpdateNotificationBus::Handler::BusConnect(canvasEntityId);
- }
- }
- // set the render target name to an automatically generated name based on entity Id
- m_renderTargetName = "FaderTarget_";
- m_renderTargetName += GetEntityId().ToString();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::Deactivate()
- {
- UiRenderControlBus::Handler::BusDisconnect();
- UiFaderBus::Handler::BusDisconnect();
- UiAnimateEntityBus::Handler::BusDisconnect();
- UiElementNotificationBus::Handler::BusDisconnect();
- if (UiTransformChangeNotificationBus::Handler::BusIsConnected())
- {
- UiTransformChangeNotificationBus::Handler::BusDisconnect();
- }
- // if deactivated during a fade we either have to cancel the fade or rely on activate reconnecting
- // to the UpdateBus. We do the latter.
- if (UiCanvasUpdateNotificationBus::Handler::BusIsConnected())
- {
- UiCanvasUpdateNotificationBus::Handler::BusDisconnect();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::CompleteFade()
- {
- SetFadeValueInternal(m_fadeTarget);
- // Queue the OnFadeComplete event to prevent deletions during the canvas update
- UiFaderNotificationBus::QueueEvent(GetEntityId(), &UiFaderNotificationBus::Events::OnFadeComplete);
- m_isFading = false;
- // Disconnect from UpdateBus
- if (UiCanvasUpdateNotificationBus::Handler::BusIsConnected())
- {
- UiCanvasUpdateNotificationBus::Handler::BusDisconnect();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::SetFadeValueInternal(float fade)
- {
- if (m_fade != fade)
- {
- m_fade = fade;
- MarkRenderGraphDirty();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::OnFadeValueChanged()
- {
- MarkRenderGraphDirty();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::OnRenderTargetChange()
- {
- // mark render graph dirty so next render will recreate render targets if necessary
- MarkRenderGraphDirty();
- // update cached primitive to reflect new transforms
- AZ::Vector2 pixelAlignedTopLeft, pixelAlignedBottomRight;
- ComputePixelAlignedBounds(pixelAlignedTopLeft, pixelAlignedBottomRight);
- UpdateCachedPrimitive(pixelAlignedTopLeft, pixelAlignedBottomRight);
- // if using a render target we need to know if the element size or position changes since that
- // affects the render target and the viewport
- if (GetUseRenderToTexture())
- {
- if (!UiTransformChangeNotificationBus::Handler::BusIsConnected())
- {
- UiTransformChangeNotificationBus::Handler::BusConnect(m_entity->GetId());
- }
- }
- else
- {
- if (UiTransformChangeNotificationBus::Handler::BusIsConnected())
- {
- UiTransformChangeNotificationBus::Handler::BusDisconnect();
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::MarkRenderGraphDirty()
- {
- // tell the canvas to invalidate the render graph
- AZ::EntityId canvasEntityId;
- UiElementBus::EventResult(canvasEntityId, GetEntityId(), &UiElementBus::Events::GetCanvasEntityId);
- UiCanvasComponentImplementationBus::Event(canvasEntityId, &UiCanvasComponentImplementationBus::Events::MarkRenderGraphDirty);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::CreateOrResizeRenderTarget(const AZ::Vector2& pixelAlignedTopLeft, const AZ::Vector2& pixelAlignedBottomRight)
- {
- // The render target size is the pixel aligned element size.
- AZ::Vector2 renderTargetSize = pixelAlignedBottomRight - pixelAlignedTopLeft;
- if (renderTargetSize.GetX() <= 0 || renderTargetSize.GetY() <= 0)
- {
- // if render targets exist then destroy them (just to be in a consistent state)
- DestroyRenderTarget();
- return;
- }
- m_viewportTopLeft = pixelAlignedTopLeft;
- m_viewportSize = renderTargetSize;
- // [LYSHINE_ATOM_TODO][GHI #6271] Optimize by reusing existing render targets
- DestroyRenderTarget();
- // Create a render target that this element and its children will be rendered to
- AZ::EntityId canvasEntityId;
- UiElementBus::EventResult(canvasEntityId, GetEntityId(), &UiElementBus::Events::GetCanvasEntityId);
- AZ::RHI::Size imageSize(static_cast<uint32_t>(renderTargetSize.GetX()), static_cast<uint32_t>(renderTargetSize.GetY()), 1);
- LyShine::RenderToTextureRequestBus::EventResult(
- m_attachmentImageId,
- canvasEntityId,
- &LyShine::RenderToTextureRequestBus::Events::UseRenderTarget,
- AZ::Name(m_renderTargetName.c_str()),
- imageSize);
- if (m_attachmentImageId.IsEmpty())
- {
- AZ_Warning("UI", false, "Failed to create render target for UiFaderComponent");
- }
- // at this point either all render targets and depth surfaces are created or none are.
- // If all succeeded then update the render target size
- if (!m_attachmentImageId.IsEmpty())
- {
- m_renderTargetWidth = static_cast<int>(renderTargetSize.GetX());
- m_renderTargetHeight = static_cast<int>(renderTargetSize.GetY());
- }
- UpdateCachedPrimitive(pixelAlignedTopLeft, pixelAlignedBottomRight);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::DestroyRenderTarget()
- {
- if (!m_attachmentImageId.IsEmpty())
- {
- AZ::EntityId canvasEntityId;
- UiElementBus::EventResult(canvasEntityId, GetEntityId(), &UiElementBus::Events::GetCanvasEntityId);
- LyShine::RenderToTextureRequestBus::Event(
- canvasEntityId, &LyShine::RenderToTextureRequestBus::Events::ReleaseRenderTarget, m_attachmentImageId);
- m_attachmentImageId = AZ::RHI::AttachmentId{};
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::UpdateCachedPrimitive(const AZ::Vector2& pixelAlignedTopLeft, const AZ::Vector2& pixelAlignedBottomRight)
- {
- // update viewport position
- m_viewportTopLeft = pixelAlignedTopLeft;
- // now create the verts to render the texture to the screen, we cache these in m_cachedPrimitive
- const int numVertices = 4;
- if (!m_cachedPrimitive.m_vertices)
- {
- // verts not yet allocated, allocate them now
- const int numIndices = 6;
- m_cachedPrimitive.m_vertices = new LyShine::UiPrimitiveVertex[numVertices];
- m_cachedPrimitive.m_numVertices = numVertices;
- static uint16 indices[numIndices] = { 0, 1, 2, 2, 3, 0 };
- m_cachedPrimitive.m_indices = indices;
- m_cachedPrimitive.m_numIndices = numIndices;
- }
- float left = pixelAlignedTopLeft.GetX();
- float right = pixelAlignedBottomRight.GetX();
- float top = pixelAlignedTopLeft.GetY();
- float bottom = pixelAlignedBottomRight.GetY();
- Vec2 positions[numVertices] = { Vec2(left, top), Vec2(right, top), Vec2(right, bottom), Vec2(left, bottom) };
- static const Vec2 uvs[numVertices] = { {0, 0}, {1, 0}, {1, 1}, {0, 1} };
- for (int i = 0; i < numVertices; ++i)
- {
- m_cachedPrimitive.m_vertices[i].xy = positions[i];
- m_cachedPrimitive.m_vertices[i].color.dcolor = 0xFFFFFFFF;
- m_cachedPrimitive.m_vertices[i].st = uvs[i];
- m_cachedPrimitive.m_vertices[i].texIndex = 0; // this will be set later by render graph
- m_cachedPrimitive.m_vertices[i].texHasColorChannel = 1;
- m_cachedPrimitive.m_vertices[i].texIndex2 = 0;
- m_cachedPrimitive.m_vertices[i].pad = 0;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::ComputePixelAlignedBounds(AZ::Vector2& pixelAlignedTopLeft, AZ::Vector2& pixelAlignedBottomRight)
- {
- // The viewport has to be axis aligned so we get the axis-aligned top-left and bottom-right of the element
- // in main viewport space. We then snap them to the nearest pixel since the render target has to be an exact number
- // of pixels.
- UiTransformInterface::RectPoints points;
- UiTransformBus::Event(GetEntityId(), &UiTransformBus::Events::GetViewportSpacePoints, points);
- pixelAlignedTopLeft = Draw2dHelper::RoundXY(points.GetAxisAlignedTopLeft(), IDraw2d::Rounding::Nearest);
- pixelAlignedBottomRight = Draw2dHelper::RoundXY(points.GetAxisAlignedBottomRight(), IDraw2d::Rounding::Nearest);
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::RenderStandardFader(LyShine::IRenderGraph* renderGraph, UiElementInterface* elementInterface,
- UiRenderInterface* renderInterface, int numChildren, bool isInGame)
- {
- // Push the fade value that is used for this element and children
- renderGraph->PushAlphaFade(m_fade);
- // Render this element and its children
- RenderElementAndChildren(renderGraph, elementInterface, renderInterface, numChildren, isInGame);
- // Pop off the fade from this fader
- renderGraph->PopAlphaFade();
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::RenderRttFader(LyShine::IRenderGraph* renderGraph, UiElementInterface* elementInterface,
- UiRenderInterface* renderInterface, int numChildren, bool isInGame)
- {
- // Get the render target
- AZ::Data::Instance<AZ::RPI::AttachmentImage> attachmentImage;
- AZ::EntityId canvasEntityId;
- UiElementBus::EventResult(canvasEntityId, GetEntityId(), &UiElementBus::Events::GetCanvasEntityId);
- LyShine::RenderToTextureRequestBus::EventResult(
- attachmentImage, canvasEntityId, &LyShine::RenderToTextureRequestBus::Events::GetRenderTarget, m_attachmentImageId);
- // Render the element and its children to a render target
- {
- // we always clear to transparent black - the accumulation of alpha in the render target requires it
- AZ::Color clearColor(0.0f, 0.0f, 0.0f, 0.0f);
- // Start building the render to texture node in the render graph
- renderGraph->BeginRenderToTexture(attachmentImage, m_viewportTopLeft, m_viewportSize, clearColor);
- // We don't want this fader or parent faders to affect what is rendered to the render target since we will
- // apply those fades when we render from the render target.
- renderGraph->PushOverrideAlphaFade(1.0f);
- // Render this element and its children
- RenderElementAndChildren(renderGraph, elementInterface, renderInterface, numChildren, isInGame);
- // finish building the render to texture node in the render graph
- renderGraph->EndRenderToTexture();
- // pop off the override alpha fade
- renderGraph->PopAlphaFade();
- }
- // render from the render target to the screen (or a parent render target) with the fade value
- {
- // set the alpha in the verts
- {
- float desiredAlpha = renderGraph->GetAlphaFade() * m_fade;
- uint8 desiredPackedAlpha = static_cast<uint8>(desiredAlpha * 255.0f);
- // If the fade value has changed we need to update the alpha values in the vertex colors but we do
- // not want to touch or recompute the RGB values
- if (m_cachedPrimitive.m_vertices[0].color.a != desiredPackedAlpha)
- {
- // go through all the cached vertices and update the alpha values
- LyShine::UCol desiredPackedColor = m_cachedPrimitive.m_vertices[0].color;
- desiredPackedColor.a = desiredPackedAlpha;
- for (int i = 0; i < m_cachedPrimitive.m_numVertices; ++i)
- {
- m_cachedPrimitive.m_vertices[i].color = desiredPackedColor;
- }
- }
- }
- // Add a primitive to render a quad using the render target we have created
- {
- // Set the texture and other render state required
- AZ::Data::Instance<AZ::RPI::Image> image = attachmentImage;
- bool isClampTextureMode = true;
- bool isTextureSRGB = true;
- bool isTexturePremultipliedAlpha = true;
- LyShine::BlendMode blendMode = LyShine::BlendMode::Normal;
- renderGraph->AddPrimitive(&m_cachedPrimitive, image, isClampTextureMode, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////
- void UiFaderComponent::RenderElementAndChildren(LyShine::IRenderGraph* renderGraph, UiElementInterface* elementInterface,
- UiRenderInterface* renderInterface, int numChildren, bool isInGame)
- {
- // Render the visual component for this element (if there is one)
- if (renderInterface)
- {
- renderInterface->Render(renderGraph);
- }
- // Render the child elements
- for (int childIndex = 0; childIndex < numChildren; ++childIndex)
- {
- UiElementInterface* childElementInterface = elementInterface->GetChildElementInterface(childIndex);
- // childElementInterface should never be nullptr but check just to be safe
- if (childElementInterface)
- {
- childElementInterface->RenderElement(renderGraph, isInGame);
- }
- }
- }
|