Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,558 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
#include "LyShineExamplesCppExample.h"
#include <AzCore/Component/Entity.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <LyShine/ISprite.h>
#include <LyShine/UiSerializeHelpers.h>
#include <LyShine/Bus/UiElementBus.h>
#include <LyShine/Bus/UiTextBus.h>
#include <LyShine/Bus/UiImageBus.h>
#include <LyShine/Bus/UiButtonBus.h>
#include <LyShine/Bus/UiCheckboxBus.h>
#include <LyShine/Bus/UiSliderBus.h>
#include <LyShine/Bus/UiTextInputBus.h>
#include <LyShine/Bus/UiInteractableStatesBus.h>
#include <LyShine/Bus/UiInitializationBus.h>
#include <LyShine/UiComponentTypes.h>
#include <LyShine/Bus/UiAnimationBus.h>
#include <LyShine/Bus/UiNavigationBus.h>
namespace LyShineExamples
{
////////////////////////////////////////////////////////////////////////////////////////////////////
LyShineExamplesCppExample::LyShineExamplesCppExample()
: m_health(10)
{
LyShineExamplesCppExampleBus::Handler::BusConnect();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
LyShineExamplesCppExample::~LyShineExamplesCppExample()
{
LyShineExamplesCppExampleBus::Handler::BusDisconnect();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::CreateCanvas()
{
// Remove the existing example canvas if it exists
DestroyCanvas();
AZ::EntityId canvasEntityId = gEnv->pLyShine->CreateCanvas();
if (!canvasEntityId.IsValid())
{
return;
}
m_canvasId = canvasEntityId;
// Create an image to be the canvas background
AZ::EntityId foregroundId = CreateBackground();
// Create the canvas title
CreateText("Title", false, foregroundId, UiTransform2dInterface::Anchors(0.5f, 0.1f, 0.5f, 0.1f), UiTransform2dInterface::Offsets(-200, 50, 200, -50),
"Canvas created through C++", AZ::Color(0.f, 0.f, 0.f, 1.f), IDraw2d::HAlign::Center, IDraw2d::VAlign::Center,
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
// Add the elements examples, creating elements from scratch
CreateElementsExample(foregroundId);
// Add the behavior example, creating some light defining of custom behavior in C++
CreateBehaviorExample(foregroundId);
// Create a button to be able to destroy this canvas and keep navigating the UiFeatures examples
m_destroyButton = CreateButton("DestroyButton", false, foregroundId, UiTransform2dInterface::Anchors(0.15f, 0.9f, 0.15f, 0.9f), UiTransform2dInterface::Offsets(-100, -25, 100, 25),
"Destroy canvas", AZ::Color(0.604f, 0.780f, 0.839f, 1.f), AZ::Color(0.380f, 0.745f, 0.871f, 1.f), AZ::Color(0.055f, 0.675f, 0.886f, 1.f), AZ::Color(1.f, 1.f, 1.f, 1.f),
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
// Connect to the button notification bus so we receive click events from the destroy button
UiButtonNotificationBus::MultiHandler::BusConnect(m_destroyButton);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::DestroyCanvas()
{
if (m_canvasId.IsValid())
{
UiButtonNotificationBus::MultiHandler::BusDisconnect(m_damageButton);
m_damageButton.SetInvalid();
UiButtonNotificationBus::MultiHandler::BusDisconnect(m_healButton);
m_healButton.SetInvalid();
UiButtonNotificationBus::MultiHandler::BusDisconnect(m_destroyButton);
m_destroyButton.SetInvalid();
m_healthBar.SetInvalid();
gEnv->pLyShine->ReleaseCanvas(m_canvasId, false);
m_canvasId.SetInvalid();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::OnButtonClick()
{
// Get the id of what button just got clicked (it has to be one that we subscribed to)
const AZ::EntityId* pButtonClickedId = UiButtonNotificationBus::GetCurrentBusId();
// If the damage button got clicked
if (*pButtonClickedId == m_damageButton)
{
UpdateHealth(-1);
}
// If the heal button got clicked
else if (*pButtonClickedId == m_healButton)
{
UpdateHealth(1);
}
// If the destroy button got clicked
else // *pButtonClickedId == m_destroyButton
{
DestroyCanvas();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::Reflect(AZ::ReflectContext* context)
{
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->EBus<LyShineExamplesCppExampleBus>("LyShineExamplesCppExampleBus")
->Event("CreateCanvas", &LyShineExamplesCppExampleBus::Events::CreateCanvas)
->Event("DestroyCanvas", &LyShineExamplesCppExampleBus::Events::DestroyCanvas);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
AZ::EntityId LyShineExamplesCppExample::CreateBackground()
{
// Get the canvas
UiCanvasInterface* canvas = UiCanvasBus::FindFirstHandler(m_canvasId);
// Create an empty element in the canvas
AZ::Entity* background = canvas->CreateChildElement("Background");
// Add a transform component and an image component to the background
CreateComponent(background, LyShine::UiTransform2dComponentUuid);
CreateComponent(background, LyShine::UiImageComponentUuid);
// Add a button component to the background to prevent interactions with interactables on the canvases below this canvas
CreateComponent(background, LyShine::UiButtonComponentUuid);
// We want the background to stretch to the corners of the canvas
// So we set the anchors to go all the way to the right and to the bottom
AZ::EntityId backgroundId = background->GetId();
EBUS_EVENT_ID(backgroundId, UiTransform2dBus, SetAnchors, UiTransform2dInterface::Anchors(0.0f, 0.0f, 1.0f, 1.0f), false, false);
// Set the color of the background image to black
EBUS_EVENT_ID(backgroundId, UiImageBus, SetColor, AZ::Color(0.f, 0.f, 0.f, 1.f));
// Set the background button's navigation to none
EBUS_EVENT_ID(backgroundId, UiNavigationBus, SetNavigationMode, UiNavigationInterface::NavigationMode::None);
// Now let's create a child of the background
AZ::Entity* foreground = canvas->CreateChildElement("Foreground");
// Add a transform and an image to the foreground as well
CreateComponent(foreground, LyShine::UiTransform2dComponentUuid);
CreateComponent(foreground, LyShine::UiImageComponentUuid);
// Stretch it to the corners of the background with the anchors, stretch it 90% of background to still a background outline
AZ::EntityId foregroundId = foreground->GetId();
EBUS_EVENT_ID(foregroundId, UiTransform2dBus, SetAnchors, UiTransform2dInterface::Anchors(0.1f, 0.1f, 0.9f, 0.9f), false, false);
return foregroundId;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::CreateElementsExample(AZ::EntityId foregroundId)
{
// Create the elements examples section title
CreateText("ElementExamples", false, foregroundId, UiTransform2dInterface::Anchors(0.1f, 0.25f, 0.1f, 0.25f), UiTransform2dInterface::Offsets(),
"Elements examples:", AZ::Color(0.f, 0.f, 0.f, 1.f), IDraw2d::HAlign::Left, IDraw2d::VAlign::Center,
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
// Create an example button
CreateButton("ButtonExample", false, foregroundId, UiTransform2dInterface::Anchors(0.2f, 0.35f, 0.2f, 0.35f), UiTransform2dInterface::Offsets(-100, -25, 100, 25),
"Button", AZ::Color(0.604f, 0.780f, 0.839f, 1.f), AZ::Color(0.380f, 0.745f, 0.871f, 1.f), AZ::Color(0.055f, 0.675f, 0.886f, 1.f), AZ::Color(0.f, 0.f, 0.f, 1.f),
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
// Create an example checkbox
CreateCheckbox("CheckBoxExample", false, foregroundId, UiTransform2dInterface::Anchors(0.5f, 0.35f, 0.5f, 0.35f), UiTransform2dInterface::Offsets(-25, -25, 25, 25),
"Checkbox", AZ::Color(1.f, 1.f, 1.f, 1.f), AZ::Color(0.718f, 0.733f, 0.741f, 1.f), AZ::Color(0.831f, 0.914f, 0.937f, 1.f), AZ::Color(0.2f, 1.f, 0.2f, 1.f), AZ::Color(0.f, 0.f, 0.f, 1.f),
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
// Create an example text input
CreateTextInput("TextInputExample", false, foregroundId, UiTransform2dInterface::Anchors(0.8f, 0.35f, 0.8f, 0.35f), UiTransform2dInterface::Offsets(-100, -25, 100, 25),
"", "Type here...", AZ::Color(1.f, 1.f, 1.f, 1.f), AZ::Color(0.616f, 0.792f, 0.851f, 1.0f), AZ::Color(0.616f, 0.792f, 0.851f, 1.0f), AZ::Color(0.f, 0.f, 0.f, 1.f), AZ::Color(0.43f, 0.43f, 0.43f, 1.f),
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::CreateBehaviorExample(AZ::EntityId foregroundId)
{
// Create the behavior example section title
CreateText("BehaviorExample", false, foregroundId, UiTransform2dInterface::Anchors(0.1f, 0.5f, 0.1f, 0.5f), UiTransform2dInterface::Offsets(),
"Behavior example:", AZ::Color(0.f, 0.f, 0.f, 1.f), IDraw2d::HAlign::Left, IDraw2d::VAlign::Center, UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
// Here we set up a very simple health bar example, all piloted from C++
// Create the health bar that we will use to display the health
// We need a background to show how much of the health has been taken off
AZ::EntityId healthBarBgId = CreateImage("HealthBarBackground", false, foregroundId, UiTransform2dInterface::Anchors(0.5f, 0.65f, 0.5f, 0.65f), UiTransform2dInterface::Offsets(-400, -50, 400, 50),
"Textures/Basic/Button_Sliced_Normal.sprite", UiImageInterface::ImageType::Sliced, AZ::Color(0.2f, 0.2f, 0.2f, 1.f), UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
// And then the currently remaining health bar
m_maxHealthBarOffsets = UiTransform2dInterface::Offsets(10, -40, 790, 40);
m_healthBar = CreateImage("HealthBar", false, healthBarBgId, UiTransform2dInterface::Anchors(0.0f, 0.5f, 0.0f, 0.5f), m_maxHealthBarOffsets,
"Textures/Basic/Button_Sliced_Normal.sprite", UiImageInterface::ImageType::Sliced, AZ::Color(0.7f, 0.f, 0.f, 1.f), UiTransformInterface::ScaleToDeviceMode::None);
m_health = 10;
// Create a damage button to decrease the health
m_damageButton = CreateButton("DamageButton", false, foregroundId, UiTransform2dInterface::Anchors(0.35f, 0.8f, 0.35f, 0.8f), UiTransform2dInterface::Offsets(-75, -25, 75, 25),
"Damage", AZ::Color(0.604f, 0.780f, 0.839f, 1.f), AZ::Color(0.380f, 0.745f, 0.871f, 1.f), AZ::Color(0.055f, 0.675f, 0.886f, 1.f), AZ::Color(0.f, 0.f, 0.f, 1.f),
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
UiButtonNotificationBus::MultiHandler::BusConnect(m_damageButton);
// Create a heal button to increase the health
m_healButton = CreateButton("HealButton", false, foregroundId, UiTransform2dInterface::Anchors(0.65f, 0.8f, 0.65f, 0.8f), UiTransform2dInterface::Offsets(-75, -25, 75, 25),
"Heal", AZ::Color(0.604f, 0.780f, 0.839f, 1.f), AZ::Color(0.380f, 0.745f, 0.871f, 1.f), AZ::Color(0.055f, 0.675f, 0.886f, 1.f), AZ::Color(0.f, 0.f, 0.f, 1.f),
UiTransformInterface::ScaleToDeviceMode::UniformScaleToFit);
UiButtonNotificationBus::MultiHandler::BusConnect(m_healButton);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::CreateComponent(AZ::Entity* entity, const AZ::Uuid& componentTypeId)
{
entity->Deactivate();
entity->CreateComponent(componentTypeId);
entity->Activate();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
AZ::EntityId LyShineExamplesCppExample::CreateButton(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
const char* text, AZ::Color baseColor, AZ::Color selectedColor, AZ::Color pressedColor, AZ::Color textColor,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode)
{
// Create the button element
AZ::Entity* button = nullptr;
if (atRoot)
{
EBUS_EVENT_ID_RESULT(button, parent, UiCanvasBus, CreateChildElement, name);
}
else
{
EBUS_EVENT_ID_RESULT(button, parent, UiElementBus, CreateChildElement, name);
}
AZ::EntityId buttonId = button->GetId();
// Set up the button element
{
CreateComponent(button, LyShine::UiTransform2dComponentUuid);
CreateComponent(button, LyShine::UiImageComponentUuid);
CreateComponent(button, LyShine::UiButtonComponentUuid);
AZ_Assert(UiTransform2dBus::FindFirstHandler(buttonId), "Transform2d component missing");
EBUS_EVENT_ID(buttonId, UiTransformBus, SetScaleToDeviceMode, scaleToDeviceMode);
EBUS_EVENT_ID(buttonId, UiTransform2dBus, SetAnchors, anchors, false, false);
EBUS_EVENT_ID(buttonId, UiTransform2dBus, SetOffsets, offsets);
EBUS_EVENT_ID(buttonId, UiImageBus, SetColor, baseColor);
EBUS_EVENT_ID(buttonId, UiInteractableStatesBus, SetStateColor, UiInteractableStatesInterface::StateHover, buttonId, selectedColor);
EBUS_EVENT_ID(buttonId, UiInteractableStatesBus, SetStateAlpha, UiInteractableStatesInterface::StateHover, buttonId, selectedColor.GetA());
EBUS_EVENT_ID(buttonId, UiInteractableStatesBus, SetStateColor, UiInteractableStatesInterface::StatePressed, buttonId, pressedColor);
EBUS_EVENT_ID(buttonId, UiInteractableStatesBus, SetStateAlpha, UiInteractableStatesInterface::StatePressed, buttonId, pressedColor.GetA());
EBUS_EVENT_ID(buttonId, UiImageBus, SetSpritePathname, "UI/Textures/Prefab/button_normal.sprite");
EBUS_EVENT_ID(buttonId, UiImageBus, SetImageType, UiImageInterface::ImageType::Sliced);
EBUS_EVENT_ID(buttonId, UiInteractableStatesBus, SetStateSpritePathname, UiInteractableStatesInterface::StateDisabled, buttonId, "UI/Textures/Prefab/button_disabled.sprite");
}
AZ::Entity* textElem = nullptr;
EBUS_EVENT_ID_RESULT(textElem, buttonId, UiElementBus, CreateChildElement, "ButtonText");
AZ::EntityId textId = textElem->GetId();
// Create and set up the text element (text displayed on the button)
{
CreateComponent(textElem, LyShine::UiTransform2dComponentUuid);
CreateComponent(textElem, LyShine::UiTextComponentUuid);
AZ_Assert(UiTransform2dBus::FindFirstHandler(textId), "Transform component missing");
EBUS_EVENT_ID(textId, UiTransform2dBus, SetAnchors, UiTransform2dInterface::Anchors(0.5, 0.5, 0.5, 0.5), false, false);
EBUS_EVENT_ID(textId, UiTransform2dBus, SetOffsets, UiTransform2dInterface::Offsets(0, 0, 0, 0));
EBUS_EVENT_ID(textId, UiTextBus, SetText, text);
EBUS_EVENT_ID(textId, UiTextBus, SetTextAlignment, IDraw2d::HAlign::Center, IDraw2d::VAlign::Center);
EBUS_EVENT_ID(textId, UiTextBus, SetColor, textColor);
EBUS_EVENT_ID(textId, UiTextBus, SetFontSize, 24.0f);
}
// Trigger all InGamePostActivate
EBUS_EVENT_ID(buttonId, UiInitializationBus, InGamePostActivate);
EBUS_EVENT_ID(textId, UiInitializationBus, InGamePostActivate);
return buttonId;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
AZ::EntityId LyShineExamplesCppExample::CreateCheckbox(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets, [[maybe_unused]] const char* text,
AZ::Color baseColor, AZ::Color selectedColor, [[maybe_unused]] AZ::Color pressedColor, AZ::Color checkColor, [[maybe_unused]] AZ::Color textColor,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode)
{
// Create the checkbox element
AZ::Entity* checkbox = nullptr;
if (atRoot)
{
EBUS_EVENT_ID_RESULT(checkbox, parent, UiCanvasBus, CreateChildElement, name);
}
else
{
EBUS_EVENT_ID_RESULT(checkbox, parent, UiElementBus, CreateChildElement, name);
}
AZ::EntityId checkboxId = checkbox->GetId();
// Set up the checkbox element
{
CreateComponent(checkbox, LyShine::UiTransform2dComponentUuid);
CreateComponent(checkbox, LyShine::UiImageComponentUuid);
CreateComponent(checkbox, LyShine::UiCheckboxComponentUuid);
AZ_Assert(UiTransform2dBus::FindFirstHandler(checkboxId), "Transform2d component missing");
EBUS_EVENT_ID(checkboxId, UiTransformBus, SetScaleToDeviceMode, scaleToDeviceMode);
EBUS_EVENT_ID(checkboxId, UiTransform2dBus, SetAnchors, anchors, false, false);
EBUS_EVENT_ID(checkboxId, UiTransform2dBus, SetOffsets, offsets);
EBUS_EVENT_ID(checkboxId, UiImageBus, SetColor, baseColor);
EBUS_EVENT_ID(checkboxId, UiImageBus, SetSpritePathname, "UI/Textures/Prefab/checkbox_box_normal.sprite");
EBUS_EVENT_ID(checkboxId, UiInteractableStatesBus, SetStateColor, UiInteractableStatesInterface::StateHover, checkboxId, selectedColor);
EBUS_EVENT_ID(checkboxId, UiInteractableStatesBus, SetStateAlpha, UiInteractableStatesInterface::StateHover, checkboxId, selectedColor.GetA());
EBUS_EVENT_ID(checkboxId, UiInteractableStatesBus, SetStateSpritePathname, UiInteractableStatesInterface::StateHover, checkboxId, "UI/Textures/Prefab/checkbox_box_hover.sprite");
EBUS_EVENT_ID(checkboxId, UiInteractableStatesBus, SetStateSpritePathname, UiInteractableStatesInterface::StateDisabled, checkboxId, "UI/Textures/Prefab/checkbox_box_disabled.sprite");
}
// Create the On element (the checkmark that will be displayed when the checkbox is "on")
AZ::Entity* onElement;
EBUS_EVENT_ID_RESULT(onElement, checkboxId, UiElementBus, CreateChildElement, "onElem");
AZ::EntityId onId = onElement->GetId();
// Set up the On element
{
CreateComponent(onElement, LyShine::UiTransform2dComponentUuid);
CreateComponent(onElement, LyShine::UiImageComponentUuid);
EBUS_EVENT_ID(onId, UiTransform2dBus, SetAnchors, UiTransform2dInterface::Anchors(0.5f, 0.5f, 0.5f, 0.5f), false, false);
EBUS_EVENT_ID(onId, UiTransform2dBus, SetOffsets, offsets);
EBUS_EVENT_ID(onId, UiImageBus, SetSpritePathname, "UI/Textures/Prefab/checkbox_check.sprite");
EBUS_EVENT_ID(onId, UiImageBus, SetColor, checkColor);
}
// Link the on and off child entities to the parent checkbox entity.
EBUS_EVENT_ID(checkboxId, UiCheckboxBus, SetCheckedEntity, onId);
// Trigger all InGamePostActivate
EBUS_EVENT_ID(onId, UiInitializationBus, InGamePostActivate);
EBUS_EVENT_ID(checkboxId, UiInitializationBus, InGamePostActivate);
return checkboxId;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
AZ::EntityId LyShineExamplesCppExample::CreateText(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
const char* text, AZ::Color textColor, IDraw2d::HAlign hAlign, IDraw2d::VAlign vAlign,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode)
{
// Create the text element
AZ::Entity* textElem = nullptr;
if (atRoot)
{
EBUS_EVENT_ID_RESULT(textElem, parent, UiCanvasBus, CreateChildElement, name);
}
else
{
EBUS_EVENT_ID_RESULT(textElem, parent, UiElementBus, CreateChildElement, name);
}
AZ::EntityId textId = textElem->GetId();
// Set up the text element
{
CreateComponent(textElem, LyShine::UiTransform2dComponentUuid);
CreateComponent(textElem, LyShine::UiTextComponentUuid);
AZ_Assert(UiTransform2dBus::FindFirstHandler(textId), "Transform component missing");
EBUS_EVENT_ID(textId, UiTransformBus, SetScaleToDeviceMode, scaleToDeviceMode);
EBUS_EVENT_ID(textId, UiTransform2dBus, SetAnchors, anchors, false, false);
EBUS_EVENT_ID(textId, UiTransform2dBus, SetOffsets, offsets);
EBUS_EVENT_ID(textId, UiTextBus, SetText, text);
EBUS_EVENT_ID(textId, UiTextBus, SetTextAlignment, hAlign, vAlign);
EBUS_EVENT_ID(textId, UiTextBus, SetColor, textColor);
}
// Trigger all InGamePostActivate
EBUS_EVENT_ID(textId, UiInitializationBus, InGamePostActivate);
return textId;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
AZ::EntityId LyShineExamplesCppExample::CreateTextInput(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
const char* text, const char* placeHolderText,
AZ::Color baseColor, AZ::Color selectedColor, AZ::Color pressedColor,
AZ::Color textColor, AZ::Color placeHolderColor,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode)
{
// Create the text input element
AZ::Entity* textInputElem = nullptr;
if (atRoot)
{
EBUS_EVENT_ID_RESULT(textInputElem, parent, UiCanvasBus, CreateChildElement, name);
}
else
{
EBUS_EVENT_ID_RESULT(textInputElem, parent, UiElementBus, CreateChildElement, name);
}
AZ::EntityId textInputId = textInputElem->GetId();
// Set up the text input element
{
CreateComponent(textInputElem, LyShine::UiTransform2dComponentUuid);
CreateComponent(textInputElem, LyShine::UiImageComponentUuid);
CreateComponent(textInputElem, LyShine::UiTextInputComponentUuid);
AZ_Assert(UiTransform2dBus::FindFirstHandler(textInputId), "Transform2d component missing");
EBUS_EVENT_ID(textInputId, UiTransformBus, SetScaleToDeviceMode, scaleToDeviceMode);
EBUS_EVENT_ID(textInputId, UiTransform2dBus, SetAnchors, anchors, false, false);
EBUS_EVENT_ID(textInputId, UiTransform2dBus, SetOffsets, offsets);
EBUS_EVENT_ID(textInputId, UiImageBus, SetColor, baseColor);
EBUS_EVENT_ID(textInputId, UiInteractableStatesBus, SetStateColor, UiInteractableStatesInterface::StateHover, textInputId, selectedColor);
EBUS_EVENT_ID(textInputId, UiInteractableStatesBus, SetStateAlpha, UiInteractableStatesInterface::StateHover, textInputId, selectedColor.GetA());
EBUS_EVENT_ID(textInputId, UiInteractableStatesBus, SetStateColor, UiInteractableStatesInterface::StatePressed, textInputId, pressedColor);
EBUS_EVENT_ID(textInputId, UiInteractableStatesBus, SetStateAlpha, UiInteractableStatesInterface::StatePressed, textInputId, pressedColor.GetA());
EBUS_EVENT_ID(textInputId, UiImageBus, SetSpritePathname, "UI/Textures/Prefab/textinput_normal.sprite");
EBUS_EVENT_ID(textInputId, UiImageBus, SetImageType, UiImageInterface::ImageType::Sliced);
EBUS_EVENT_ID(textInputId, UiInteractableStatesBus, SetStateSpritePathname, UiInteractableStatesInterface::StateHover, textInputId, "UI/Textures/Prefab/textinput_hover.sprite");
EBUS_EVENT_ID(textInputId, UiInteractableStatesBus, SetStateSpritePathname, UiInteractableStatesInterface::StateDisabled, textInputId, "UI/Textures/Prefab/textinput_disabled.sprite");
}
// Create the text element (what the user will type)
AZ::EntityId textElemId = CreateText("Text", false, textInputId,
UiTransform2dInterface::Anchors(0.0f, 0.0f, 1.0f, 1.0f),
UiTransform2dInterface::Offsets(5.0f, 5.0f, -5.0f, -5.00f),
text, textColor, IDraw2d::HAlign::Center, IDraw2d::VAlign::Center);
// reduce the font size
EBUS_EVENT_ID(textElemId, UiTextBus, SetFontSize, 24.0f);
// now link the textInputComponent to the child text entity
EBUS_EVENT_ID(textInputId, UiTextInputBus, SetTextEntity, textElemId);
// Create the placeholder text element (what appears before any text is typed)
AZ::EntityId placeHolderElemId = CreateText("PlaceholderText", false, textInputId,
UiTransform2dInterface::Anchors(0.0f, 0.0f, 1.0f, 1.0f),
UiTransform2dInterface::Offsets(5.0f, 5.0f, -5.0f, -5.00f),
placeHolderText, placeHolderColor, IDraw2d::HAlign::Center, IDraw2d::VAlign::Center);
// reduce the font size
EBUS_EVENT_ID(placeHolderElemId, UiTextBus, SetFontSize, 24.0f);
// now link the textInputComponent to the child placeholder text entity
EBUS_EVENT_ID(textInputId, UiTextInputBus, SetPlaceHolderTextEntity, placeHolderElemId);
// Trigger all InGamePostActivate
EBUS_EVENT_ID(textInputId, UiInitializationBus, InGamePostActivate);
EBUS_EVENT_ID(textElemId, UiInitializationBus, InGamePostActivate);
EBUS_EVENT_ID(placeHolderElemId, UiInitializationBus, InGamePostActivate);
return textInputId;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
AZ::EntityId LyShineExamplesCppExample::CreateImage(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
AZStd::string spritePath, UiImageInterface::ImageType imageType, AZ::Color color,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode)
{
// Create the image element
AZ::Entity* image = nullptr;
if (atRoot)
{
EBUS_EVENT_ID_RESULT(image, parent, UiCanvasBus, CreateChildElement, name);
}
else
{
EBUS_EVENT_ID_RESULT(image, parent, UiElementBus, CreateChildElement, name);
}
AZ::EntityId imageId = image->GetId();
// Set up the image element
{
CreateComponent(image, LyShine::UiTransform2dComponentUuid);
CreateComponent(image, LyShine::UiImageComponentUuid);
AZ_Assert(UiTransform2dBus::FindFirstHandler(imageId), "Transform2d component missing");
EBUS_EVENT_ID(imageId, UiTransformBus, SetScaleToDeviceMode, scaleToDeviceMode);
EBUS_EVENT_ID(imageId, UiTransform2dBus, SetAnchors, anchors, false, false);
EBUS_EVENT_ID(imageId, UiTransform2dBus, SetOffsets, offsets);
EBUS_EVENT_ID(imageId, UiImageBus, SetColor, color);
EBUS_EVENT_ID(imageId, UiImageBus, SetSpritePathname, spritePath);
EBUS_EVENT_ID(imageId, UiImageBus, SetImageType, imageType);
}
// Trigger all InGamePostActivate
EBUS_EVENT_ID(imageId, UiInitializationBus, InGamePostActivate);
return imageId;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void LyShineExamplesCppExample::UpdateHealth(int change)
{
// Max health is 10, min health is 0
m_health = AZStd::max(0, AZStd::min(10, m_health + change));
// Update the health bar accordingly
UiTransform2dInterface::Offsets newOffsets = m_maxHealthBarOffsets;
float healthFraction = m_health / 10.f;
newOffsets.m_right = m_maxHealthBarOffsets.m_left + (m_maxHealthBarOffsets.m_right - m_maxHealthBarOffsets.m_left) * healthFraction;
EBUS_EVENT_ID(m_healthBar, UiTransform2dBus, SetOffsets, newOffsets);
}
}
@@ -0,0 +1,116 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Slice/SliceAsset.h>
#include <LyShine/IDraw2d.h>
#include <LyShine/Bus/UiCanvasBus.h>
#include <LyShine/Bus/UiTransform2dBus.h>
#include <LyShine/Bus/UiImageBus.h>
#include <LyShine/Bus/UiButtonBus.h>
#include <LyShineExamples/LyShineExamplesCppExampleBus.h>
namespace LyShineExamples
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//! Class for demonstrating how to programmatically create a canvas from scratch in C++
//! The created canvas shows a few examples of interactable elements (a button, a checkbox, and a
//! textInput) as well as a very simple example of custom behavior (a small health system with a
//! health bar that can be damaged / healed through two buttons).
class LyShineExamplesCppExample
: protected LyShineExamplesCppExampleBus::Handler
, public UiButtonNotificationBus::MultiHandler
{
public: // member functions
LyShineExamplesCppExample();
~LyShineExamplesCppExample();
// LyShineExamplesCppExampleBus
void CreateCanvas() override;
void DestroyCanvas() override;
// ~LyShineExamplesCppExampleBus
// UiButtonNotificationBus
void OnButtonClick() override;
// ~UiButtonNotificationBus
static void Reflect(AZ::ReflectContext* context);
private: // member functions
AZ_DISABLE_COPY_MOVE(LyShineExamplesCppExample);
//! Create the background image
AZ::EntityId CreateBackground();
//! Create elements from the ground up
void CreateElementsExample(AZ::EntityId foregroundId);
//! Create elements with programmatic behavior
void CreateBehaviorExample(AZ::EntityId foregroundId);
//! Creates a component
void CreateComponent(AZ::Entity* entity, const AZ::Uuid& componentTypeId);
//! Creates a button element
AZ::EntityId CreateButton(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
const char* text, AZ::Color baseColor, AZ::Color selectedColor, AZ::Color pressedColor,
AZ::Color textColor, UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode);
//! Creates a checkbox element
AZ::EntityId CreateCheckbox(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
const char* text, AZ::Color baseColor, AZ::Color selectedColor, AZ::Color pressedColor,
AZ::Color checkColor, AZ::Color textColor,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode = UiTransformInterface::ScaleToDeviceMode::None);
//! Creates a text element
AZ::EntityId CreateText(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
const char* text, AZ::Color textColor, IDraw2d::HAlign hAlign, IDraw2d::VAlign vAlign,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode = UiTransformInterface::ScaleToDeviceMode::None);
//! Creates a text input element
AZ::EntityId CreateTextInput(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
const char* text, const char* placeHolderText,
AZ::Color baseColor, AZ::Color selectedColor, AZ::Color pressedColor,
AZ::Color textColor, AZ::Color placeHolderColor,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode = UiTransformInterface::ScaleToDeviceMode::None);
//! Creates an image element
AZ::EntityId CreateImage(const char* name, bool atRoot, AZ::EntityId parent,
UiTransform2dInterface::Anchors anchors, UiTransform2dInterface::Offsets offsets,
AZStd::string spritePath, UiImageInterface::ImageType imageType, AZ::Color color,
UiTransformInterface::ScaleToDeviceMode scaleToDeviceMode = UiTransformInterface::ScaleToDeviceMode::None);
//! Change the health by change amount and update the health bar
void UpdateHealth(int change);
private: // data
AZ::EntityId m_canvasId;
AZ::EntityId m_damageButton;
AZ::EntityId m_healButton;
AZ::EntityId m_destroyButton;
AZ::EntityId m_healthBar;
UiTransform2dInterface::Offsets m_maxHealthBarOffsets;
int m_health;
};
}
@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/EBus/EBus.h>
namespace LyShineExamples
{
class UiDynamicContentDatabase;
class LyShineExamplesInternal
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
// Public functions
//! Get the UiDynamicContentDatabase. It is gauranteed to be created when the
//! gem system component is activated.
virtual UiDynamicContentDatabase* GetUiDynamicContentDatabase() = 0;
};
using LyShineExamplesInternalBus = AZ::EBus<LyShineExamplesInternal>;
} // namespace LyShineExamples
@@ -0,0 +1,55 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
#include "LyShineExamplesSystemComponent.h"
#include "UiTestScrollBoxDataProviderComponent.h"
#include "UiCustomImageComponent.h"
#include <IGem.h>
namespace LyShineExamples
{
class LyShineExamplesModule
: public CryHooksModule
{
public:
AZ_RTTI(LyShineExamplesModule, "{BC028F50-D2C4-4A71-84D1-F1BDC727019A}", CryHooksModule);
LyShineExamplesModule()
: CryHooksModule()
{
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
LyShineExamplesSystemComponent::CreateDescriptor(),
UiTestScrollBoxDataProviderComponent::CreateDescriptor(),
UiCustomImageComponent::CreateDescriptor(),
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
return AZ::ComponentTypeList{
azrtti_typeid<LyShineExamplesSystemComponent>(),
};
}
};
}
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
AZ_DECLARE_MODULE_CLASS(Gem_LyShineExamples, LyShineExamples::LyShineExamplesModule)
@@ -0,0 +1,127 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
#include "LyShineExamplesSerialize.h"
#include <LyShine/UiSerializeHelpers.h>
#include <LyShineExamples/UiCustomImageBus.h>
#include <AzCore/RTTI/BehaviorContext.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
// NAMESPACE FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace LyShineExamplesSerialize
{
//////////////////////////////////////////////////////////////////////////
void UVCoordsScriptConstructor(UiCustomImageInterface::UVRect* thisPtr, AZ::ScriptDataContext& dc)
{
int numArgs = dc.GetNumArguments();
const int noArgsGiven = 0;
const int allArgsGiven = 4;
switch (numArgs)
{
case noArgsGiven:
{
*thisPtr = UiCustomImageInterface::UVRect();
}
break;
case allArgsGiven:
{
if (dc.IsNumber(0) && dc.IsNumber(1) && dc.IsNumber(2) && dc.IsNumber(3))
{
float left = 0;
float top = 0;
float right = 0;
float bottom = 0;
dc.ReadArg(0, left);
dc.ReadArg(1, top);
dc.ReadArg(2, right);
dc.ReadArg(3, bottom);
*thisPtr = UiCustomImageInterface::UVRect(left, top, right, bottom);
}
else
{
dc.GetScriptContext()->Error(AZ::ScriptContext::ErrorType::Error, true, "When providing 4 arguments to UVCoords(), all must be numbers!");
}
}
break;
default:
{
dc.GetScriptContext()->Error(AZ::ScriptContext::ErrorType::Error, true, "UVCoords() accepts only 0 or 4 arguments, not %d!", numArgs);
}
break;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void ReflectTypes(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
// Serialize the UVs struct
{
if (serializeContext)
{
serializeContext->Class<UiCustomImageInterface::UVRect>()->
Field("left", &UiCustomImageInterface::UVRect::m_left)->
Field("top", &UiCustomImageInterface::UVRect::m_top)->
Field("right", &UiCustomImageInterface::UVRect::m_right)->
Field("bottom", &UiCustomImageInterface::UVRect::m_bottom);
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
auto editInfo = ec->Class<UiCustomImageInterface::UVRect>(0, "");
editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "UVRect")
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::ShowChildrenOnly);
editInfo->DataElement(0, &UiCustomImageInterface::UVRect::m_left, "Left", "The lower X UV coordinate.");
editInfo->DataElement(0, &UiCustomImageInterface::UVRect::m_top, "Top", "The higher Y UV coordinate.");
editInfo->DataElement(0, &UiCustomImageInterface::UVRect::m_right, "Right", "The higher X UV coordinate.");
editInfo->DataElement(0, &UiCustomImageInterface::UVRect::m_bottom, "Bottom", "The lower Y UV coordinate.");
}
}
if (behaviorContext)
{
behaviorContext->Class<UiCustomImageInterface::UVRect>("UVCoords")
->Constructor<>()
->Constructor<float, float, float, float>()
->Attribute(AZ::Script::Attributes::Storage, AZ::Script::Attributes::StorageType::Value)
->Attribute(AZ::Script::Attributes::ConstructorOverride, &UVCoordsScriptConstructor)
->Property("left", BehaviorValueProperty(&UiCustomImageInterface::UVRect::m_left))
->Property("top", BehaviorValueProperty(&UiCustomImageInterface::UVRect::m_top))
->Property("right", BehaviorValueProperty(&UiCustomImageInterface::UVRect::m_right))
->Property("bottom", BehaviorValueProperty(&UiCustomImageInterface::UVRect::m_bottom))
->Method("SetLeft", [](UiCustomImageInterface::UVRect* thisPtr, float left) { thisPtr->m_left = left; })
->Method("SetTop", [](UiCustomImageInterface::UVRect* thisPtr, float top) { thisPtr->m_top = top; })
->Method("SetRight", [](UiCustomImageInterface::UVRect* thisPtr, float right) { thisPtr->m_right = right; })
->Method("SetBottom", [](UiCustomImageInterface::UVRect* thisPtr, float bottom) { thisPtr->m_bottom= bottom; })
->Method("SetUVCoords", [](UiCustomImageInterface::UVRect* thisPtr, float left, float top, float right, float bottom)
{
thisPtr->m_left = left;
thisPtr->m_top = top;
thisPtr->m_right = right;
thisPtr->m_bottom = bottom;
});
}
}
}
}
@@ -0,0 +1,21 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <LyShine/IDraw2d.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace LyShineExamplesSerialize
{
//! Define the UI types for the AZ Serialize system
void ReflectTypes(AZ::ReflectContext* context);
}
@@ -0,0 +1,96 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include "LyShineExamplesSystemComponent.h"
#include "LyShineExamplesSerialize.h"
#include "UiDynamicContentDatabase.h"
#include "LyShineExamplesCppExample.h"
namespace LyShineExamples
{
void LyShineExamplesSystemComponent::Reflect(AZ::ReflectContext* context)
{
LyShineExamplesSerialize::ReflectTypes(context);
UiDynamicContentDatabase::Reflect(context);
LyShineExamplesCppExample::Reflect(context);
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<LyShineExamplesSystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<LyShineExamplesSystemComponent>("LyShineExamples", "This provides example code using LyShine and code used by sample UI canvases and levels")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "UI")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
}
void LyShineExamplesSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("LyShineExamplesService"));
}
void LyShineExamplesSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("LyShineExamplesService"));
}
void LyShineExamplesSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("LyShineService"));;
}
void LyShineExamplesSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
(void)dependent;
}
UiDynamicContentDatabase* LyShineExamplesSystemComponent::GetUiDynamicContentDatabase()
{
return m_uiDynamicContentDatabase;
}
void LyShineExamplesSystemComponent::Init()
{
}
void LyShineExamplesSystemComponent::Activate()
{
m_uiDynamicContentDatabase = new UiDynamicContentDatabase();
m_cppExample = new LyShineExamplesCppExample();
LyShineExamplesRequestBus::Handler::BusConnect();
LyShineExamplesInternalBus::Handler::BusConnect();
}
void LyShineExamplesSystemComponent::Deactivate()
{
LyShineExamplesRequestBus::Handler::BusDisconnect();
LyShineExamplesInternalBus::Handler::BusDisconnect();
SAFE_DELETE(m_uiDynamicContentDatabase);
SAFE_DELETE(m_cppExample);
}
}
@@ -0,0 +1,60 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <LyShineExamples/LyShineExamplesBus.h>
#include <LyShineExamplesCppExample.h>
#include "LyShineExamplesInternalBus.h"
namespace LyShineExamples
{
class LyShineExamplesSystemComponent
: public AZ::Component
, protected LyShineExamplesRequestBus::Handler
, protected LyShineExamplesInternalBus::Handler
{
public:
AZ_COMPONENT(LyShineExamplesSystemComponent, "{045500EA-BB1D-40CE-8811-F1DF6A340557}");
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent);
protected:
////////////////////////////////////////////////////////////////////////
// LyShineExamplesRequestBus interface implementation
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// LyShineExamplesInternalBus interface implementation
UiDynamicContentDatabase* GetUiDynamicContentDatabase() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
private: // data
UiDynamicContentDatabase* m_uiDynamicContentDatabase = nullptr;
LyShineExamplesCppExample* m_cppExample = nullptr;
};
}
@@ -0,0 +1,13 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <platform.h> // Many CryCommon files require that this is included first.
@@ -0,0 +1,456 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
#include "UiCustomImageComponent.h"
#include <LyShineExamples/UiCustomImageBus.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <IRenderer.h>
#include <LyShine/IDraw2d.h>
#include <LyShine/ISprite.h>
#include <LyShine/Bus/UiElementBus.h>
#include <LyShine/Bus/UiCanvasBus.h>
#include <LyShine/Bus/UiTransformBus.h>
namespace LyShineExamples
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
UiCustomImageComponent::UiCustomImageComponent()
: m_color(1.f, 1.f, 1.f, 1.f)
, m_alpha(1.f)
, m_sprite(nullptr)
, m_uvs(0, 0, 1, 1)
, m_clamp(true)
, m_overrideColor(m_color)
, m_overrideAlpha(m_alpha)
, m_overrideSprite(nullptr)
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
UiCustomImageComponent::~UiCustomImageComponent()
{
SAFE_RELEASE(m_sprite);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::ResetOverrides()
{
m_overrideColor = m_color;
m_overrideAlpha = m_alpha;
m_overrideSprite = nullptr;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetOverrideColor(const AZ::Color& color)
{
m_overrideColor.Set(color.GetAsVector3());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetOverrideAlpha(float alpha)
{
m_overrideAlpha = alpha;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetOverrideSprite(ISprite* sprite, AZ::u32 /* cellIndex */)
{
m_overrideSprite = sprite;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::Render(LyShine::IRenderGraph* renderGraph)
{
// get fade value (tracked by UiRenderer) and compute the desired alpha for the image
float fade = renderGraph->GetAlphaFade();
float desiredAlpha = m_overrideAlpha * fade;
uint8 desiredPackedAlpha = static_cast<uint8>(desiredAlpha * 255.0f);
// if desired alpha is zero then no need to do any more
if (desiredPackedAlpha == 0)
{
return;
}
ISprite* sprite = (m_overrideSprite) ? m_overrideSprite : m_sprite;
ITexture* texture = (sprite) ? sprite->GetTexture() : nullptr;
if (!texture)
{
// if there is no texture we will just use a white texture
texture = gEnv->pRenderer->EF_GetTextureByID(gEnv->pRenderer->GetWhiteTextureId());
}
if (m_isRenderCacheDirty)
{
RenderToCache(renderGraph);
m_isRenderCacheDirty = false;
}
// Render cache is now valid - render using the cache
// 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
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;
}
}
bool isTextureSRGB = false;
bool isTexturePremultipliedAlpha = false; // we are not rendering from a render target with alpha in it
LyShine::BlendMode blendMode = LyShine::BlendMode::Normal;
renderGraph->AddPrimitive(&m_cachedPrimitive, texture, m_clamp, isTextureSRGB, isTexturePremultipliedAlpha, blendMode);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
AZ::Color UiCustomImageComponent::GetColor()
{
return AZ::Color::CreateFromVector3AndFloat(m_color.GetAsVector3(), m_alpha);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetColor(const AZ::Color& color)
{
m_color.Set(color.GetAsVector3());
m_alpha = color.GetA();
m_overrideColor = m_color;
m_overrideAlpha = m_alpha;
MarkRenderCacheDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ISprite* UiCustomImageComponent::GetSprite()
{
return m_sprite;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetSprite(ISprite* sprite)
{
if (m_sprite)
{
m_sprite->Release();
m_spritePathname.SetAssetPath("");
}
m_sprite = sprite;
if (m_sprite)
{
m_sprite->AddRef();
m_spritePathname.SetAssetPath(m_sprite->GetPathname().c_str());
}
MarkRenderGraphDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
AZStd::string UiCustomImageComponent::GetSpritePathname()
{
return m_spritePathname.GetAssetPath();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetSpritePathname(AZStd::string spritePath)
{
m_spritePathname.SetAssetPath(spritePath.c_str());
MarkRenderGraphDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
UiCustomImageInterface::UVRect UiCustomImageComponent::GetUVs()
{
return m_uvs;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetUVs(UiCustomImageInterface::UVRect uvs)
{
m_uvs = uvs;
MarkRenderCacheDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool UiCustomImageComponent::GetClamp()
{
return m_clamp;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::SetClamp(bool clamp)
{
m_clamp = clamp;
MarkRenderGraphDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::OnCanvasSpaceRectChanged(AZ::EntityId /*entityId*/, const UiTransformInterface::Rect& /*oldRect*/, const UiTransformInterface::Rect& /*newRect*/)
{
MarkRenderCacheDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::OnTransformToViewportChanged()
{
MarkRenderCacheDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC STATIC MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
// Serialize this component
if (serializeContext)
{
serializeContext->Class<UiCustomImageComponent, AZ::Component>()
->Field("SpritePath", &UiCustomImageComponent::m_spritePathname)
->Field("Color", &UiCustomImageComponent::m_color)
->Field("Alpha", &UiCustomImageComponent::m_alpha)
->Field("UVCoords", &UiCustomImageComponent::m_uvs)
->Field("Clamp", &UiCustomImageComponent::m_clamp);
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
auto editInfo = ec->Class<UiCustomImageComponent>("Custom Image", "A visual component to draw a rectangle with an optional sprite/texture");
editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiImage.png")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiImage.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0))
->Attribute(AZ::Edit::Attributes::AutoExpand, true);
editInfo->DataElement("Sprite", &UiCustomImageComponent::m_spritePathname, "Sprite path", "The sprite path. Can be overridden by another component such as an interactable.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiCustomImageComponent::OnSpritePathnameChange);
editInfo->DataElement(AZ::Edit::UIHandlers::Color, &UiCustomImageComponent::m_color, "Color", "The color tint for the image. Can be overridden by another component such as an interactable.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiCustomImageComponent::OnColorChange);
editInfo->DataElement(AZ::Edit::UIHandlers::Slider, &UiCustomImageComponent::m_alpha, "Alpha", "The transparency. Can be overridden by another component such as an interactable.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiCustomImageComponent::OnColorChange)
->Attribute(AZ::Edit::Attributes::Min, 0.0f)
->Attribute(AZ::Edit::Attributes::Max, 1.0f);
editInfo->DataElement(0, &UiCustomImageComponent::m_uvs, "UV Rect", "The UV coordinates of the rectangle for rendering the texture.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiCustomImageComponent::OnRenderSettingChange)
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ_CRC("RefreshValues", 0x28e720d4))
->Attribute(AZ::Edit::Attributes::Visibility, AZ::Edit::PropertyVisibility::Show); // needed because sub-elements are hidden
editInfo->DataElement(AZ::Edit::UIHandlers::CheckBox, &UiCustomImageComponent::m_clamp, "Clamp", "Whether the image should be clamped or not.")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &UiCustomImageComponent::OnRenderSettingChange)
->Attribute(AZ::Edit::Attributes::ChangeNotify, AZ_CRC("RefreshValues", 0x28e720d4));
}
}
if (behaviorContext)
{
behaviorContext->EBus<UiCustomImageBus>("UiCustomImageBus")
->Event("GetColor", &UiCustomImageBus::Events::GetColor)
->Event("SetColor", &UiCustomImageBus::Events::SetColor)
->Event("GetSpritePathname", &UiCustomImageBus::Events::GetSpritePathname)
->Event("SetSpritePathname", &UiCustomImageBus::Events::SetSpritePathname)
->Event("GetUVs", &UiCustomImageBus::Events::GetUVs)
->Event("SetUVs", &UiCustomImageBus::Events::SetUVs)
->Event("GetClamp", &UiCustomImageBus::Events::GetClamp)
->Event("SetClamp", &UiCustomImageBus::Events::SetClamp);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PROTECTED MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::Init()
{
// If this is called from RC.exe for example these pointers will not be set. In that case
// we only need to be able to load, init and save the component. It will never be
// activated.
if (!(gEnv && gEnv->pLyShine))
{
return;
}
// Load our sprite from the path at the beginning of the game
if (!m_sprite)
{
if (!m_spritePathname.GetAssetPath().empty())
{
m_sprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str());
}
}
m_overrideColor = m_color;
m_overrideAlpha = m_alpha;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::Activate()
{
UiVisualBus::Handler::BusConnect(m_entity->GetId());
UiRenderBus::Handler::BusConnect(m_entity->GetId());
UiCustomImageBus::Handler::BusConnect(m_entity->GetId());
UiTransformChangeNotificationBus::Handler::BusConnect(m_entity->GetId());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::Deactivate()
{
UiVisualBus::Handler::BusDisconnect();
UiRenderBus::Handler::BusDisconnect();
UiCustomImageBus::Handler::BusDisconnect();
UiTransformChangeNotificationBus::Handler::BusDisconnect();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::RenderToCache(LyShine::IRenderGraph* renderGraph)
{
UiTransformInterface::RectPoints points;
EBUS_EVENT_ID(GetEntityId(), UiTransformBus, GetViewportSpacePoints, points);
// points are a clockwise quad
const AZ::Vector2 uvs[4] = {
AZ::Vector2(m_uvs.m_left, m_uvs.m_top), AZ::Vector2(m_uvs.m_right, m_uvs.m_top)
, AZ::Vector2(m_uvs.m_right, m_uvs.m_bottom), AZ::Vector2(m_uvs.m_left, m_uvs.m_bottom)
};
RenderSingleQuad(renderGraph, points.pt, uvs);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::RenderSingleQuad(LyShine::IRenderGraph* renderGraph, const AZ::Vector2* positions, const AZ::Vector2* uvs)
{
float fade = renderGraph->GetAlphaFade();
float desiredAlpha = m_overrideAlpha * fade;
AZ::Color color = AZ::Color::CreateFromVector3AndFloat(m_overrideColor.GetAsVector3(), desiredAlpha);
color = color.GammaToLinear(); // the colors are specified in sRGB but we want linear colors in the shader
uint32 packedColor = (color.GetA8() << 24) | (color.GetR8() << 16) | (color.GetG8() << 8) | color.GetB8();
IDraw2d::Rounding pixelRounding = IsPixelAligned() ? IDraw2d::Rounding::Nearest : IDraw2d::Rounding::None;
const int numVertices = 4;
if (numVertices != m_cachedPrimitive.m_numVertices)
{
if (m_cachedPrimitive.m_vertices)
{
delete [] m_cachedPrimitive.m_vertices;
}
m_cachedPrimitive.m_vertices = new SVF_P2F_C4B_T2F_F4B[numVertices];
m_cachedPrimitive.m_numVertices = numVertices;
}
// points are a clockwise quad
for (int i = 0; i < numVertices; ++i)
{
AZ::Vector2 pos = Draw2dHelper::RoundXY(positions[i], pixelRounding);
m_cachedPrimitive.m_vertices[i].xy = Vec2(pos.GetX(), pos.GetY());
m_cachedPrimitive.m_vertices[i].color.dcolor = packedColor;
m_cachedPrimitive.m_vertices[i].st = Vec2(uvs[i].GetX(), uvs[i].GetY());
m_cachedPrimitive.m_vertices[i].texIndex = 0;
m_cachedPrimitive.m_vertices[i].texHasColorChannel = 1;
m_cachedPrimitive.m_vertices[i].texIndex2 = 0;
m_cachedPrimitive.m_vertices[i].pad = 0;
}
static uint16 indices[6] = { 0, 1, 2, 2, 3, 0 };
m_cachedPrimitive.m_numIndices = 6;
m_cachedPrimitive.m_indices = indices;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool UiCustomImageComponent::IsPixelAligned()
{
AZ::EntityId canvasEntityId;
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
bool isPixelAligned = true;
EBUS_EVENT_ID_RESULT(isPixelAligned, canvasEntityId, UiCanvasBus, GetIsPixelAligned);
return isPixelAligned;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::OnSpritePathnameChange()
{
ISprite* newSprite = nullptr;
if (!m_spritePathname.GetAssetPath().empty())
{
// Load the new texture.
newSprite = gEnv->pLyShine->LoadSprite(m_spritePathname.GetAssetPath().c_str());
}
SAFE_RELEASE(m_sprite);
m_sprite = newSprite;
MarkRenderGraphDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::OnColorChange()
{
m_overrideColor = m_color;
m_overrideAlpha = m_alpha;
MarkRenderCacheDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::OnRenderSettingChange()
{
MarkRenderCacheDirty();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::MarkRenderCacheDirty()
{
if (!m_isRenderCacheDirty)
{
m_isRenderCacheDirty = true;
MarkRenderGraphDirty();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiCustomImageComponent::MarkRenderGraphDirty()
{
// tell the canvas to invalidate the render graph (never want to do this while rendering)
AZ::EntityId canvasEntityId;
EBUS_EVENT_ID_RESULT(canvasEntityId, GetEntityId(), UiElementBus, GetCanvasEntityId);
EBUS_EVENT_ID(canvasEntityId, UiCanvasComponentImplementationBus, MarkRenderGraphDirty);
}
}
@@ -0,0 +1,146 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <LyShine/Bus/UiVisualBus.h>
#include <LyShine/Bus/UiRenderBus.h>
#include <LyShine/Bus/UiTransformBus.h>
#include <LyShine/UiComponentTypes.h>
#include <LyShine/IRenderGraph.h>
#include <LyShineExamples/UiCustomImageBus.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Math/Vector2.h>
#include <LmbrCentral/Rendering/MaterialAsset.h>
class ITexture;
class ISprite;
namespace LyShineExamples
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//! This component is an example of how to implement a custom component. It is a simple image
//! component that takes UV coordinates instead of image and sprite types.
class UiCustomImageComponent
: public AZ::Component
, public UiVisualBus::Handler
, public UiRenderBus::Handler
, public UiCustomImageBus::Handler
, public UiTransformChangeNotificationBus::Handler
{
public: // member functions
AZ_COMPONENT(UiCustomImageComponent, "{466B78EC-A85C-4112-A89D-FF2D7EDE650E}", AZ::Component);
UiCustomImageComponent();
~UiCustomImageComponent() override;
// UiVisualInterface
void ResetOverrides() override;
void SetOverrideColor(const AZ::Color& color) override;
void SetOverrideAlpha(float alpha) override;
void SetOverrideSprite(ISprite* sprite, AZ::u32 cellIndex = 0) override;
// ~UiVisualInterface
// UiRenderInterface
void Render(LyShine::IRenderGraph* renderGraph) override;
// ~UiRenderInterface
// UiCustomImageInterface
AZ::Color GetColor() override;
void SetColor(const AZ::Color& color) override;
ISprite* GetSprite() override;
void SetSprite(ISprite* sprite) override;
AZStd::string GetSpritePathname() override;
void SetSpritePathname(AZStd::string spritePath) override;
UVRect GetUVs() override;
void SetUVs(UVRect uvs) override;
bool GetClamp() override;
void SetClamp(bool clamp) override;
// ~UiCustomImageInterface
// UiTransformChangeNotification
void OnCanvasSpaceRectChanged(AZ::EntityId entityId, const UiTransformInterface::Rect& oldRect, const UiTransformInterface::Rect& newRect) override;
void OnTransformToViewportChanged() override;
// ~UiTransformChangeNotification
private: // static member functions
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("UiVisualService", 0xa864fdf8));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("UiVisualService", 0xa864fdf8));
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("UiElementService", 0x3dca7ad4));
required.push_back(AZ_CRC("UiTransformService", 0x3a838e34));
}
static void Reflect(AZ::ReflectContext* context);
private: // member functions
void RenderToCache(LyShine::IRenderGraph* renderGraph);
void RenderSingleQuad(LyShine::IRenderGraph* renderGraph, const AZ::Vector2* positions, const AZ::Vector2* uvs);
bool IsPixelAligned();
//! ChangeNotify callback for sprite pathname change
void OnSpritePathnameChange();
//! ChangeNotify callback for color change
void OnColorChange();
//! ChangeNotify callback for other settings that need to make render cache dirty
void OnRenderSettingChange();
//! Mark the render graph as dirty, this should be done when any change is made affects the structure of the graph
void MarkRenderCacheDirty();
//! Mark the render graph as dirty, this should be done when any change is made affects the structure of the graph
void MarkRenderGraphDirty();
// AZ::Component
void Init() override;
void Activate() override;
void Deactivate() override;
// ~AZ::Component
AZ_DISABLE_COPY_MOVE(UiCustomImageComponent);
private: // data
AzFramework::SimpleAssetReference<LmbrCentral::TextureAsset> m_spritePathname;
AZ::Color m_color;
float m_alpha;
UVRect m_uvs;
bool m_clamp;
ISprite* m_sprite;
ISprite* m_overrideSprite;
AZ::Color m_overrideColor;
float m_overrideAlpha;
// cached rendering data for performance optimization
IRenderer::DynUiPrimitive m_cachedPrimitive;
bool m_isRenderCacheDirty = true;
};
}
@@ -0,0 +1,163 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
#include "UiDynamicContentDatabase.h"
#include <ISystem.h>
#include <AzCore/JSON/reader.h>
#include <AzCore/JSON/error/en.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzFramework/Archive/IArchive.h>
namespace LyShineExamples
{
UiDynamicContentDatabase::UiDynamicContentDatabase()
{
memset(m_documentParsed, 0, sizeof(m_documentParsed));
UiDynamicContentDatabaseBus::Handler::BusConnect();
}
UiDynamicContentDatabase::~UiDynamicContentDatabase()
{
UiDynamicContentDatabaseBus::Handler::BusDisconnect();
}
int UiDynamicContentDatabase::GetNumColors(ColorType colorType)
{
if (!m_documentParsed[colorType])
{
return 0;
}
const rapidjson::Value& colors = m_document[colorType]["colors"];
return colors.Size();
}
AZ::Color UiDynamicContentDatabase::GetColor(ColorType colorType, int index)
{
AZ::Color color(0.0f, 0.0f, 0.0f, 1.0f);
if (!m_documentParsed[colorType])
{
return color;
}
if (index < GetNumColors(colorType))
{
const rapidjson::Value& jsonColors = m_document[colorType]["colors"];
const rapidjson::Value& jsonColor = jsonColors[index]["color"];
color.Set(jsonColor[0].GetInt() / 255.0f, jsonColor[1].GetInt() / 255.0f, jsonColor[2].GetInt() / 255.0f, 1.0f);
}
return color;
}
AZStd::string UiDynamicContentDatabase::GetColorName(ColorType colorType, int index)
{
AZStd::string colorName;
if (!m_documentParsed[colorType])
{
return colorName;
}
if (index < GetNumColors(colorType))
{
const rapidjson::Value& colors = m_document[colorType]["colors"];
const rapidjson::Value& name = colors[index]["name"];
colorName = name.GetString();
}
return colorName;
}
AZStd::string UiDynamicContentDatabase::GetColorPrice(ColorType colorType, int index)
{
AZStd::string colorPrice;
if (!m_documentParsed[colorType])
{
return "";
}
if (index < GetNumColors(colorType))
{
const rapidjson::Value& colors = m_document[colorType]["colors"];
const rapidjson::Value& price = colors[index]["price"];
colorPrice = price.GetString();
}
return colorPrice;
}
void UiDynamicContentDatabase::Refresh(ColorType colorType, const AZStd::string& filePath)
{
AZ::IO::HandleType readHandle = gEnv->pCryPak->FOpen(filePath.c_str(), "rt");
if (readHandle == AZ::IO::InvalidHandle)
{
return;
}
size_t fileSize = gEnv->pCryPak->FGetSize(readHandle);
if (fileSize > 0)
{
AZStd::string fileBuf;
fileBuf.resize(fileSize);
size_t read = gEnv->pCryPak->FRead(fileBuf.data(), fileSize, readHandle);
m_documentParsed[colorType] = false;
rapidjson::ParseResult parseResult = m_document[colorType].Parse(fileBuf.data());
if (!parseResult)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING,
"Failed to parse content due to '%s' at offset %zd.\n",
rapidjson::GetParseError_En(parseResult.Code()), parseResult.Offset());
}
else if (!m_document[colorType].IsObject())
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING,
"Expected an object at the root.");
}
else
{
m_documentParsed[colorType] = true;
}
}
gEnv->pCryPak->FClose(readHandle);
}
void UiDynamicContentDatabase::Reflect(AZ::ReflectContext* context)
{
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
behaviorContext->Enum<(int)UiDynamicContentDatabaseInterface::ColorType::FreeColors>("eUiDynamicContentDBColorType_Free")
->Enum<(int)UiDynamicContentDatabaseInterface::ColorType::PaidColors>("eUiDynamicContentDBColorType_Paid");
behaviorContext->EBus<UiDynamicContentDatabaseBus>("UiDynamicContentDatabaseBus")
->Event("GetNumColors", &UiDynamicContentDatabaseBus::Events::GetNumColors)
->Event("GetColor", &UiDynamicContentDatabaseBus::Events::GetColor)
->Event("GetColorName", &UiDynamicContentDatabaseBus::Events::GetColorName)
->Event("GetColorPrice", &UiDynamicContentDatabaseBus::Events::GetColorPrice)
->Event("Refresh", &UiDynamicContentDatabaseBus::Events::Refresh);
}
}
} // namespace LYGame
@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Math/Color.h>
#include <AzCore/JSON/document.h>
#include <AzCore/std/string/string.h>
#include <LyShineExamples/UiDynamicContentDatabaseBus.h>
namespace LyShineExamples
{
class UiDynamicContentDatabase
: protected UiDynamicContentDatabaseBus::Handler
{
public: // member functions
UiDynamicContentDatabase();
~UiDynamicContentDatabase();
// UiDynamicContentDatabaseBus interface implementation
int GetNumColors(ColorType colorType) override;
AZ::Color GetColor(ColorType colorType, int index) override;
AZStd::string GetColorName(ColorType colorType, int index) override;
AZStd::string GetColorPrice(ColorType colorType, int index) override;
void Refresh(ColorType colorType, const AZStd::string& filePath) override;
// ~UiDynamicContentDatabaseBus
public: // static member functions
static void Reflect(AZ::ReflectContext* context);
private: // member functions
AZ_DISABLE_COPY_MOVE(UiDynamicContentDatabase);
private: // data
rapidjson::Document m_document[UiDynamicContentDatabaseInterface::ColorType::NumColorTypes];
bool m_documentParsed[UiDynamicContentDatabaseInterface::ColorType::NumColorTypes];
};
} // namespace LYGame
@@ -0,0 +1,136 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "LyShineExamples_precompiled.h"
#include "UiTestScrollBoxDataProviderComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <LyShine/Bus/UiElementBus.h>
#include <LyShine/Bus/UiTextBus.h>
#include <LyShine/Bus/UiImageBus.h>
#include "UiDynamicContentDatabase.h"
#include "LyShineExamplesInternalBus.h"
namespace LyShineExamples
{
////////////////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
UiTestScrollBoxDataProviderComponent::UiTestScrollBoxDataProviderComponent()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
UiTestScrollBoxDataProviderComponent::~UiTestScrollBoxDataProviderComponent()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////////
int UiTestScrollBoxDataProviderComponent::GetNumElements()
{
UiDynamicContentDatabase *uiDynamicContentDB = nullptr;
EBUS_EVENT_RESULT(uiDynamicContentDB, LyShineExamplesInternalBus, GetUiDynamicContentDatabase);
if (uiDynamicContentDB)
{
return uiDynamicContentDB->GetNumColors(UiDynamicContentDatabaseInterface::ColorType::PaidColors);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiTestScrollBoxDataProviderComponent::OnElementBecomingVisible(AZ::EntityId entityId, int index)
{
UiDynamicContentDatabase *uiDynamicContentDB = nullptr;
EBUS_EVENT_RESULT(uiDynamicContentDB, LyShineExamplesInternalBus, GetUiDynamicContentDatabase);
if (uiDynamicContentDB)
{
if ((index >= 0) && (index < uiDynamicContentDB->GetNumColors(UiDynamicContentDatabaseInterface::ColorType::PaidColors)))
{
AZ::Entity* entity = nullptr;
EBUS_EVENT_ID_RESULT(entity, entityId, UiElementBus, FindChildByName, "Name");
if (entity)
{
AZStd::string text = uiDynamicContentDB->GetColorName(UiDynamicContentDatabaseInterface::ColorType::PaidColors, index);
EBUS_EVENT_ID(entity->GetId(), UiTextBus, SetText, text.c_str());
}
entity = nullptr;
EBUS_EVENT_ID_RESULT(entity, entityId, UiElementBus, FindChildByName, "Price");
if (entity)
{
AZStd::string text = uiDynamicContentDB->GetColorPrice(UiDynamicContentDatabaseInterface::ColorType::PaidColors, index);
EBUS_EVENT_ID(entity->GetId(), UiTextBus, SetText, text.c_str());
}
entity = nullptr;
EBUS_EVENT_ID_RESULT(entity, entityId, UiElementBus, FindChildByName, "Icon");
if (entity)
{
AZ::Color color = uiDynamicContentDB->GetColor(UiDynamicContentDatabaseInterface::ColorType::PaidColors, index);
EBUS_EVENT_ID(entity->GetId(), UiImageBus, SetColor, color);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PROTECTED STATIC MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiTestScrollBoxDataProviderComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<UiTestScrollBoxDataProviderComponent, AZ::Component>()
->Version(1);
AZ::EditContext* ec = serializeContext->GetEditContext();
if (ec)
{
auto editInfo = ec->Class<UiTestScrollBoxDataProviderComponent>("TestScrollBoxDataProvider",
"Associates dynamic data with a dynamic scroll box");
editInfo->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/UiTestScrollBoxDataProvider.png")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/UiTestScrollBoxDataProvider.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("UI", 0x27ff46b0));
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// PROTECTED MEMBER FUNCTIONS
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiTestScrollBoxDataProviderComponent::Activate()
{
UiDynamicScrollBoxDataBus::Handler::BusConnect(GetEntityId());
UiDynamicScrollBoxElementNotificationBus::Handler::BusConnect(GetEntityId());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void UiTestScrollBoxDataProviderComponent::Deactivate()
{
UiDynamicScrollBoxDataBus::Handler::BusDisconnect();
UiDynamicScrollBoxElementNotificationBus::Handler::BusDisconnect();
}
}
@@ -0,0 +1,75 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <LyShine/Bus/UiDynamicScrollBoxBus.h>
#include <AzCore/Component/Component.h>
namespace LyShineExamples
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//! This component associates dynamic data with the dynamic scroll box in the UiComponents
//! level
class UiTestScrollBoxDataProviderComponent
: public AZ::Component
, public UiDynamicScrollBoxDataBus::Handler
, public UiDynamicScrollBoxElementNotificationBus::Handler
{
public: // member functions
AZ_COMPONENT(UiTestScrollBoxDataProviderComponent, "{C66A6BBF-D715-4876-8302-D452CC6975C8}", AZ::Component);
UiTestScrollBoxDataProviderComponent();
~UiTestScrollBoxDataProviderComponent() override;
// UiDynamicScrollBoxDataInterface
virtual int GetNumElements() override;
// ~UiDynamicScrollBoxDataInterface
// UiDynamicScrollBoxElementNotifications
virtual void OnElementBecomingVisible(AZ::EntityId entityId, int index) override;
// ~UiDynamicScrollBoxElementNotifications
protected: // static member functions
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("UiDynamicContentProviderService", 0xe25f3f73));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("UiDynamicContentProviderService", 0xe25f3f73));
}
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("UiDynamicScrollBoxService", 0x11112f1a));
required.push_back(AZ_CRC("UiElementService", 0x3dca7ad4));
required.push_back(AZ_CRC("UiTransformService", 0x3a838e34));
}
static void Reflect(AZ::ReflectContext* context);
protected: // member functions
// AZ::Component
void Activate() override;
void Deactivate() override;
// ~AZ::Component
AZ_DISABLE_COPY_MOVE(UiTestScrollBoxDataProviderComponent);
protected: // data
};
}