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,141 @@
/*
* 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 <Atom/Features/SrgSemantics.azsli>
#include <Atom/Features/PostProcessing/PostProcessUtil.azsli>
// Indicates whether to use pre-multiplied alpha
option bool o_preMultiplyAlpha;
// If true pixels with an alpha value of less than 0.5 are clipped
option bool o_alphaTest;
// If true both the texture color and diffuse color are converted from linear to sRGB color space
option bool o_srgbWrite;
// Indicates how to use the second texture indexed by a vertex (if at all)
option enum class Modulate { None, Alpha, AlphaAndColor } o_modulate;
// Each vertex can select one or two of the 16 textures bound
ShaderResourceGroup InstanceSrg : SRG_PerDraw
{
row_major float4x4 m_worldToProj;
Texture2D m_texture[16];
Sampler m_sampler[16];
};
struct VSInput
{
float2 m_position : POSITION;
float4 m_color : COLOR0;
float2 m_uv : TEXCOORD0;
uint2 m_flags : BLENDINDICES;
};
struct VSOutput
{
float4 m_position : SV_Position;
float4 m_color : COLOR0;
float2 m_uv : TEXCOORD0;
nointerpolation uint m_texIndex : COLOR1;
nointerpolation uint m_texHasColorChannel : COLOR2;
nointerpolation uint m_texIndex2 : COLOR3;
};
VSOutput MainVS(VSInput IN)
{
float4x4 worldToProj = InstanceSrg::m_worldToProj;
float4 posPS = mul(worldToProj, float4(IN.m_position, 1.0f, 1.0f));
VSOutput OUT;
OUT.m_position = posPS;
OUT.m_color = IN.m_color;
OUT.m_uv = IN.m_uv;
OUT.m_texIndex = IN.m_flags.x & 0x00FF;
OUT.m_texHasColorChannel = ((IN.m_flags.x & 0xFF00) > 0) ? 1 : 0;
OUT.m_texIndex2 = IN.m_flags.y & 0x00FF;
return OUT;
};
struct PSOutput
{
float4 m_color : SV_Target0;
};
float4 SampleTriangleTexture(int texIndex, float2 uv)
{
// We use an array of textures and an array of samplers. The nth sampler has the correct sampler state
// for the nth texture.
return InstanceSrg::m_texture[texIndex].Sample(InstanceSrg::m_sampler[texIndex], uv);
}
PSOutput MainPS(VSOutput IN)
{
PSOutput OUT;
float4 baseTex = SampleTriangleTexture(IN.m_texIndex, IN.m_uv.xy);
float4 inDiffuse = IN.m_color;
// If the texture does not have a color channel then the alpha channel will be in the R channel of the R8 texture
baseTex = (IN.m_texHasColorChannel) ? baseTex : float4(1.0f, 1.0f, 1.0f, baseTex.x);
float4 resColor = baseTex * inDiffuse;
if (o_alphaTest)
{
clip(resColor.w - 0.5);
}
// Should use srgb anytime after tonemapping
if (o_srgbWrite)
{
resColor.xyz = LinearToSRGB(resColor.xyz);
}
// Check for flag to premultiply alpha
if (o_preMultiplyAlpha)
{
// premultiply the color by the alpha. This would not be required if we had full access to the separate alpha blend mode
float preMult = resColor.w;
resColor.xyz *= preMult;
}
// If the o_modulate option is not None it means that the verts have two texture indicies. The second texture is used to
// mask the first. This is used for gradient masks.
if (o_modulate == Modulate::Alpha)
{
float4 maskTexAlpha = SampleTriangleTexture(IN.m_texIndex2, IN.m_uv.xy);
resColor.w *= maskTexAlpha.w;
if (o_alphaTest)
{
// This is a rare case that would only happen if a gradient mask is used inside the mask primitive for a stencil mask
clip(resColor.w - 0.5);
}
}
else if (o_modulate == Modulate::AlphaAndColor)
{
float4 maskTex = SampleTriangleTexture(IN.m_texIndex2, IN.m_uv.xy);
resColor *= maskTex.w;
if (o_alphaTest)
{
// This is a rare case that would only happen if a gradient mask is used inside the mask primitive for a stencil mask
clip(resColor.w - 0.5);
}
}
OUT.m_color = resColor;
return OUT;
};
@@ -0,0 +1,39 @@
{
"Source" : "LyShineUI",
"DepthStencilState" : {
"Depth" : {
"Enable" : false,
"CompareFunc" : "Always"
}
},
"RasterState" : {
"DepthClipEnable" : false,
"CullMode" : "None"
},
"BlendState" : {
"Enable" : true,
"BlendSource" : "One",
"BlendDest" : "AlphaSourceInverse",
"BlendOp" : "Add"
},
"DrawList" : "2dpass",
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -0,0 +1,23 @@
{
"Shader" : "LyShineUI.shader",
"Variants" : [
{
"StableId": 1,
"Options": {
"o_preMultiplyAlpha": "true",
"o_alphaTest": "false",
"o_srgbWrite": "true",
"o_modulate": "Modulate::None"
}
},
{
"StableId": 2,
"Options": {
"o_preMultiplyAlpha": "false",
"o_alphaTest": "false",
"o_srgbWrite": "true",
"o_modulate": "Modulate::None"
}
}
]
}
@@ -0,0 +1,107 @@
/*
* 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 <Atom/Features/SrgSemantics.azsli>
// Indicates whether the sampler should use Wrap or Clamp
option bool o_clamp;
// Indicates whether to use color channels from the texture or only the alpha channel
option bool o_useColorChannels;
ShaderResourceGroup InstanceSrg : SRG_PerDraw
{
row_major float4x4 m_worldToProj;
Texture2D m_texture;
Sampler m_wrapSampler
{
MaxAnisotropy = 16;
AddressU = Wrap;
AddressV = Wrap;
AddressW = Wrap;
};
Sampler m_clampSampler
{
MaxAnisotropy = 16;
AddressU = Clamp;
AddressV = Clamp;
AddressW = Clamp;
};
};
struct VSInput
{
float3 m_position : POSITION;
float4 m_color : COLOR0;
float2 m_uv : TEXCOORD0;
};
struct VSOutput
{
float4 m_position : SV_Position;
float4 m_color : COLOR0;
float2 m_uv : TEXCOORD0;
};
VSOutput MainVS(VSInput IN)
{
float4x4 worldToProj = InstanceSrg::m_worldToProj;
float4 posPS = mul(worldToProj, float4(IN.m_position, 1.0f));
VSOutput OUT;
OUT.m_position = posPS;
OUT.m_color = IN.m_color;
OUT.m_uv = IN.m_uv;
return OUT;
};
struct PSOutput
{
float4 m_color : SV_Target0;
};
PSOutput MainPS(VSOutput IN)
{
PSOutput OUT;
float4 tex;
if (o_clamp)
{
tex = InstanceSrg::m_texture.Sample(InstanceSrg::m_clampSampler, IN.m_uv);
}
else
{
tex = InstanceSrg::m_texture.Sample(InstanceSrg::m_wrapSampler, IN.m_uv);
}
if (!o_useColorChannels)
{
// When getting rgba from an R8 the "r" channel will be the value from the texture.
// We want to put the r in the alpha (to use as opacity) and set the rgb to 1.
// We do this rather than using an A8 texture because A8 is not supported on Vulkan.
tex.a = tex.r;
tex.rgb = 1.0f;
}
float opacity = IN.m_color.a * tex.a;
// We use pre-multiplied alpha here since it is more flexible. For example, it enables alpha-blended rendering to
// a render target and then alpha blending that render target into another render target
OUT.m_color.rgb = IN.m_color.rgb * tex.rgb * opacity;
OUT.m_color.a = opacity;
return OUT;
};
@@ -0,0 +1,39 @@
{
"Source" : "SimpleTextured",
"DepthStencilState" : {
"Depth" : {
"Enable" : false,
"CompareFunc" : "Always"
}
},
"RasterState" : {
"DepthClipEnable" : false,
"CullMode" : "None"
},
"BlendState" : {
"Enable" : true,
"BlendSource" : "One",
"BlendDest" : "AlphaSourceInverse",
"BlendOp" : "Add"
},
"DrawList" : "2dpass",
"ProgramSettings":
{
"EntryPoints":
[
{
"name": "MainVS",
"type": "Vertex"
},
{
"name": "MainPS",
"type": "Fragment"
}
]
}
}
@@ -0,0 +1,26 @@
{
"Shader" : "SimpleTextured.shader",
"Variants" : [
{
"StableId": 1,
"Options": {
"o_clamp": "true",
"o_useColorChannels": "false"
}
},
{
"StableId": 2,
"Options": {
"o_clamp": "true",
"o_useColorChannels": "true"
}
},
{
"StableId": 3,
"Options": {
"o_clamp": "false",
"o_useColorChannels": "true"
}
}
]
}
@@ -0,0 +1,12 @@
#
# 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.
#
add_subdirectory(Code)
@@ -0,0 +1,74 @@
#
# 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.
#
ly_add_target(
NAME Atom_AtomBridge.Static STATIC
NAMESPACE Gem
FILES_CMAKE
atombridge_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
COMPILE_DEFINITIONS
PRIVATE
ENABLE_ATOM_DEBUG_DISPLAY=0
BUILD_DEPENDENCIES
PUBLIC
AZ::AtomCore
AZ::AzFramework
Gem::Atom_RPI.Public
Gem::Atom_Bootstrap.Headers
Legacy::CryCommon
)
ly_add_target(
NAME Atom_AtomBridge ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
OUTPUT_NAME Gem.Atom_AtomBridge.b55b2738aa4a46c8b034fe98e6e5158b.v0.1.0
FILES_CMAKE
atombridge_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
COMPILE_DEFINITIONS
PRIVATE
ENABLE_ATOM_DEBUG_DISPLAY=0
BUILD_DEPENDENCIES
PRIVATE
Gem::Atom_AtomBridge.Static
)
if(PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME Atom_AtomBridge.Editor ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
OUTPUT_NAME Gem.Atom_AtomBridge.Editor.b55b2738aa4a46c8b034fe98e6e5158b.v0.1.0
FILES_CMAKE
atombridge_editor_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
COMPILE_DEFINITIONS
PRIVATE
EDITOR
BUILD_DEPENDENCIES
PRIVATE
AZ::AssetBuilderSDK
Gem::Atom_Utils.Static
Gem::Atom_AtomBridge.Static
)
endif()
@@ -0,0 +1,33 @@
/*
* 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/EBus/EBus.h>
namespace AZ
{
namespace AtomBridge
{
class AtomBridgeRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//////////////////////////////////////////////////////////////////////////
// Put your public methods here
};
using AtomBridgeRequestBus = AZ::EBus<AtomBridgeRequests>;
} // namespace AtomBridge
} // namespace AZ
@@ -0,0 +1,35 @@
/*
* 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/Component/ComponentBus.h>
namespace AZ
{
namespace AtomBridge
{
/// This bus is used to enable and disable the FlyCamera so that input can be used for UI etc.
class FlyCameraInputInterface
: public AZ::ComponentBus
{
public:
virtual void SetIsEnabled(bool isEnabled) = 0;
virtual bool GetIsEnabled() = 0;
public: // static member data
//! Only one component on a entity can implement the events
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
};
typedef AZ::EBus<FlyCameraInputInterface> FlyCameraInputBus;
}
}
@@ -0,0 +1,58 @@
/*
* 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 <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Module/Module.h>
#include <AtomBridgeModule.h>
#include <BuilderComponent.h>
#include "./Editor/AssetCollectionAsyncLoaderTestComponent.h"
namespace AZ
{
namespace AtomBridge
{
class EditorModule
: public Module
{
public:
AZ_RTTI(EditorModule, "{7B330394-BE9C-4BDA-9345-1A0859815982}", Module);
AZ_CLASS_ALLOCATOR(EditorModule, AZ::SystemAllocator, 0);
EditorModule()
: Module()
{
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
BuilderComponent::CreateDescriptor(),
AssetCollectionAsyncLoaderTestComponent::CreateDescriptor(),
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
AZ::ComponentTypeList components = Module::GetRequiredSystemComponents();
// components.insert(components.end(), {
// });
return components;
}
};
}
} // namespace AZ
// 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_Atom_AtomBridge.Editor, AZ::AtomBridge::EditorModule)
@@ -0,0 +1,49 @@
/*
* 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 <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Module/Module.h>
#include <AtomBridgeModule.h>
namespace AZ
{
namespace AtomBridge
{
Module::Module()
: AZ::Module()
{
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
FlyCameraInputComponent::CreateDescriptor(),
AtomBridgeSystemComponent::CreateDescriptor(),
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList Module::GetRequiredSystemComponents() const
{
return AZ::ComponentTypeList{
azrtti_typeid<AtomBridgeSystemComponent>(),
};
}
}
} // namespace AZ
#ifndef EDITOR
// 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_Atom_AtomBridge, AZ::AtomBridge::Module)
#endif
@@ -0,0 +1,39 @@
/*
* 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/Memory/SystemAllocator.h>
#include <AzCore/Module/Module.h>
#include <FlyCameraInputComponent.h>
#include <AtomBridgeSystemComponent.h>
namespace AZ
{
namespace AtomBridge
{
class Module
: public AZ::Module
{
public:
AZ_RTTI(Module, "{92196B90-6DF5-479D-8746-296AF56F0ABA}", AZ::Module);
AZ_CLASS_ALLOCATOR(Module, AZ::SystemAllocator, 0);
Module();
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList GetRequiredSystemComponents() const override;
};
}
} // namespace AZ
@@ -0,0 +1,241 @@
/*
* 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 <AtomBridgeSystemComponent.h>
#include <AtomDebugDisplayViewportInterface.h>
#include <FlyCameraInputComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Interface/Interface.h>
#include <AzFramework/API/ApplicationAPI.h>
#include <AzFramework/Entity/GameEntityContextBus.h>
#include <AzCore/Math/MatrixUtils.h>
#include <Atom/RHI/Factory.h>
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <Atom/Bootstrap/DefaultWindowBus.h>
namespace AZ
{
namespace AtomBridge
{
void AtomBridgeSystemComponent::Reflect(ReflectContext* context)
{
if (SerializeContext* serialize = azrtti_cast<SerializeContext*>(context))
{
serialize->Class<AtomBridgeSystemComponent, Component>()
->Version(0)
;
if (EditContext* ec = serialize->GetEditContext())
{
ec->Class<AtomBridgeSystemComponent>("AtomBridge", "[Description of functionality provided by this System Component]")
->ClassElement(Edit::ClassElements::EditorData, "")
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
->Attribute(Edit::Attributes::AutoExpand, true)
;
}
}
}
AtomBridgeSystemComponent::AtomBridgeSystemComponent()
{
AZ::Interface<AzFramework::AtomActiveInterface>::Register(this);
}
AtomBridgeSystemComponent::~AtomBridgeSystemComponent()
{
AZ::Interface<AzFramework::AtomActiveInterface>::Unregister(this);
}
void AtomBridgeSystemComponent::GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
}
void AtomBridgeSystemComponent::GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("AtomBridgeService", 0xdb816a99));
}
void AtomBridgeSystemComponent::GetRequiredServices(ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ::RHI::Factory::GetComponentService());
required.push_back(AZ_CRC("AssetDatabaseService", 0x3abf5601));
required.push_back(AZ_CRC("RPISystem", 0xf2add773));
required.push_back(AZ_CRC("BootstrapSystemComponent", 0xb8f32711));
}
void AtomBridgeSystemComponent::GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
}
static const AZ::Crc32 mainViewportEntityDebugDisplayId = AZ_CRC_CE("MainViewportEntityDebugDisplayId");
void AtomBridgeSystemComponent::Init()
{
#if defined(ENABLE_ATOM_DEBUG_DISPLAY) && ENABLE_ATOM_DEBUG_DISPLAY
AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusConnect();
#endif
}
void AtomBridgeSystemComponent::Activate()
{
AzFramework::Render::RenderSystemRequestBus::Handler::BusConnect();
AtomBridgeRequestBus::Handler::BusConnect();
AzFramework::Components::DeprecatedComponentsRequestBus::Handler::BusConnect();
AzFramework::GameEntityContextRequestBus::BroadcastResult(m_entityContextId, &AzFramework::GameEntityContextRequestBus::Events::GetGameEntityContextId);
AZ::Render::Bootstrap::NotificationBus::Handler::BusConnect();
}
void AtomBridgeSystemComponent::Deactivate()
{
#if defined(ENABLE_ATOM_DEBUG_DISPLAY) && ENABLE_ATOM_DEBUG_DISPLAY
AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusDisconnect();
#endif
RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get();
// Check if scene is emptry since scene might be released already when running AtomSampleViewer
if (scene)
{
auto auxGeomFP = scene->GetFeatureProcessor<RPI::AuxGeomFeatureProcessorInterface>();
if (auxGeomFP)
{
auxGeomFP->ReleaseDrawQueueForView(m_view.get());
}
}
// Don't want to leave this until our destructor because the AZ::Data::InstanceDatabase may not be valid at that point
m_view = nullptr;
AZ::Render::Bootstrap::NotificationBus::Handler::BusDisconnect();
AzFramework::Components::DeprecatedComponentsRequestBus::Handler::BusDisconnect();
AtomBridgeRequestBus::Handler::BusDisconnect();
AzFramework::Render::RenderSystemRequestBus::Handler::BusDisconnect();
}
AZStd::string AtomBridgeSystemComponent::GetRendererName() const
{
return "Other";
}
void AtomBridgeSystemComponent::EnumerateDeprecatedComponents(AzFramework::Components::DeprecatedComponentsList& list) const
{
static const AZ::Uuid legacyRenderComponentUuids[] = {
AZ::Uuid("{FC315B86-3280-4D03-B4F0-5553D7D08432}"), // EditorMeshComponent
AZ::Uuid("{4B85E77D-91F9-40C5-8FCB-B494000A9E69}"), // EditorLensFlareComponent
AZ::Uuid("{7C18B273-5BA3-4E0F-857D-1F30BD6B0733}"), // EditorLightComponent
AZ::Uuid("{00818135-138D-42AD-8657-FF3FD38D9E7A}"), // EditorPointLightComponent
AZ::Uuid("{1DE624B1-876F-4E0A-96A6-7B248FA2076F}"), // EditorAreaLightComponent
AZ::Uuid("{41928E34-B558-4559-82CF-8B5795A38CB4}"), // EditorProjectorLightComponent
AZ::Uuid("{BA3890BD-D2E7-4DB6-95CD-7E7D5525567A}"), // EditorDecalComponent
AZ::Uuid("{8DBD6035-583E-409F-AFD9-F36829A0655D}"), // EditorEnvProbeComponent
AZ::Uuid("{9C86E09D-0727-476E-A4A1-25989CDBF9C6}"), // EditorHighQualityShadowComponent
AZ::Uuid("{045C0C58-C13E-49B0-A471-D4AC5D3FC6BD}"), // EditorGeometryCacheComponent
};
const AZStd::string deprecatedString = " (DEPRECATED By Atom)";
for (const AZ::Uuid& componentUuid : legacyRenderComponentUuids)
{
auto deprecatedEntry = list.find(componentUuid);
if (deprecatedEntry == list.end())
{
list[componentUuid] = AzFramework::Components::DeprecatedInfo{ false, deprecatedString };
}
else
{
// write to deprecatedEntry->second.m_hideComponent if component should be hidden.
deprecatedEntry->second.m_deprecationString += deprecatedString;
}
}
}
void AtomBridgeSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
{
AZStd::shared_ptr<AZ::RPI::WindowContext> windowContext;
AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(windowContext, &AZ::Render::Bootstrap::DefaultWindowInterface::GetDefaultWindowContext);
if (!windowContext)
{
AZ_Warning("Atom", false, "Cannot initialize Atom because no window context is available");
return;
}
AZ::RPI::RenderPipelinePtr renderPipeline = bootstrapScene->GetDefaultRenderPipeline();
// If RenderPipeline doesn't have a default view, create a view and make it the default view.
// These settings will be overridden by the editor or game camera.
if (renderPipeline->GetDefaultView() == nullptr)
{
auto viewContextManager = AZ::Interface<RPI::ViewportContextRequestsInterface>::Get();
m_view = AZ::RPI::View::CreateView(AZ::Name("AtomSystem Default View"), RPI::View::UsageCamera);
viewContextManager->PushView(viewContextManager->GetDefaultViewportContextName(), m_view);
const auto& viewport = windowContext->GetViewport();
const float aspectRatio = viewport.m_maxX / viewport.m_maxY;
// Note: This is projection assumes a setup for reversed depth
AZ::Matrix4x4 viewToClipMatrix;
AZ::MakePerspectiveFovMatrixRH(viewToClipMatrix, AZ::Constants::HalfPi, aspectRatio, 0.1f, 100.f, true);
m_view->SetViewToClipMatrix(viewToClipMatrix);
renderPipeline = bootstrapScene->GetDefaultRenderPipeline();
renderPipeline->SetDefaultView(m_view);
auto auxGeomFP = bootstrapScene->GetFeatureProcessor<RPI::AuxGeomFeatureProcessorInterface>();
if (auxGeomFP)
{
auxGeomFP->GetOrCreateDrawQueueForView(m_view.get());
}
#if defined(ENABLE_ATOM_DEBUG_DISPLAY) && ENABLE_ATOM_DEBUG_DISPLAY
// Make default AtomDebugDisplayViewportInterface for the scene
AZStd::shared_ptr<AtomDebugDisplayViewportInterface> mainEntityDebugDisplay = AZStd::make_shared<AtomDebugDisplayViewportInterface>(mainViewportEntityDebugDisplayId);
m_activeViewportsList[mainViewportEntityDebugDisplayId] = mainEntityDebugDisplay;
#endif
}
}
void AtomBridgeSystemComponent::OnViewportContextAdded(AZ::RPI::ViewportContextPtr viewportContext)
{
#if defined(ENABLE_ATOM_DEBUG_DISPLAY) && ENABLE_ATOM_DEBUG_DISPLAY
AZStd::shared_ptr<AtomDebugDisplayViewportInterface> viewportDebugDisplay = AZStd::make_shared<AtomDebugDisplayViewportInterface>(viewportContext);
m_activeViewportsList[viewportContext->GetId()] = viewportDebugDisplay;
#endif
}
void AtomBridgeSystemComponent::OnViewportContextRemoved(AzFramework::ViewportId viewportId)
{
#if defined(ENABLE_ATOM_DEBUG_DISPLAY) && ENABLE_ATOM_DEBUG_DISPLAY
m_activeViewportsList.erase(viewportId);
#else
AZ_UNUSED(viewportId);
#endif
}
} // namespace AtomBridge
} // namespace AZ
@@ -0,0 +1,89 @@
/*
* 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/std/containers/map.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <AzCore/Component/Component.h>
#include <AzFramework/API/AtomActiveInterface.h>
#include <AzFramework/Render/RenderSystemBus.h>
#include <AzFramework/Components/DeprecatedComponentsBus.h>
#include <AtomBridge/AtomBridgeBus.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
namespace AZ
{
namespace AtomBridge
{
// forward declares
class AtomDebugDisplayViewportInterface;
class AtomBridgeSystemComponent
: public Component
, public AzFramework::AtomActiveInterface
, public AzFramework::Render::RenderSystemRequestBus::Handler
, public AzFramework::Components::DeprecatedComponentsRequestBus::Handler
, public Render::Bootstrap::NotificationBus::Handler
, protected AtomBridgeRequestBus::Handler
, public AZ::RPI::ViewportContextManagerNotificationsBus::Handler
{
public:
AZ_COMPONENT(AtomBridgeSystemComponent, "{FFB99CE4-2C9E-476D-8140-50A8A696E242}");
static void Reflect(ReflectContext* context);
AtomBridgeSystemComponent();
~AtomBridgeSystemComponent() override;
static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(ComponentDescriptor::DependencyArrayType& incompatible);
static void GetRequiredServices(ComponentDescriptor::DependencyArrayType& required);
static void GetDependentServices(ComponentDescriptor::DependencyArrayType& dependent);
protected:
// Component overrides ...
void Init() override;
void Activate() override;
void Deactivate() override;
// AzFramework::Render::RenderSystemRequestBus::Handler overrides ...
AZStd::string GetRendererName() const override;
// AzFramework::Components::DeprecatedComponentsRequestBus::Handler overrides ...
void EnumerateDeprecatedComponents(AzFramework::Components::DeprecatedComponentsList& list) const override;
// AtomBridgeRequestBus::Handler overrides ...
// (Empty)
// AZ::Render::Bootstrap::NotificationBus overrides
void OnBootstrapSceneReady(RPI::Scene* bootstrapScene) override;
// ViewportContextManagerNotificationsBus overrides
void OnViewportContextAdded(AZ::RPI::ViewportContextPtr viewportContext) override;
void OnViewportContextRemoved(AzFramework::ViewportId viewportId) override;
AzFramework::EntityContextId m_entityContextId;
RPI::ViewPtr m_view = nullptr;
AZStd::unordered_map<AzFramework::ViewportId, AZStd::shared_ptr<AtomDebugDisplayViewportInterface> > m_activeViewportsList;
};
}
} // namespace AZ
@@ -0,0 +1,999 @@
/*
* 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 <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/std/containers/array.h>
#include <AzCore/Math/Obb.h>
#include <AtomDebugDisplayViewportInterface.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <AzCore/Interface/Interface.h>
namespace AZ
{
namespace AtomBridge
{
////////////////////////////////////////////////////////////////////////
SingleColorDynamicSizeLineHelper::SingleColorDynamicSizeLineHelper(
int estimatedNumLineSegments
)
{
m_points.reserve(estimatedNumLineSegments * 2);
}
void SingleColorDynamicSizeLineHelper::AddLineSegment(
const AZ::Vector3& lineStart,
const AZ::Vector3& lineEnd
)
{
m_points.push_back(lineStart);
m_points.push_back(lineEnd);
}
void SingleColorDynamicSizeLineHelper::Draw(
AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr,
const RenderState& rendState
) const
{
if (auxGeomDrawPtr && !m_points.empty())
{
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = m_points.data();
drawArgs.m_vertCount = aznumeric_cast<uint32_t>(m_points.size());
drawArgs.m_colors = &rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_size = rendState.m_lineWidth;
drawArgs.m_opacityType = rendState.m_opacityType;
drawArgs.m_depthTest = rendState.m_depthTest;
drawArgs.m_depthWrite = rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = rendState.m_viewProjOverrideIndex;
auxGeomDrawPtr->DrawLines( drawArgs );
}
}
void SingleColorDynamicSizeLineHelper::Reset()
{
m_points.clear();
}
////////////////////////////////////////////////////////////////////////
// Partial implementation of the DebugDisplayRequestBus on Atom.
// Commented out function prototypes are waiting to be implemented.
// work tracked in [ATOM-3459]
AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr)
{
ResetRenderState();
m_viewportId = viewportContextPtr->GetId();
m_defaultInstance = false;
RPI::Scene* scene = viewportContextPtr->GetRenderScene().get();
InitInternal(scene, viewportContextPtr);
}
AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress)
{
ResetRenderState();
m_viewportId = defaultInstanceAddress;
m_defaultInstance = true;
RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get();
InitInternal(scene, nullptr);
}
void AtomDebugDisplayViewportInterface::InitInternal(RPI::Scene* scene, AZ::RPI::ViewportContextPtr viewportContextPtr)
{
if (!scene)
{
m_auxGeomPtr = nullptr;
return;
}
auto auxGeomFP = scene->GetFeatureProcessor<RPI::AuxGeomFeatureProcessorInterface>();
if (!auxGeomFP)
{
m_auxGeomPtr = nullptr;
return;
}
if (m_defaultInstance)
{
m_auxGeomPtr = auxGeomFP->GetDrawQueue();
}
else
{
m_auxGeomPtr = auxGeomFP->GetOrCreateDrawQueueForView(viewportContextPtr->GetDefaultView().get());
}
AzFramework::DebugDisplayRequestBus::Handler::BusConnect(m_viewportId);
}
AtomDebugDisplayViewportInterface::~AtomDebugDisplayViewportInterface()
{
AzFramework::DebugDisplayRequestBus::Handler::BusDisconnect(m_viewportId);
m_viewportId = AzFramework::InvalidViewportId;
m_auxGeomPtr = nullptr;
}
void AtomDebugDisplayViewportInterface::ResetRenderState()
{
m_rendState = RenderState();
for (int index = 0; index < RenderState::TransformStackSize; ++index)
{
m_rendState.m_transformStack[index] = AZ::Matrix3x4::Identity();
}
}
void AtomDebugDisplayViewportInterface::SetColor(float r, float g, float b, float a)
{
m_rendState.m_color = AZ::Color(r, g, b, a);
}
void AtomDebugDisplayViewportInterface::SetColor(const AZ::Color& color)
{
m_rendState.m_color = color;
}
void AtomDebugDisplayViewportInterface::SetColor(const AZ::Vector4& color)
{
m_rendState.m_color = AZ::Color(color);
}
void AtomDebugDisplayViewportInterface::SetAlpha(float a)
{
m_rendState.m_color.SetA(a);
if (a < 1.0f)
{
m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque;
}
else
{
m_rendState.m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Translucent;
}
}
void AtomDebugDisplayViewportInterface::DrawQuad(
const AZ::Vector3& p1,
const AZ::Vector3& p2,
const AZ::Vector3& p3,
const AZ::Vector3& p4)
{
if (m_auxGeomPtr)
{
AZ::Vector3 wsPoints[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) };
AZ::Vector3 triangles[6];
triangles[0] = wsPoints[0];
triangles[1] = wsPoints[1];
triangles[2] = wsPoints[2];
triangles[3] = wsPoints[2];
triangles[4] = wsPoints[3];
triangles[5] = wsPoints[0];
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = triangles;
drawArgs.m_vertCount = 6;
drawArgs.m_colors = &m_rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawTriangles(drawArgs);
}
}
// void DrawQuad(float width, float height) override
// void DrawWireQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override;
// void DrawWireQuad(float width, float height) override;
void AtomDebugDisplayViewportInterface::DrawQuadGradient(
const AZ::Vector3& p1,
const AZ::Vector3& p2,
const AZ::Vector3& p3,
const AZ::Vector3& p4,
const AZ::Vector4& firstColor,
const AZ::Vector4& secondColor)
{
if (m_auxGeomPtr)
{
AZ::Vector3 wsPoints[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) };
AZ::Vector3 triangles[6];
AZ::Color colors[6];
triangles[0] = wsPoints[0]; colors[0] = firstColor;
triangles[1] = wsPoints[1]; colors[1] = firstColor;
triangles[2] = wsPoints[2]; colors[2] = secondColor;
triangles[3] = wsPoints[2]; colors[3] = secondColor;
triangles[4] = wsPoints[3]; colors[4] = secondColor;
triangles[5] = wsPoints[0]; colors[5] = firstColor;
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = triangles;
drawArgs.m_vertCount = 6;
drawArgs.m_colors = colors;
drawArgs.m_colorCount = 6;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawTriangles(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawTri(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3)
{
if (m_auxGeomPtr)
{
AZ::Vector3 verts[3] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3)};
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = verts;
drawArgs.m_vertCount = 3;
drawArgs.m_colors = &m_rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawTriangles(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawTriangles(const AZStd::vector<AZ::Vector3>& vertices, const AZ::Color& color)
{
if (m_auxGeomPtr)
{
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = vertices.data();
drawArgs.m_vertCount = aznumeric_cast<uint32_t>(vertices.size());
drawArgs.m_colors = &color;
drawArgs.m_colorCount = 1;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawTriangles(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawTrianglesIndexed(
const AZStd::vector<AZ::Vector3>& vertices,
const AZStd::vector<AZ::u32>& indices,
const AZ::Color& color)
{
if (m_auxGeomPtr)
{
AZ::RPI::AuxGeomDraw::AuxGeomDynamicIndexedDrawArguments drawArgs;
drawArgs.m_verts = vertices.data();
drawArgs.m_vertCount = aznumeric_cast<uint32_t>(vertices.size());
drawArgs.m_indices = indices.data();
drawArgs.m_indexCount = aznumeric_cast<uint32_t>(indices.size());
drawArgs.m_colors = &color;
drawArgs.m_colorCount = 1;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawTriangles(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max)
{
if (m_auxGeomPtr)
{
m_auxGeomPtr->DrawAabb(
AZ::Aabb::CreateFromMinMax(min, max),
GetCurrentTransform(),
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Line,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawSolidBox(const AZ::Vector3& min, const AZ::Vector3& max)
{
if (m_auxGeomPtr)
{
m_auxGeomPtr->DrawAabb(
AZ::Aabb::CreateFromMinMax(min, max),
GetCurrentTransform(),
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Solid,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex);
}
}
void AtomDebugDisplayViewportInterface::DrawSolidOBB(
const AZ::Vector3& center,
const AZ::Vector3& axisX,
const AZ::Vector3& axisY,
const AZ::Vector3& axisZ,
const AZ::Vector3& halfExtents)
{
if (m_auxGeomPtr)
{
AZ::Quaternion rotation = AZ::Quaternion::CreateFromMatrix3x3(AZ::Matrix3x3::CreateFromColumns(axisX, axisY, axisZ));
AZ::Obb obb = AZ::Obb::CreateFromPositionRotationAndHalfLengths(center, rotation, halfExtents);
m_auxGeomPtr->DrawObb(
obb,
AZ::Vector3::CreateZero(),
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Solid,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex);
}
}
void AtomDebugDisplayViewportInterface::DrawPoint(const AZ::Vector3& p, int nSize)
{
if (m_auxGeomPtr)
{
AZ::Vector3 wsPoint = ToWorldSpacePosition(p);
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = &wsPoint;
drawArgs.m_vertCount = 1;
drawArgs.m_colors = &m_rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_size = aznumeric_cast<uint8_t>(nSize);
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawPoints(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2)
{
if (m_auxGeomPtr)
{
AZ::Vector3 verts[2] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2)};
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = verts;
drawArgs.m_vertCount = 2;
drawArgs.m_colors = &m_rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_size = m_rendState.m_lineWidth;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawLines(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector4& col1, const AZ::Vector4& col2)
{
if (m_auxGeomPtr)
{
AZ::Vector3 verts[2] = {ToWorldSpacePosition(p1), ToWorldSpacePosition(p2)};
AZ::Color colors[2] = {col1, col2};
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = verts;
drawArgs.m_vertCount = 2;
drawArgs.m_colors = colors;
drawArgs.m_colorCount = 2;
drawArgs.m_size = m_rendState.m_lineWidth;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawLines(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawLines(const AZStd::vector<AZ::Vector3>& lines, const AZ::Color& color)
{
if (m_auxGeomPtr)
{
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = lines.data();
drawArgs.m_vertCount = aznumeric_cast<uint32_t>(lines.size());
drawArgs.m_colors = &color;
drawArgs.m_colorCount = 1;
drawArgs.m_size = m_rendState.m_lineWidth;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawLines(drawArgs);
}
}
void AtomDebugDisplayViewportInterface::DrawPolyLine(const AZ::Vector3* pnts, int numPoints, bool cycled)
{
if (m_auxGeomPtr)
{
AZStd::vector<AZ::Vector3> wsPoints(static_cast<size_t>(numPoints));
for (int index = 0; index < numPoints; ++index)
{
wsPoints[index] = ToWorldSpacePosition(pnts[index]);
}
AZ::RPI::AuxGeomDraw::PolylineEnd polylineEnd = cycled ? AZ::RPI::AuxGeomDraw::PolylineEnd::Closed : AZ::RPI::AuxGeomDraw::PolylineEnd::Open;
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = wsPoints.data();
drawArgs.m_vertCount = aznumeric_cast<uint32_t>(numPoints);
drawArgs.m_colors = &m_rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_size = m_rendState.m_lineWidth;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
m_auxGeomPtr->DrawPolylines(drawArgs, polylineEnd);
}
}
// void AtomDebugDisplayViewportInterface::DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override;
// void AtomDebugDisplayViewportInterface::DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override;
// void AtomDebugDisplayViewportInterface::DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override;
// void AtomDebugDisplayViewportInterface::DrawWireCircle2d(const AZ::Vector2& center, float radius, float z) override;
void AtomDebugDisplayViewportInterface::DrawArc(
const AZ::Vector3& pos,
float radius,
float startAngleDegrees,
float sweepAngleDegrees,
float angularStepDegrees,
int referenceAxis)
{
if (m_auxGeomPtr)
{
// Draw axis aligned arc
const float stepAngle = DegToRad(angularStepDegrees);
const float startAngle = DegToRad(startAngleDegrees);
const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle;
SingleColorDynamicSizeLineHelper lines(1+static_cast<int>(sweepAngleDegrees/angularStepDegrees));
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
CreateAxisAlignedArc(
lines,
stepAngle,
startAngle,
stopAngle,
pos,
radiusV3,
static_cast<CircleAxis>(referenceAxis)
);
lines.Draw(m_auxGeomPtr, m_rendState);
}
}
void AtomDebugDisplayViewportInterface::DrawArc(
const AZ::Vector3& pos,
float radius,
float startAngleDegrees,
float sweepAngleDegrees,
float angularStepDegrees,
const AZ::Vector3& fixedAxis)
{
if (m_auxGeomPtr)
{
// Draw arbitraty axis arc
const float stepAngle = DegToRad(angularStepDegrees);
const float startAngle = DegToRad(startAngleDegrees);
const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle;
SingleColorDynamicSizeLineHelper lines(1+static_cast<int>(sweepAngleDegrees/angularStepDegrees));
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
CreateArbitraryAxisArc(
lines,
stepAngle,
startAngle,
stopAngle,
pos,
radiusV3,
fixedAxis
);
lines.Draw(m_auxGeomPtr, m_rendState);
}
}
void AtomDebugDisplayViewportInterface::DrawCircle(const AZ::Vector3& pos, float radius, int nUnchangedAxis)
{
if (m_auxGeomPtr)
{
// Draw circle with default radius.
const float step = DegToRad(10.0f);
const float maxAngle = DegToRad(360.0f) + step;
SingleColorStaticSizeLineHelper<40> lines; // hard code 40 lines until DegToRad is constexpr.
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
CreateAxisAlignedArc(
lines,
step,
0.0f,
maxAngle,
pos,
radiusV3,
static_cast<CircleAxis>(nUnchangedAxis));
lines.Draw(m_auxGeomPtr, m_rendState);
}
}
void AtomDebugDisplayViewportInterface::DrawHalfDottedCircle(const AZ::Vector3& pos, float radius, const AZ::Vector3& viewPos, int nUnchangedAxis)
{
if (m_auxGeomPtr)
{
// Draw circle with single radius.
const float step = DegToRad(10.0f);
const float maxAngle = DegToRad(360.0f) + step;
SingleColorStaticSizeLineHelper<40> lines; // hard code 40 lines until DegToRad is constexpr.
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
const AZ::Vector3 worldPos = ToWorldSpacePosition(pos);
const AZ::Vector3 worldView = ToWorldSpacePosition(viewPos);
const AZ::Vector3 worldDir = worldView - worldPos;
CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, radiusV3, static_cast<CircleAxis>(nUnchangedAxis%CircleAxisMax),
[&worldPos, &worldDir](const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd, int segmentIndex)
{
AZ_UNUSED(lineEnd);
const float dot = (lineStart - worldPos).Dot(worldDir);
const bool facing = dot > 0.0f;
// if so skip every other line to produce a dotted effect
if (facing || segmentIndex % 2 == 0)
{
return true;
}
return false;
});
lines.Draw(m_auxGeomPtr, m_rendState);
}
}
void AtomDebugDisplayViewportInterface::DrawCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height, bool drawShaded)
{
if (m_auxGeomPtr)
{
const AZ::Vector3 worldPos = ToWorldSpacePosition(pos);
const AZ::Vector3 worldDir = ToWorldSpaceVector(dir);
m_auxGeomPtr->DrawCone(
worldPos,
worldDir,
radius,
height,
m_rendState.m_color,
drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawWireCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height)
{
if (m_auxGeomPtr)
{
const AZ::Vector3 worldCenter = ToWorldSpacePosition(center);
const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis);
m_auxGeomPtr->DrawCylinder(
worldCenter,
worldAxis,
radius,
height,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Line,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawSolidCylinder(
const AZ::Vector3& center,
const AZ::Vector3& axis,
float radius,
float height,
bool drawShaded)
{
if (m_auxGeomPtr)
{
const AZ::Vector3 worldCenter = ToWorldSpacePosition(center);
const AZ::Vector3 worldAxis = ToWorldSpaceVector(axis);
m_auxGeomPtr->DrawCylinder(
worldCenter,
worldAxis,
radius,
height,
m_rendState.m_color,
drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawWireCapsule(
const AZ::Vector3& center,
const AZ::Vector3& axis,
float radius,
float heightStraightSection)
{
if (m_auxGeomPtr && radius > FLT_EPSILON && axis.GetLengthSq() > FLT_EPSILON)
{
AZ::Vector3 axisNormalized = axis.GetNormalizedEstimate();
SingleColorStaticSizeLineHelper<(16+1) * 5> lines; // 360/22.5 = 16, 5 possible calls to CreateArbitraryAxisArc
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
float stepAngle = DegToRad(22.5f);
float Deg0 = DegToRad(0.0f);
// Draw cylinder part (or just a circle around the middle)
if (heightStraightSection > FLT_EPSILON)
{
DrawWireCylinder(center, axis, radius, heightStraightSection);
}
else
{
float Deg360 = DegToRad(360.0f);
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg0,
Deg360,
center,
radiusV3,
axisNormalized
);
}
float Deg90 = DegToRad(90.0f);
float Deg180 = DegToRad(180.0f);
AZ::Vector3 ortho1Normalized, ortho2Normalized;
CalcBasisVectors(axisNormalized, ortho1Normalized, ortho2Normalized);
AZ::Vector3 centerToTopCircleCenter = axisNormalized * heightStraightSection * 0.5f;
AZ::Vector3 topCenter = center + centerToTopCircleCenter;
AZ::Vector3 bottomCenter = center - centerToTopCircleCenter;
// Draw top cap as two criss-crossing 180deg arcs
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg90,
Deg90 + Deg180,
topCenter,
radiusV3,
ortho1Normalized
);
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg180,
Deg180 + Deg180,
topCenter,
radiusV3,
ortho2Normalized
);
// Draw bottom cap
CreateArbitraryAxisArc(
lines,
stepAngle,
-Deg90,
-Deg90 + Deg180,
bottomCenter,
radiusV3,
ortho1Normalized
);
CreateArbitraryAxisArc(
lines,
stepAngle,
Deg0,
Deg0 + Deg180,
bottomCenter,
radiusV3,
ortho2Normalized
);
lines.Draw(m_auxGeomPtr, m_rendState);
}
}
void AtomDebugDisplayViewportInterface::DrawWireSphere(const AZ::Vector3& pos, float radius)
{
if (m_auxGeomPtr)
{
m_auxGeomPtr->DrawSphere(
ToWorldSpacePosition(pos),
radius,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Line,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawWireSphere(const AZ::Vector3& pos, const AZ::Vector3 radius)
{
if (m_auxGeomPtr)
{
// This matches Cry behavior, the DrawWireSphere above may need modifying to use the same approach.
// Draw 3 axis aligned circles
const float step = DegToRad(10.0f);
const float maxAngle = DegToRad(360.0f) + step;
SingleColorStaticSizeLineHelper<40*3> lines; // hard code to 40 lines * 3 circles until DegToRad is constexpr.
// Z Axis
AZ::Vector3 axisRadius(radius.GetX(), radius.GetY(), 0.0f);
CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisZ);
// X Axis
axisRadius = AZ::Vector3(0.0f, radius.GetY(), radius.GetZ());
CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisX);
// Y Axis
axisRadius = AZ::Vector3(radius.GetX(), 0.0f, radius.GetZ());
CreateAxisAlignedArc(lines, step, 0.0f, maxAngle, pos, axisRadius, CircleAxisY);
lines.Draw(m_auxGeomPtr, m_rendState);
}
}
void AtomDebugDisplayViewportInterface::DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius)
{
if (m_auxGeomPtr)
{
// Draw 3 axis aligned circles
const float stepAngle = DegToRad(11.25f);
const float startAngle = DegToRad(0.0f);
const float stopAngle = DegToRad(360.0f) + startAngle;
SingleColorDynamicSizeLineHelper lines(2+static_cast<int>(360.0f/11.25f)); // num disk segments + 1 for azis line + 1 for spare
const AZ::Vector3 radiusV3 = AZ::Vector3(radius);
CreateArbitraryAxisArc(
lines,
stepAngle,
startAngle,
stopAngle,
pos,
radiusV3,
dir
);
lines.AddLineSegment(ToWorldSpacePosition(pos), ToWorldSpacePosition(pos + dir * (radius * 0.2f))); // 0.2f comes from Code\Sandbox\Editor\Objects\DisplayContextShared.inl DisplayContext::DrawWireDisk
lines.Draw(m_auxGeomPtr, m_rendState);
}
}
void AtomDebugDisplayViewportInterface::DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded)
{
if (m_auxGeomPtr)
{
// get the max scaled radius in case the transform on the stack is scaled non-uniformly
const float transformedRadiusX = ToWorldSpaceVector(AZ::Vector3(radius, 0.0f, 0.0f)).GetLengthEstimate();
const float transformedRadiusY = ToWorldSpaceVector(AZ::Vector3(0.0f, radius, 0.0f)).GetLengthEstimate();
const float transformedRadiusZ = ToWorldSpaceVector(AZ::Vector3(0.0f, 0.0f, radius)).GetLengthEstimate();
const float maxTransformedRadius =
AZ::GetMax(transformedRadiusX, AZ::GetMax(transformedRadiusY, transformedRadiusZ));
AZ::RPI::AuxGeomDraw::DrawStyle drawStyle = drawShaded ? AZ::RPI::AuxGeomDraw::DrawStyle::Shaded : AZ::RPI::AuxGeomDraw::DrawStyle::Solid;
m_auxGeomPtr->DrawSphere(
ToWorldSpacePosition(pos),
maxTransformedRadius,
m_rendState.m_color,
drawStyle,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius)
{
if (m_auxGeomPtr)
{
const AZ::Vector3 worldPos = ToWorldSpacePosition(pos);
const AZ::Vector3 worldDir = ToWorldSpaceVector(dir);
m_auxGeomPtr->DrawDisk(
worldPos,
worldDir,
radius,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Shaded,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
void AtomDebugDisplayViewportInterface::DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float headScale, bool dualEndedArrow)
{
if (m_auxGeomPtr)
{
float f2dScale = 1.0f;
float arrowLen = 0.4f * headScale;
float arrowRadius = 0.1f * headScale;
// if (flags & DISPLAY_2D)
// {
// f2dScale = 1.2f * ToWorldSpaceVector(Vec3(1, 0, 0)).GetLength();
// }
AZ::Vector3 dir = trg - src;
dir = ToWorldSpaceVector(dir.GetNormalized());
AZ::Vector3 verts[2] = {ToWorldSpacePosition(src), ToWorldSpacePosition(trg)};
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = verts;
drawArgs.m_vertCount = 2;
drawArgs.m_colors = &m_rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_size = m_rendState.m_lineWidth;
drawArgs.m_opacityType = m_rendState.m_opacityType;
drawArgs.m_depthTest = m_rendState.m_depthTest;
drawArgs.m_depthWrite = m_rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = m_rendState.m_viewProjOverrideIndex;
if (!dualEndedArrow)
{
verts[1] -= dir * arrowLen;
m_auxGeomPtr->DrawLines(drawArgs);
m_auxGeomPtr->DrawCone(
verts[1],
dir,
arrowRadius * f2dScale,
arrowLen * f2dScale,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Shaded,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
else
{
verts[0] += dir * arrowLen;
verts[1] -= dir * arrowLen;
m_auxGeomPtr->DrawLines(drawArgs);
m_auxGeomPtr->DrawCone(
verts[0],
-dir,
arrowRadius * f2dScale,
arrowLen * f2dScale,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Shaded,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
m_auxGeomPtr->DrawCone(
verts[1],
dir,
arrowRadius * f2dScale,
arrowLen * f2dScale,
m_rendState.m_color,
AZ::RPI::AuxGeomDraw::DrawStyle::Shaded,
m_rendState.m_depthTest,
m_rendState.m_depthWrite,
m_rendState.m_faceCullMode,
m_rendState.m_viewProjOverrideIndex
);
}
}
}
// void AtomDebugDisplayViewportInterface::DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter = false, int srcOffsetX = 0, int srcOffsetY = 0) override;
// void AtomDebugDisplayViewportInterface::Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter = false) override;
// void AtomDebugDisplayViewportInterface::DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& TextColor, const AZ::Vector4& TextBackColor) override;
// unhandledled on Atom - virtual void DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override;
// void AtomDebugDisplayViewportInterface::DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override;
void AtomDebugDisplayViewportInterface::SetLineWidth(float width)
{
AZ_Assert(width >= 0.0f && width <= 255.0f, "Width (%f) exceeds allowable range [0 - 255]", width);
m_rendState.m_lineWidth = static_cast<AZ::u8>(width);
}
// bool AtomDebugDisplayViewportInterface::IsVisible(const AZ::Aabb& bounds) override;
// int AtomDebugDisplayViewportInterface::SetFillMode(int nFillMode) override;
float AtomDebugDisplayViewportInterface::GetLineWidth()
{
return m_rendState.m_lineWidth;
}
float AtomDebugDisplayViewportInterface::GetAspectRatio()
{
auto viewContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
AZ::RPI::ViewportContextPtr viewportContext;
if (m_defaultInstance)
{
viewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName());
}
else
{
viewportContext = viewContextManager->GetViewportContextById(m_viewportId);
}
auto windowSize = viewportContext->GetViewportSize();
return aznumeric_cast<float>(windowSize.m_width)/aznumeric_cast<float>(windowSize.m_height);
}
void AtomDebugDisplayViewportInterface::DepthTestOff()
{
m_rendState.m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::Off;
}
void AtomDebugDisplayViewportInterface::DepthTestOn()
{
m_rendState.m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::On;
}
void AtomDebugDisplayViewportInterface::DepthWriteOff()
{
m_rendState.m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::Off;
}
void AtomDebugDisplayViewportInterface::DepthWriteOn()
{
m_rendState.m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::On;
}
void AtomDebugDisplayViewportInterface::CullOff()
{
m_rendState.m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::None;
}
void AtomDebugDisplayViewportInterface::CullOn()
{
m_rendState.m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::Back;
}
bool AtomDebugDisplayViewportInterface::SetDrawInFrontMode(bool on)
{
AZ_UNUSED(on);
return false;
}
// AZ::u32 AtomDebugDisplayViewportInterface::GetState() override;
// AZ::u32 AtomDebugDisplayViewportInterface::SetState(AZ::u32 state) override;
// AZ::u32 AtomDebugDisplayViewportInterface::SetStateFlag(AZ::u32 state) override;
// AZ::u32 AtomDebugDisplayViewportInterface::ClearStateFlag(AZ::u32 state) override;
void AtomDebugDisplayViewportInterface::PushMatrix(const AZ::Transform& tm)
{
AZ_Assert(m_rendState.m_currentTransform < RenderState::TransformStackSize, "Exceeded AtomDebugDisplayViewportInterface matrix stack size");
if (m_rendState.m_currentTransform < RenderState::TransformStackSize)
{
m_rendState.m_currentTransform++;
m_rendState.m_transformStack[m_rendState.m_currentTransform] = m_rendState.m_transformStack[m_rendState.m_currentTransform - 1] * AZ::Matrix3x4::CreateFromTransform(tm);
}
}
void AtomDebugDisplayViewportInterface::PopMatrix()
{
AZ_Assert(m_rendState.m_currentTransform > 0, "Underflowed AtomDebugDisplayViewportInterface matrix stack");
if (m_rendState.m_currentTransform > 0)
{
m_rendState.m_currentTransform--;
}
}
const AZ::Matrix3x4& AtomDebugDisplayViewportInterface::GetCurrentTransform() const
{
return m_rendState.m_transformStack[m_rendState.m_currentTransform];
}
}
}
@@ -0,0 +1,330 @@
/*
* 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/Casting/numeric_cast.h>
#include <AzCore/Component/Component.h>
#include <AzCore/std/containers/fixed_vector.h>
#include <AzCore/Math/Matrix3x4.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
#include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
#include <Atom/RPI.Public/ViewportContext.h>
namespace AZ::AtomBridge
{
struct RenderState
{
AZ::Color m_color = AZ::Color(0.0f, 0.0f, 0.0f, 1.0f);
uint8_t m_lineWidth = 1u;
uint16_t m_currentTransform = 0;
enum { TransformStackSize = 32 };
AZ::Matrix3x4 m_transformStack[TransformStackSize];
AZ::RPI::AuxGeomDraw::OpacityType m_opacityType = AZ::RPI::AuxGeomDraw::OpacityType::Opaque;
AZ::RPI::AuxGeomDraw::DepthTest m_depthTest = AZ::RPI::AuxGeomDraw::DepthTest::On;
AZ::RPI::AuxGeomDraw::DepthWrite m_depthWrite = AZ::RPI::AuxGeomDraw::DepthWrite::On;
AZ::RPI::AuxGeomDraw::FaceCullMode m_faceCullMode = AZ::RPI::AuxGeomDraw::FaceCullMode::Back;
int32_t m_viewProjOverrideIndex = -1; // will be used to implement SetDrawInFrontMode & 2D mode
};
//! Utility class to collect line segments when the number of segments is known at compile time.
template <int MaxNumLines>
struct SingleColorStaticSizeLineHelper
{
bool AddLineSegment(const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd)
{
if ((m_points.size()+2) < m_points.capacity())
{
m_points.push_back(lineStart);
m_points.push_back(lineEnd);
return true;
}
return false;
}
void Draw(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const
{
if (auxGeomDrawPtr && !m_points.empty())
{
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArgs;
drawArgs.m_verts = m_points.data();
drawArgs.m_vertCount = aznumeric_cast<uint32_t>(m_points.size());
drawArgs.m_colors = &rendState.m_color;
drawArgs.m_colorCount = 1;
drawArgs.m_size = rendState.m_lineWidth;
drawArgs.m_opacityType = rendState.m_opacityType;
drawArgs.m_depthTest = rendState.m_depthTest;
drawArgs.m_depthWrite = rendState.m_depthWrite;
drawArgs.m_viewProjectionOverrideIndex = rendState.m_viewProjOverrideIndex;
auxGeomDrawPtr->DrawLines( drawArgs );
}
}
void Reset()
{
m_points.clear();
}
AZStd::fixed_vector<AZ::Vector3, 2 * MaxNumLines> m_points;
};
//! Utility class to collect line segments
struct SingleColorDynamicSizeLineHelper final
{
SingleColorDynamicSizeLineHelper(int estimatedNumLineSegments);
void AddLineSegment(const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd);
void Draw(AZ::RPI::AuxGeomDrawPtr auxGeomDrawPtr, const RenderState& rendState) const;
void Reset();
AZStd::vector<AZ::Vector3> m_points;
};
class AtomDebugDisplayViewportInterface final
: public AzFramework::DebugDisplayRequestBus::Handler
{
public:
AZ_RTTI(AtomDebugDisplayViewportInterface, "{09AF6A46-0100-4FBF-8F94-E6B221322D14}", AzFramework::DebugDisplayRequestBus::Handler);
explicit AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr);
explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress);
~AtomDebugDisplayViewportInterface();
void ResetRenderState();
////////////////////////////////////////////////////////////////////////////
// AzFramework/Entity/DebugDisplayRequestBus::Handler overrides ...
// Partial implementation of the DebugDisplayRequestBus on Atom.
// Commented out function prototypes are remaining part of the api
// waiting to be implemented.
// work tracked in [ATOM-3459]
void SetColor(float r, float g, float b, float a = 1.f) override;
void SetColor(const AZ::Color& color) override;
void SetColor(const AZ::Vector4& color) override;
void SetAlpha(float a) override;
void DrawQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override;
// void DrawQuad(float width, float height) overr
// void DrawWireQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4) override;
// void DrawWireQuad(float width, float height) override;
void DrawQuadGradient(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override;
void DrawTri(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3) override;
void DrawTriangles(const AZStd::vector<AZ::Vector3>& vertices, const AZ::Color& color) override;
void DrawTrianglesIndexed(const AZStd::vector<AZ::Vector3>& vertices, const AZStd::vector<AZ::u32>& indices, const AZ::Color& color) override;
void DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max) override;
void DrawSolidBox(const AZ::Vector3& min, const AZ::Vector3& max) override;
void DrawSolidOBB(const AZ::Vector3& center, const AZ::Vector3& axisX, const AZ::Vector3& axisY, const AZ::Vector3& axisZ, const AZ::Vector3& halfExtents) override;
void DrawPoint(const AZ::Vector3& p, int nSize = 1) override;
void DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2) override;
void DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector4& col1, const AZ::Vector4& col2) override;
void DrawLines(const AZStd::vector<AZ::Vector3>& lines, const AZ::Color& color) override;
void DrawPolyLine(const AZ::Vector3* pnts, int numPoints, bool cycled = true) override;
// void DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override;
// void DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z) override;
// void DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor) override;
// void DrawWireCircle2d(const AZ::Vector2& center, float radius, float z) override;
void DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, int referenceAxis = 2) override;
void DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, const AZ::Vector3& fixedAxis) override;
void DrawCircle(const AZ::Vector3& pos, float radius, int nUnchangedAxis = 2 /*z axis*/) override;
void DrawHalfDottedCircle(const AZ::Vector3& pos, float radius, const AZ::Vector3& viewPos, int nUnchangedAxis = 2 /*z axis*/) override;
void DrawCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height, bool drawShaded) override;
void DrawWireCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height) override;
void DrawSolidCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height, bool drawShaded) override;
void DrawWireCapsule(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float heightStraightSection) override;
void DrawWireSphere(const AZ::Vector3& pos, float radius) override;
void DrawWireSphere(const AZ::Vector3& pos, const AZ::Vector3 radius) override;
void DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) override;
void DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded) override;
void DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius) override;
void DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float headScale = 1.0f, bool dualEndedArrow = false) override;
// void DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter = false, int srcOffsetX = 0, int srcOffsetY = 0) override;
// void Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter = false) override;
// void DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& TextColor, const AZ::Vector4& TextBackColor) override;
// unhandled on Atom - virtual void DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override;
// void DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags) override;
void SetLineWidth(float width) override;
// bool IsVisible(const AZ::Aabb& bounds) override;
// int SetFillMode(int nFillMode) override;
float GetLineWidth() override;
float GetAspectRatio() override;
void DepthTestOff() override;
void DepthTestOn() override;
void DepthWriteOff() override;
void DepthWriteOn() override;
void CullOff() override;
void CullOn() override;
bool SetDrawInFrontMode(bool on) override;
// AZ::u32 GetState() override;
// AZ::u32 SetState(AZ::u32 state) override;
// AZ::u32 SetStateFlag(AZ::u32 state) override;
// AZ::u32 ClearStateFlag(AZ::u32 state) override;
void PushMatrix(const AZ::Transform& tm) override;
void PopMatrix() override;
private:
using LineSegmentFilterFunc = AZStd::function<bool(const AZ::Vector3& lineStart, const AZ::Vector3& lineEnd, int segmentIndex)>;
enum CircleAxis
{
CircleAxisX = 0,
CircleAxisY = 1,
CircleAxisZ = 2,
CircleAxisMax = 3,
};
template<typename LineStorageType>
void CreateAxisAlignedArc(
LineStorageType& lines,
float segmentAngle, // radians
float minAngle, // radians
float maxAngle, // radians
const AZ::Vector3& position,
const AZ::Vector3& radiusV3,
CircleAxis circleAxis,
LineSegmentFilterFunc filterFunc =
[](const AZ::Vector3&, const AZ::Vector3&, int)
{return true;}
);
template<typename LineStorageType>
void CreateArbitraryAxisArc(
LineStorageType& lines,
float segmentAngle, // radians
float minAngle, // radians
float maxAngle, // radians
const AZ::Vector3& position,
const AZ::Vector3& radiusV3,
const AZ::Vector3& axis,
LineSegmentFilterFunc filterFunc =
[](const AZ::Vector3&, const AZ::Vector3&, int)
{return true;}
);
//! Convert position to world space.
AZ::Vector3 ToWorldSpacePosition(const AZ::Vector3& v) const { return m_rendState.m_transformStack[m_rendState.m_currentTransform] * v; }
//! Convert direction to world space (translation is not considered)
AZ::Vector3 ToWorldSpaceVector(const AZ::Vector3& v) const { return m_rendState.m_transformStack[m_rendState.m_currentTransform].Multiply3x3(v); }
void CalcBasisVectors(const AZ::Vector3& n, AZ::Vector3& b1, AZ::Vector3& b2) const;
const AZ::Matrix3x4& GetCurrentTransform() const;
void InitInternal(RPI::Scene* scene, AZ::RPI::ViewportContextPtr viewportContextPtr);
RenderState m_rendState;
AZ::RPI::AuxGeomDrawPtr m_auxGeomPtr;
bool m_defaultInstance = false; // only true for drawing to a particular viewport. What would 2D drawing mean in a scene with several windows?
AzFramework::ViewportId m_viewportId = AzFramework::InvalidViewportId; // Address this instance answers on.
};
// this is duplicated from Cry_Math.h, GetBasisVectors.
// Need to match it's behavior to get the same orientations on curves.
inline void AtomDebugDisplayViewportInterface::CalcBasisVectors(
const AZ::Vector3& unitVector,
AZ::Vector3& basis1,
AZ::Vector3& basis2
) const
{
if (unitVector.GetZ() < FLT_EPSILON - 1.0f)
{
basis1 = AZ::Vector3(0.0f, -1.0f, 0.0f);
basis2 = AZ::Vector3(-1.0f, 0.0f, 0.0f);
return;
}
const float a = 1.0f / (1.0f + unitVector.GetZ());
const float b = -unitVector.GetX() * unitVector.GetY() * a;
basis1 = AZ::Vector3(1.0f - unitVector.GetX() * unitVector.GetX() * a, b, -unitVector.GetX());
basis2 = AZ::Vector3(b, 1.0f - unitVector.GetY() * unitVector.GetY() * a, -unitVector.GetY());
}
template<typename LineStorageType>
void AtomDebugDisplayViewportInterface::CreateAxisAlignedArc(
LineStorageType& lines,
float segmentAngle, // radians
float minAngle, // radians
float maxAngle, // radians
const AZ::Vector3& position,
const AZ::Vector3& radiusV3,
CircleAxis circleAxis,
LineSegmentFilterFunc filterFunc)
{
AZ::Vector3 p1;
AZ::Vector3 sinCos = AZ::Vector3::CreateZero();
const uint32_t circleAxis1 = (circleAxis + 1) % CircleAxisMax;
const uint32_t circleAxis2 = (circleAxis + 2) % CircleAxisMax;
sinCos.SetElement(circleAxis1, sinf(minAngle));
sinCos.SetElement(circleAxis2, cosf(minAngle));
AZ::Vector3 p0 = position + radiusV3 * sinCos;
p0 = ToWorldSpacePosition(p0);
int segmentIndex = 0;
for (float angle = minAngle + segmentAngle; angle < maxAngle; angle += segmentAngle)
{
float calcAngle = AZStd::clamp(angle, minAngle, maxAngle);
sinCos.SetElement(circleAxis1, sinf(calcAngle));
sinCos.SetElement(circleAxis2, cosf(calcAngle));
p1 = position + radiusV3 * sinCos;
p1 = ToWorldSpacePosition(p1);
if (filterFunc(p0, p1, segmentIndex))
{
lines.AddLineSegment(p0, p1);
}
p0 = p1;
++segmentIndex;
}
}
template<typename LineStorageType>
void AtomDebugDisplayViewportInterface::CreateArbitraryAxisArc(
LineStorageType& lines,
float segmentAngle, // radians
float minAngle, // radians
float maxAngle, // radians
const AZ::Vector3& position,
const AZ::Vector3& radiusV3,
const AZ::Vector3& axis,
LineSegmentFilterFunc filterFunc)
{
AZ::Vector3 p1;
float sinVF;
float cosVF;
AZ::SinCos(minAngle, sinVF, cosVF);
AZ::Vector3 a, b;
CalcBasisVectors(axis, a, b);
AZ::Vector3 p0 = position + radiusV3 * (cosVF * a + sinVF * b);
p0 = ToWorldSpacePosition(p0);
int segmentIndex = 0;
for (float angle = minAngle + segmentAngle; angle < maxAngle; angle += segmentAngle)
{
float calcAngle = AZ::GetClamp(angle, minAngle, maxAngle);
AZ::SinCos(calcAngle, sinVF, cosVF);
p1 = position + radiusV3 * (cosVF * a + sinVF * b);
p1 = ToWorldSpacePosition(p1);
if (filterFunc(p0, p1, segmentIndex))
{
lines.AddLineSegment(p0, p1);
}
p0 = p1;
++segmentIndex;
}
}
} // namespace AZ::AtomBridge
@@ -0,0 +1,56 @@
/*
* 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 <AzCore/Component/Entity.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Interface/Interface.h>
#include <BuilderComponent.h>
#include <AssetBuilderSDK/AssetBuilderSDK.h>
namespace AZ
{
namespace AtomBridge
{
void BuilderComponent::Reflect(AZ::ReflectContext* context)
{
if (auto* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<BuilderComponent, AZ::Component>()
->Version(0)
->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector<AZ::Crc32>({ AssetBuilderSDK::ComponentTags::AssetBuilder }))
;
}
}
BuilderComponent::BuilderComponent()
{
AZ::Interface<AzFramework::AtomActiveInterface>::Register(this);
}
BuilderComponent::~BuilderComponent()
{
AZ::Component::~Component();
AZ::Interface<AzFramework::AtomActiveInterface>::Unregister(this);
}
void BuilderComponent::Activate()
{
}
void BuilderComponent::Deactivate()
{
}
} // namespace RPI
} // namespace AZ
@@ -0,0 +1,38 @@
/*
* 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/Component/Component.h>
#include <AzFramework/API/AtomActiveInterface.h>
namespace AZ
{
namespace AtomBridge
{
class BuilderComponent final
: public AZ::Component
, public AzFramework::AtomActiveInterface
{
public:
AZ_COMPONENT(BuilderComponent, "{D1FE015B-8431-4155-8FD0-8197F246901A}");
static void Reflect(AZ::ReflectContext* context);
BuilderComponent();
~BuilderComponent() override;
// AZ::Component overrides...
void Activate() override;
void Deactivate() override;
};
} // namespace RPI
} // namespace AZ
@@ -0,0 +1,287 @@
/*
* 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 "AssetCollectionAsyncLoaderTestComponent.h"
#include <AzCore/RTTI/ReflectContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AtomCore/Serialization/Json/JsonUtils.h>
// Included so we can deduce the asset type from asset paths.
#include <Atom/RPI.Reflect/Shader/ShaderAsset.h>
#include <Atom/RPI.Reflect/Model/ModelAsset.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Shader/ShaderResourceGroupAsset.h>
namespace AZ
{
namespace AtomBridge
{
static constexpr char AssetCollectionAsyncLoaderTestComponentName[] = " AssetCollectionAsyncLoaderTestComponent";
void AssetCollectionAsyncLoaderTestComponent::Reflect(AZ::ReflectContext* context)
{
auto serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssetCollectionAsyncLoaderTestComponent, EditorComponentBase>()
->Version(1)
->Field("AssetListPathJson", &AssetCollectionAsyncLoaderTestComponent::m_pathToAssetListJson)
;
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<AssetCollectionAsyncLoaderTestComponent>(
"AssetCollectionAsyncLoaderTest", "The AssetCollectionAsyncLoaderTest component allows you to test the API provided by AssetCollectionAsyncLoader")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Test")
->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/Comment.svg")
->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/Comment.png")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZStd::vector<AZ::Crc32>({ AZ_CRC("Level", 0x9aeacc13), AZ_CRC("Game", 0x232b318c), AZ_CRC("Layer", 0xe4db211a) }))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
->DataElement(AZ::Edit::UIHandlers::LineEdit, &AssetCollectionAsyncLoaderTestComponent::m_pathToAssetListJson, "", "Path To Asset List")
->Attribute(AZ_CRC("PlaceholderText", 0xa23ec278), "Path to a JSON file")
->UIElement(AZ::Edit::UIHandlers::Button, "", "Starts/Stop the test")
->Attribute(AZ::Edit::Attributes::ChangeNotify, &AssetCollectionAsyncLoaderTestComponent::OnStartCancelButtonClicked)
->Attribute(AZ::Edit::Attributes::ButtonText, &AssetCollectionAsyncLoaderTestComponent::GetStartCancelButtonText);
}
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AssetCollectionAsyncLoaderTestBus>("AssetCollectionAsyncLoaderTestBus")
->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
->Attribute(AZ::Script::Attributes::Category, "Test")
->Attribute(AZ::Script::Attributes::Module, "test")
->Event("StartLoadingAssetsFromJsonFile", &AssetCollectionAsyncLoaderTestBus::Events::StartLoadingAssetsFromJsonFile)
->Event("StartLoadingAssetsFromAssetList", &AssetCollectionAsyncLoaderTestBus::Events::StartLoadingAssetsFromAssetList)
->Event("CancelLoadingAssets", &AssetCollectionAsyncLoaderTestBus::Events::CancelLoadingAssets)
->Event("GetPendingAssetsList", &AssetCollectionAsyncLoaderTestBus::Events::GetPendingAssetsList)
->Event("GetCountOfPendingAssets", &AssetCollectionAsyncLoaderTestBus::Events::GetCountOfPendingAssets)
->Event("ValidateAssetWasLoaded", &AssetCollectionAsyncLoaderTestBus::Events::ValidateAssetWasLoaded)
;
}
}
void AssetCollectionAsyncLoaderTestComponent::Activate()
{
m_assetCollectionAsyncLoader = AZStd::make_unique<AZ::AssetCollectionAsyncLoader>();
AssetCollectionAsyncLoaderTestBus::Handler::BusConnect(GetEntityId());
}
void AssetCollectionAsyncLoaderTestComponent::Deactivate()
{
m_assetCollectionAsyncLoader = nullptr;
AssetCollectionAsyncLoaderTestBus::Handler::BusDisconnect();
}
AZ::Crc32 AssetCollectionAsyncLoaderTestComponent::OnStartCancelButtonClicked()
{
switch (m_state)
{
case State::LoadingAssets:
CancelLoadingAssets();
break;
default:
StartLoadingAssetsFromJsonFile(m_pathToAssetListJson);
break;
}
return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
}
AZStd::string AssetCollectionAsyncLoaderTestComponent::GetStartCancelButtonText() const
{
switch (m_state)
{
case State::LoadingAssets:
return "Cancel Loading Assets";
}
return "Start Loading Assets";
}
//////////////////////////////////////////////////////////////////////////
// AssetCollectionAsyncLoaderTestBus overrides
bool AssetCollectionAsyncLoaderTestComponent::StartLoadingAssetsFromJsonFile(const AZStd::string& pathToAssetListJson)
{
rapidjson::Document jsonDoc;
auto readJsonResult = JsonSerializationUtils::ReadJsonFile(pathToAssetListJson);
if (!readJsonResult.IsSuccess())
{
AZ_Error(AssetCollectionAsyncLoaderTestComponentName, false, "Failed to parse asset list json file %s", pathToAssetListJson.c_str());
return false;
}
jsonDoc = readJsonResult.TakeValue();
AZStd::vector<AZStd::string> assetList;
for (rapidjson::Value::ConstValueIterator itr = jsonDoc.Begin(); itr != jsonDoc.End(); ++itr)
{
AZStd::string_view assetPath = itr->GetString();
AZ_TracePrintf(AssetCollectionAsyncLoaderTestComponentName, "Asset path: %s\n", assetPath.data());
assetList.push_back(assetPath);
}
return StartLoadingAssetsFromAssetList(assetList);
}
//! Helper method
static Data::AssetType GetAssetTypeFromAssetPath(const AZStd::string& assetPath)
{
AZStd::string extension;
if (!AzFramework::StringFunc::Path::GetExtension(assetPath.c_str(), extension, false /*include dot*/))
{
AZ_Error(AssetCollectionAsyncLoaderTestComponentName, false, "Failed to get extension from path: %s", assetPath.c_str());
return {};
}
if (extension == "azshader")
{
return azrtti_typeid<RPI::ShaderAsset>();
}
else if (extension == "azmodel")
{
return azrtti_typeid<RPI::ModelAsset>();
}
else if (extension == "streamingimage")
{
return azrtti_typeid<RPI::StreamingImageAsset>();
}
else if (extension == "azsrg")
{
return azrtti_typeid<RPI::ShaderResourceGroupAsset>();
}
AZ_Error(AssetCollectionAsyncLoaderTestComponentName, false, "Do not know the asset type for file: %s", assetPath.c_str());
return {};
}
bool AssetCollectionAsyncLoaderTestComponent::StartLoadingAssetsFromAssetList(const AZStd::vector<AZStd::string>& assetList)
{
if (assetList.empty())
{
AZ_Error(AssetCollectionAsyncLoaderTestComponentName, false, "Input asset list is empty");
return false;
}
// Build the list with asset types deduced from the file extensions.
AZStd::vector<AssetCollectionAsyncLoader::AssetToLoadInfo> assetListWithType;
assetListWithType.reserve(assetList.size());
for (const auto& assetPath : assetList)
{
const auto assetType = GetAssetTypeFromAssetPath(assetPath);
assetListWithType.push_back({ assetPath, assetType });
m_pendingAssets.insert(assetPath);
}
m_assetCollectionAsyncLoader->LoadAssetsAsync(assetListWithType,
[&](AZStd::string_view assetPath, [[maybe_unused]] bool success, [[maybe_unused]] size_t pendingAssetCount)
{
AZ_TracePrintf(AssetCollectionAsyncLoaderTestComponentName, "Got asset load [%s] for asset [%s]. Pending asset count [%zu]\n"
, success ? "SUCCESS" : "ERROR", assetPath.data(), pendingAssetCount);
switch (m_state)
{
case State::LoadingAssets:
{
if (m_pendingAssets.count(assetPath))
{
m_pendingAssets.erase(assetPath);
if (!m_pendingAssets.size())
{
AZ_TracePrintf(AssetCollectionAsyncLoaderTestComponentName, "Asset Loading Is Successfully Complete\n");
m_state = State::Idle;
}
}
else
{
AZ_Error(AssetCollectionAsyncLoaderTestComponentName, false, "While loading assets, got asset update from an unexpected asset with path: %s", assetPath.data());
m_assetCollectionAsyncLoader->Cancel();
m_state = State::FatalError;
}
}
break;
default:
AZ_Error(AssetCollectionAsyncLoaderTestComponentName, false, "Got asset update from an unexpected asset with path: %s", assetPath.data());
m_state = State::FatalError;
break;
}
});
m_state = State::LoadingAssets;
return true;
}
void AssetCollectionAsyncLoaderTestComponent::CancelLoadingAssets()
{
m_assetCollectionAsyncLoader->Cancel();
m_pendingAssets.clear();
m_state = State::Idle;
}
AZStd::vector<AZStd::string> AssetCollectionAsyncLoaderTestComponent::GetPendingAssetsList() const
{
AZStd::vector<AZStd::string> retList;
retList.reserve(m_pendingAssets.size());
AZStd::for_each(m_pendingAssets.begin(), m_pendingAssets.end(),
[&](const AZStd::string& assetPath)
{
retList.push_back(assetPath);
});
return retList;
}
uint32_t AssetCollectionAsyncLoaderTestComponent::GetCountOfPendingAssets() const
{
return m_pendingAssets.size();
}
bool AssetCollectionAsyncLoaderTestComponent::ValidateAssetWasLoaded(const AZStd::string& assetPath) const
{
Data::AssetType assetType = GetAssetTypeFromAssetPath(assetPath);
if (assetType == azrtti_typeid<RPI::ShaderAsset>())
{
auto asset = m_assetCollectionAsyncLoader->GetAsset<RPI::ShaderAsset>(assetPath);
return (bool)asset && asset.GetId().IsValid() && asset.IsReady() && !asset->GetName().IsEmpty();
}
else if (assetType == azrtti_typeid<RPI::ModelAsset>())
{
auto asset = m_assetCollectionAsyncLoader->GetAsset<RPI::ModelAsset>(assetPath);
return (bool)asset && asset.GetId().IsValid() && asset.IsReady() && asset->GetLodCount();
}
else if (assetType == azrtti_typeid<RPI::StreamingImageAsset>())
{
auto asset = m_assetCollectionAsyncLoader->GetAsset<RPI::StreamingImageAsset>(assetPath);
return (bool)asset && asset.GetId().IsValid() && asset.IsReady() && asset->GetTotalImageDataSize();
}
else if (assetType == azrtti_typeid<RPI::ShaderResourceGroupAsset>())
{
auto asset = m_assetCollectionAsyncLoader->GetAsset<RPI::ShaderResourceGroupAsset>(assetPath);
return (bool)asset && asset.GetId().IsValid() && asset.IsReady() && !asset->GetName().IsEmpty();
}
AZ_Error(AssetCollectionAsyncLoaderTestComponentName, false, "Can not handle asset type for assetPath: %s", assetPath.c_str());
return false;
}
//////////////////////////////////////////////////////////////////////////
} //namespace AtomBridge
} // namespace AZ
@@ -0,0 +1,141 @@
/*
* 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 <AzToolsFramework/ToolsComponents/EditorComponentBase.h>
#include <Atom/Utils/AssetCollectionAsyncLoader.h>
namespace AZ
{
namespace AtomBridge
{
/**
* Interface for AZ::AtomBridge::AssetCollectionAsyncLoaderTestBus, which is an EBus that receives requests
* to test AssetCollectionAsyncLoader API
*/
class AssetCollectionAsyncLoaderTestInterface
: public ComponentBus
{
public:
AZ_RTTI(AssetCollectionAsyncLoaderTestInterface, "{2C000A68-3B9A-4462-B8CF-E2995FA2C208}");
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
//////////////////////////////////////////////////////////////////////////
/**
* Destroys the instance of the class.
*/
virtual ~AssetCollectionAsyncLoaderTestInterface() {}
//////////////////////////////////////////////////////////////////////////
// The API
//! @pathToAssetListJson Path to a json file with a plain list of file paths.
//! Each path is the path of an asset product.
//! The AssetType will be deduced from the file extension.
//! Returns true if the asset loading job starts successfully.
virtual bool StartLoadingAssetsFromJsonFile(const AZStd::string& pathToAssetListJson) = 0;
//! @assetList Similar as above but the list of assets is given directly.
//! Returns true if the asset loading job starts successfully.
virtual bool StartLoadingAssetsFromAssetList(const AZStd::vector<AZStd::string>& assetList) = 0;
//! Cancels any pending job to that has been queued by this component.
virtual void CancelLoadingAssets() = 0;
//! Returns a list of the assets that have not been loaded yet from the Asset Processor Cache.
virtual AZStd::vector<AZStd::string> GetPendingAssetsList() const = 0;
//! Shortcut to GetPendingAssetsList().size()
virtual uint32_t GetCountOfPendingAssets() const = 0;
//! Returns true if the asset was loaded successfully.
virtual bool ValidateAssetWasLoaded(const AZStd::string& assetPath) const = 0;
};
/**
* The EBus for events defined in AssetCollectionAsyncLoaderTestInterface class .
*/
typedef AZ::EBus<AssetCollectionAsyncLoaderTestInterface> AssetCollectionAsyncLoaderTestBus;
/*
* This class is designed to be used under automation, but the user can add it to an entity
* and manually specify a json file with a list of asset paths to load asynchronously. From an user point of view
* it has no value, but for debugging it can be useful to try the AssetCollectionAsyncLoader API without having to write
* a test suite for it.
*/
class AssetCollectionAsyncLoaderTestComponent
: public AzToolsFramework::Components::EditorComponentBase
, public AssetCollectionAsyncLoaderTestBus::Handler
{
public:
AZ_EDITOR_COMPONENT(AssetCollectionAsyncLoaderTestComponent, "{D0A558AD-F8CD-4DB8-80A4-40B4E1F947FA}"
, AzToolsFramework::Components::EditorComponentBase
, AssetCollectionAsyncLoaderTestInterface)
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// AssetCollectionAsyncLoaderTestBus overrides
bool StartLoadingAssetsFromJsonFile(const AZStd::string& pathToAssetListJson) override;
bool StartLoadingAssetsFromAssetList(const AZStd::vector<AZStd::string>& assetList) override;
void CancelLoadingAssets() override;
AZStd::vector<AZStd::string> GetPendingAssetsList() const override;
uint32_t GetCountOfPendingAssets() const override;
bool ValidateAssetWasLoaded(const AZStd::string& assetPath) const override;
//////////////////////////////////////////////////////////////////////////
protected:
enum class State
{
Idle,
LoadingAssets,
FatalError,
};
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0xdd5ab934));
}
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services)
{
services.push_back(AZ_CRC("AssetCollectionAsyncLoaderTest", 0xdd5ab934));
}
static void Reflect(AZ::ReflectContext* context);
AZ::Crc32 OnStartCancelButtonClicked();
AZStd::string GetStartCancelButtonText() const;
//! Serialized member variables.
//! A user editable path to a json file that contains the list of assets to load.
AZStd::string m_pathToAssetListJson;
//! Non-serialized member variables.
State m_state = State::Idle;
AZStd::unordered_set<AZStd::string> m_pendingAssets; // List of assets that have not been loaded yet.
// This is the Object Under Test
AZStd::unique_ptr<AZ::AssetCollectionAsyncLoader> m_assetCollectionAsyncLoader;
};
} // namespace AtomBridge
} // namespace AZ
@@ -0,0 +1,455 @@
/*
* 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 "FlyCameraInputComponent.h"
#include <ISystem.h>
#include <ITimer.h>
#include <IConsole.h>
#include <AzCore/Component/Component.h>
#include <AzCore/Component/TransformBus.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/Math/Transform.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
#include <AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
#include <MathConversion.h>
#include <Atom/RPI.Public/ViewProviderBus.h>
#include <Atom/RPI.Public/View.h>
#include <AzFramework/Components/CameraBus.h>
using namespace AzFramework;
using namespace AZ::AtomBridge;
//////////////////////////////////////////////////////////////////////////////
namespace
{
//////////////////////////////////////////////////////////////////////////
int GenerateThumbstickTexture()
{
// [GFX TODO] Get Atom test fly cam virtual thumbsticks working on mobile
return 0;
}
//////////////////////////////////////////////////////////////////////////
void ReleaseThumbstickTexture([[maybe_unused]] int textureId)
{
// [GFX TODO] Get Atom test fly cam virtual thumbsticks working on mobile
}
//////////////////////////////////////////////////////////////////////////
void DrawThumbstick([[maybe_unused]] Vec2 initialPosition,
[[maybe_unused]] Vec2 currentPosition,
[[maybe_unused]] int textureId)
{
// [GFX TODO] Get Atom test fly cam virtual thumbsticks working on mobile
// we do not have any 2D drawing capability like IDraw2d in Atom yet
}
}
//////////////////////////////////////////////////////////////////////////////
const AZ::Crc32 FlyCameraInputComponent::UnknownInputChannelId("unknown_input_channel_id");
//////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
}
//////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("InputService", 0xd41af40c));
}
//////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
serializeContext->Class<FlyCameraInputComponent, AZ::Component>()
->Version(1)
->Field("Move Speed", &FlyCameraInputComponent::m_moveSpeed)
->Field("Rotation Speed", &FlyCameraInputComponent::m_rotationSpeed)
->Field("Mouse Sensitivity", &FlyCameraInputComponent::m_mouseSensitivity)
->Field("Invert Rotation Input X", &FlyCameraInputComponent::m_InvertRotationInputAxisX)
->Field("Invert Rotation Input Y", &FlyCameraInputComponent::m_InvertRotationInputAxisY)
->Field("Is enabled", &FlyCameraInputComponent::m_isEnabled);
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<FlyCameraInputComponent>("Fly Camera Input", "The Fly Camera Input allows you to control the camera")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute("Category", "Gameplay")
->Attribute("Icon", "Editor/Icons/Components/CameraRig.svg")
->Attribute("ViewportIcon", "Editor/Icons/Components/Viewport/CameraRig.png")
->Attribute("AutoExpand", true)
->Attribute("AppearsInAddComponentMenu", AZ_CRC("Game", 0x232b318c))
->DataElement(0, &FlyCameraInputComponent::m_moveSpeed, "Move Speed", "Speed at which the camera moves")
->Attribute("Min", 1.0f)
->Attribute("Max", 100.0f)
->Attribute("ChangeNotify", AZ_CRC("RefreshValues", 0x28e720d4))
->DataElement(0, &FlyCameraInputComponent::m_rotationSpeed, "Rotation Speed", "Speed at which the camera rotates")
->Attribute("Min", 1.0f)
->Attribute("Max", 100.0f)
->Attribute("ChangeNotify", AZ_CRC("RefreshValues", 0x28e720d4))
->DataElement(0, &FlyCameraInputComponent::m_mouseSensitivity, "Mouse Sensitivity", "Mouse sensitivity factor")
->Attribute("Min", 0.0f)
->Attribute("Max", 1.0f)
->Attribute("ChangeNotify", AZ_CRC("RefreshValues", 0x28e720d4))
->DataElement(0, &FlyCameraInputComponent::m_InvertRotationInputAxisX, "Invert Rotation Input X", "Invert rotation input x-axis")
->Attribute("ChangeNotify", AZ_CRC("RefreshValues", 0x28e720d4))
->DataElement(0, &FlyCameraInputComponent::m_InvertRotationInputAxisY, "Invert Rotation Input Y", "Invert rotation input y-axis")
->Attribute("ChangeNotify", AZ_CRC("RefreshValues", 0x28e720d4))
->DataElement(AZ::Edit::UIHandlers::CheckBox, &FlyCameraInputComponent::m_isEnabled,
"Is Initially Enabled", "When checked, the fly cam input is enabled on activate, else it has to be specifically enabled.");
}
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflection);
if (behaviorContext)
{
behaviorContext->EBus<FlyCameraInputBus>("FlyCameraInputBus")
->Attribute(AZ::Script::Attributes::ExcludeFrom, AZ::Script::Attributes::ExcludeFlags::Preview)
->Event("SetIsEnabled", &FlyCameraInputBus::Events::SetIsEnabled)
->Event("GetIsEnabled", &FlyCameraInputBus::Events::GetIsEnabled);
}
}
//////////////////////////////////////////////////////////////////////////////
FlyCameraInputComponent::~FlyCameraInputComponent()
{
ReleaseThumbstickTexture(m_thumbstickTextureId);
}
//////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::Init()
{
m_thumbstickTextureId = GenerateThumbstickTexture();
}
//////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::Activate()
{
InputChannelEventListener::Connect();
AZ::TickBus::Handler::BusConnect();
FlyCameraInputBus::Handler::BusConnect(GetEntityId());
}
//////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::Deactivate()
{
FlyCameraInputBus::Handler::BusDisconnect();
AZ::TickBus::Handler::BusDisconnect();
InputChannelEventListener::Disconnect();
}
//////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::OnTick(float deltaTime, AZ::ScriptTimePoint /*time*/)
{
if (!m_isEnabled)
{
return;
}
AZ::Transform worldTransform = AZ::Transform::Identity();
EBUS_EVENT_ID_RESULT(worldTransform, GetEntityId(), AZ::TransformBus, GetWorldTM);
// Update movement
const float moveSpeed = m_moveSpeed * deltaTime;
const AZ::Vector3 right = worldTransform.GetBasisX();
const AZ::Vector3 forward = worldTransform.GetBasisY();
const AZ::Vector3 movement = (forward * m_movement.y) + (right * m_movement.x);
const AZ::Vector3 newPosition = worldTransform.GetTranslation() + (movement * moveSpeed);
worldTransform.SetTranslation(newPosition);
const Vec2 invertedRotation(m_InvertRotationInputAxisX ? m_rotation.x : -m_rotation.x,
m_InvertRotationInputAxisY ? m_rotation.y : -m_rotation.y);
// Update rotation (not sure how to do this properly using just AZ::Quaternion)
const AZ::Quaternion worldOrientation = worldTransform.GetRotation();
const Ang3 rotation(AZQuaternionToLYQuaternion(worldOrientation));
const Ang3 newRotation = rotation + Ang3(DEG2RAD(invertedRotation.y), 0.f, DEG2RAD(invertedRotation.x)) * m_rotationSpeed;
const AZ::Quaternion newOrientation = LYQuaternionToAZQuaternion(Quat(newRotation));
worldTransform.SetRotation(newOrientation);
EBUS_EVENT_ID(GetEntityId(), AZ::TransformBus, SetWorldTM, worldTransform);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool FlyCameraInputComponent::OnInputChannelEventFiltered(const InputChannel& inputChannel)
{
if (!m_isEnabled)
{
return false;
}
const InputDeviceId& deviceId = inputChannel.GetInputDevice().GetInputDeviceId();
if (InputDeviceMouse::IsMouseDevice(deviceId))
{
OnMouseEvent(inputChannel);
}
else if (InputDeviceKeyboard::IsKeyboardDevice(deviceId))
{
OnKeyboardEvent(inputChannel);
}
else if (InputDeviceTouch::IsTouchDevice(deviceId))
{
const InputChannel::PositionData2D* positionData2D = inputChannel.GetCustomData<InputChannel::PositionData2D>();
if (positionData2D)
{
float defaultViewWidth = GetViewWidth();
float defaultViewHeight = GetViewHeight();
const Vec2 screenPosition(positionData2D->m_normalizedPosition.GetX() * defaultViewWidth,
positionData2D->m_normalizedPosition.GetY() * defaultViewHeight);
OnTouchEvent(inputChannel, screenPosition);
}
}
else if (AzFramework::InputDeviceGamepad::IsGamepadDevice(deviceId))
{
OnGamepadEvent(inputChannel);
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::SetIsEnabled(bool isEnabled)
{
m_isEnabled = isEnabled;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
bool FlyCameraInputComponent::GetIsEnabled()
{
return m_isEnabled;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
float Snap_s360(float val)
{
if (val < 0.0f)
{
val = f32(360.0f + fmodf(val, 360.0f));
}
else if (val >= 360.0f)
{
val = f32(fmodf(val, 360.0f));
}
return val;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::OnMouseEvent(const InputChannel& inputChannel)
{
const InputChannelId& channelId = inputChannel.GetInputChannelId();
if (channelId == InputDeviceMouse::Movement::X)
{
m_rotation.x = Snap_s360(inputChannel.GetValue() * m_mouseSensitivity);
}
else if (channelId == InputDeviceMouse::Movement::Y)
{
m_rotation.y = Snap_s360(inputChannel.GetValue() * m_mouseSensitivity);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::OnKeyboardEvent(const InputChannel& inputChannel)
{
if (gEnv && gEnv->pConsole && gEnv->pConsole->IsOpened())
{
return;
}
const InputChannelId& channelId = inputChannel.GetInputChannelId();
if (channelId == InputDeviceKeyboard::Key::AlphanumericW)
{
m_movement.y = inputChannel.GetValue();
}
if (channelId == InputDeviceKeyboard::Key::AlphanumericA)
{
m_movement.x = -inputChannel.GetValue();
}
if (channelId == InputDeviceKeyboard::Key::AlphanumericS)
{
m_movement.y = -inputChannel.GetValue();
}
if (channelId == InputDeviceKeyboard::Key::AlphanumericD)
{
m_movement.x = inputChannel.GetValue();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::OnGamepadEvent(const InputChannel& inputChannel)
{
const InputChannelId& channelId = inputChannel.GetInputChannelId();
if (channelId == InputDeviceGamepad::ThumbStickAxis1D::LX)
{
m_movement.x = inputChannel.GetValue();
}
if (channelId == InputDeviceGamepad::ThumbStickAxis1D::LY)
{
m_movement.y = inputChannel.GetValue();
}
if (channelId == InputDeviceGamepad::ThumbStickAxis1D::RX)
{
m_rotation.x = inputChannel.GetValue();
}
if (channelId == InputDeviceGamepad::ThumbStickAxis1D::RY)
{
m_rotation.y = inputChannel.GetValue();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::OnTouchEvent(const InputChannel& inputChannel, const Vec2& screenPosition)
{
if (inputChannel.IsStateBegan())
{
const float screenCentreX = GetViewWidth() * 0.5f;
if (screenPosition.x <= screenCentreX)
{
if (m_leftFingerId == UnknownInputChannelId)
{
// Initiate left thumb-stick (movement)
m_leftDownPosition = screenPosition;
m_leftFingerId = inputChannel.GetInputChannelId().GetNameCrc32();
DrawThumbstick(m_leftDownPosition, screenPosition, m_thumbstickTextureId);
}
}
else
{
if (m_rightFingerId == UnknownInputChannelId)
{
// Initiate right thumb-stick (rotation)
m_rightDownPosition = screenPosition;
m_rightFingerId = inputChannel.GetInputChannelId().GetNameCrc32();
DrawThumbstick(m_rightDownPosition, screenPosition, m_thumbstickTextureId);
}
}
}
else if (inputChannel.GetInputChannelId().GetNameCrc32() == m_leftFingerId)
{
// Update left thumb-stick (movement)
OnVirtualLeftThumbstickEvent(inputChannel, screenPosition);
}
else if (inputChannel.GetInputChannelId().GetNameCrc32() == m_rightFingerId)
{
// Update right thumb-stick (rotation)
OnVirtualRightThumbstickEvent(inputChannel, screenPosition);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::OnVirtualLeftThumbstickEvent(const InputChannel& inputChannel, const Vec2& screenPosition)
{
if (inputChannel.GetInputChannelId().GetNameCrc32() != m_leftFingerId)
{
return;
}
switch (inputChannel.GetState())
{
case InputChannel::State::Ended:
{
// Stop movement
m_leftFingerId = UnknownInputChannelId;
m_movement = ZERO;
}
break;
case InputChannel::State::Updated:
{
// Calculate movement
const float discRadius = GetViewWidth() * m_virtualThumbstickRadiusAsPercentageOfScreenWidth;
const float distScalar = 1.0f / discRadius;
Vec2 dist = screenPosition - m_leftDownPosition;
dist *= distScalar;
m_movement.x = AZ::GetClamp(dist.x, -1.0f, 1.0f);
m_movement.y = AZ::GetClamp(-dist.y, -1.0f, 1.0f);
DrawThumbstick(m_leftDownPosition, screenPosition, m_thumbstickTextureId);
}
break;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void FlyCameraInputComponent::OnVirtualRightThumbstickEvent(const InputChannel& inputChannel, const Vec2& screenPosition)
{
if (inputChannel.GetInputChannelId().GetNameCrc32() != m_rightFingerId)
{
return;
}
switch (inputChannel.GetState())
{
case InputChannel::State::Ended:
{
// Stop rotation
m_rightFingerId = UnknownInputChannelId;
m_rotation = ZERO;
}
break;
case InputChannel::State::Updated:
{
// Calculate rotation
const float discRadius = GetViewWidth() * m_virtualThumbstickRadiusAsPercentageOfScreenWidth;
const float distScalar = 1.0f / discRadius;
Vec2 dist = screenPosition - m_rightDownPosition;
dist *= distScalar;
m_rotation.x = AZ::GetClamp(dist.x, -1.0f, 1.0f);
m_rotation.y = AZ::GetClamp(dist.y, -1.0f, 1.0f);
DrawThumbstick(m_rightDownPosition, screenPosition, m_thumbstickTextureId);
}
break;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
float FlyCameraInputComponent::GetViewWidth() const
{
float viewWidth = 256.0f;
Camera::CameraRequestBus::EventResult(viewWidth, GetEntityId(), &Camera::CameraRequestBus::Events::GetFrustumWidth);
return viewWidth;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
float FlyCameraInputComponent::GetViewHeight() const
{
float viewHeight = 256.0f;
Camera::CameraRequestBus::EventResult(viewHeight, GetEntityId(), &Camera::CameraRequestBus::Events::GetFrustumHeight);
return viewHeight;
}
@@ -0,0 +1,91 @@
/*
* 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/Component/Component.h>
#include <AzCore/Component/TickBus.h>
#include <AzFramework/Input/Events/InputChannelEventListener.h>
#include <Cry_Math.h>
#include <AtomBridge/FlyCameraInputBus.h>
namespace AZ
{
namespace AtomBridge
{
/// This is based on the FlyCameraInputComponent in SamplesProject and is just used to test the CameraComponent
class FlyCameraInputComponent
: public AZ::Component
, public AZ::TickBus::Handler
, public AzFramework::InputChannelEventListener
, public FlyCameraInputBus::Handler
{
public:
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void Reflect(AZ::ReflectContext* reflection);
AZ_COMPONENT(FlyCameraInputComponent, "{EB588B1E-AC2E-44AA-A1E6-E5960942E950}");
virtual ~FlyCameraInputComponent();
// AZ::Component
void Init() override;
void Activate() override;
void Deactivate() override;
// AZ::TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
// AzFramework::InputChannelEventListener
bool OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel) override;
// FlyCameraInputInterface
void SetIsEnabled(bool isEnabled) override;
bool GetIsEnabled() override;
private:
void OnMouseEvent(const AzFramework::InputChannel& inputChannel);
void OnKeyboardEvent(const AzFramework::InputChannel& inputChannel);
void OnGamepadEvent(const AzFramework::InputChannel& inputChannel);
void OnTouchEvent(const AzFramework::InputChannel& inputChannel, const Vec2& screenPosition);
void OnVirtualLeftThumbstickEvent(const AzFramework::InputChannel& inputChannel, const Vec2& screenPosition);
void OnVirtualRightThumbstickEvent(const AzFramework::InputChannel& inputChannel, const Vec2& screenPosition);
float GetViewWidth() const;
float GetViewHeight() const;
static const AZ::Crc32 UnknownInputChannelId;
// Editable Properties
float m_moveSpeed = 20.0f;
float m_rotationSpeed = 5.0f;
float m_mouseSensitivity = 0.025f;
float m_virtualThumbstickRadiusAsPercentageOfScreenWidth = 0.1f;
bool m_InvertRotationInputAxisX = false;
bool m_InvertRotationInputAxisY = false;
bool m_isEnabled = true;
// Run-time Properties
Vec2 m_movement = ZERO;
Vec2 m_rotation = ZERO;
Vec2 m_leftDownPosition = ZERO;
AZ::Crc32 m_leftFingerId = UnknownInputChannelId;
Vec2 m_rightDownPosition = ZERO;
AZ::Crc32 m_rightFingerId = UnknownInputChannelId;
int m_thumbstickTextureId = 0;
};
}
}
@@ -0,0 +1,20 @@
#
# 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.
#
set(FILES
Source/AtomBridgeEditorModule.cpp
Source/AtomBridgeModule.cpp
Source/AtomBridgeModule.h
Source/BuilderComponent.cpp
Source/BuilderComponent.h
Source/Editor/AssetCollectionAsyncLoaderTestComponent.cpp
Source/Editor/AssetCollectionAsyncLoaderTestComponent.h
)
@@ -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.
#
set(FILES
Include/AtomBridge/AtomBridgeBus.h
Include/AtomBridge/FlyCameraInputBus.h
Source/AtomBridgeSystemComponent.cpp
Source/AtomBridgeSystemComponent.h
Source/FlyCameraInputComponent.cpp
Source/FlyCameraInputComponent.h
Source/AtomDebugDisplayViewportInterface.cpp
Source/AtomDebugDisplayViewportInterface.h
)
@@ -0,0 +1,14 @@
#
# 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.
#
set(FILES
Source/AtomBridgeModule.cpp
)
@@ -0,0 +1,36 @@
{
"Dependencies": [
{
"Uuid": "a218db9eb2114477b46600fea4441a6c",
"VersionConstraints": [
"~>0.1.0"
],
"_comment": "Atom RPI"
},
{
"Uuid": "c7ff89ad6e8b4b45b2fadef2bcf12d6e",
"VersionConstraints": [
"~>0.1.0"
],
"_comment": "Atom_Bootstrap"
}
],
"GemFormatVersion": 4,
"Uuid": "b55b2738aa4a46c8b034fe98e6e5158b",
"Name": "Atom_AtomBridge",
"DisplayName": "Atom.AtomBridge",
"Version": "0.1.0",
"Summary": "A short description of my Gem.",
"Tags": ["Untagged"],
"IconPath": "preview.png",
"Modules": [
{
"Type": "GameModule"
},
{
"Name": "Editor",
"Type": "EditorModule",
"Extends": "GameModule"
}
]
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6d6204c6730e5675791765ca194e9b1cbec282208e280507de830afc2805e5fa
size 41127
@@ -0,0 +1,12 @@
#
# 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.
#
add_subdirectory(Code)
@@ -0,0 +1,57 @@
#
# 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.
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
ly_add_target(
NAME AtomFont ${PAL_TRAIT_MONOLITHIC_DRIVEN_LIBRARY_TYPE}
NAMESPACE Gem
FILES_CMAKE
atomfont_files.cmake
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PUBLIC
Include
Source
BUILD_DEPENDENCIES
PRIVATE
3rdParty::FreeType2
AZ::AzCore
AZ::AtomCore
Legacy::CryCommon
Gem::Atom_RHI.Reflect
Gem::Atom_RPI.Public
Gem::Atom_Bootstrap.Headers
)
################################################################################
# Tests
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AtomFont.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
atomfont_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
)
ly_add_googletest(
NAME Gem::AtomFont.Tests
)
endif()
@@ -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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#if !defined(USE_NULLFONT_ALWAYS)
#include <Cry_Vector2.h>
#include <IXml.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/smart_ptr/weak_ptr.h>
#include <map>
namespace AZ
{
class FFont;
//! AtomFont is the font system manager.
//! AtomFont manages the lifetime of FFont instances, each of which represents an individual font (e.g Courier New Italic)
//! AtomFont also knows about font families (e.g Courier New + [Italic, Bold, Normal, Bold Italic]), languages, etc,
//! and manages their loading & saving together.
class AtomFont
: public ICryFont
{
friend class FFont;
public:
struct GlyphSize
{
union
{
struct // unnamed struct
{
int32_t x;
int32_t y;
};
int32_t data[2];
};
GlyphSize() : x(0), y(0) {}
GlyphSize(const int32_t sizeX, const int32_t sizeY) : x(sizeX), y(sizeY) {}
GlyphSize(const Vec2i v) : x(v.x), y(v.y) {}
bool operator==(const GlyphSize& rhs) const {return x == rhs.x && y == rhs.y;}
};
static const GlyphSize defaultGlyphSize; //!< Default glyph size indicates that glyphs in the font texture
//!< should be rendered at the maximum resolution supported by
//!< the font texture's glyph cell/slot configuration (configured
//!< via font XML).
public:
AtomFont(ISystem* system);
virtual ~AtomFont();
//////////////////////////////////////////////////////////////////////////////////
// ICryFont interface
void Release() override;
IFFont* NewFont(const char* fontName) override;
IFFont* GetFont(const char* fontName) const override;
FontFamilyPtr LoadFontFamily(const char* fontFamilyName) override;
FontFamilyPtr GetFontFamily(const char* fontFamilyName) override;
void AddCharsToFontTextures(FontFamilyPtr fontFamily, const char* chars, int glyphSizeX = ICryFont::defaultGlyphSizeX, int glyphSizeY = ICryFont::defaultGlyphSizeY) override;
void SetRendererProperties([[maybe_unused]] IRenderer* renderer) override {}
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const override {}
string GetLoadedFontNames() const;
void OnLanguageChanged() override;
void ReloadAllFonts() override;
//////////////////////////////////////////////////////////////////////////////////
public:
void UnregisterFont(const char* fontName);
private:
typedef std::map<string, FFont*> FontMap;
typedef FontMap::iterator FontMapItor;
typedef FontMap::const_iterator FontMapConstItor;
typedef AZStd::map<AZStd::string, AZStd::weak_ptr<FontFamily>> FontFamilyMap;
typedef AZStd::map<FontFamily*, FontFamilyMap::iterator> FontFamilyReverseLookupMap;
private:
//! Convenience method for loading fonts
IFFont* LoadFont(const char* fontName);
//! Called when final FontFamily shared_ptr is destroyed; do not call directly.
void ReleaseFontFamily(FontFamily* fontFamily);
//! Adds new entries into both font family maps for the given font family
//!
//! Note that it's not possible to update Font Family mappings with this
//! method. The only way to do that would be to release the font family
//! and re-load it with the new values.
//!
//! \return True only if the Font Family was added to the maps, false for all other cases (such as
//! when the font family is already mapped).
bool AddFontFamilyToMaps(const char* fontFamilyFilename, const char* fontFamilyName, FontFamilyPtr fontFamily);
//! Internal method that (possibly) makes several attempts at locating and loading a given font family XML.
//! \param fontFamilyName The name of the font family, or path to a font family file.
//! \param outputDirectory Path to loaded font family (no filename), may need resolving with PathUtil::MakeGamePath.
//! \param outputFullPath Full path to loaded font family, may need resolving with PathUtil::MakeGamePath.
XmlNodeRef LoadFontFamilyXml(const char* fontFamilyName, string& outputDirectory, string& outputFullPath);
private:
FontMap m_fonts;
FontFamilyMap m_fontFamilies; //!< Map font family names to weak ptrs so we can construct shared_ptrs but not keep a ref ourselves.
FontFamilyReverseLookupMap m_fontFamilyReverseLookup; //<! FontFamily pointer reverse-lookup for quick removal
ISystem* m_system;
int r_persistFontFamilies = 1; //!< Persist fonts for application lifetime to prevent unnecessary work; enabled by default.
AZStd::vector<FontFamilyPtr> m_persistedFontFamilies; //!< Stores persisted fonts (if "persist font families" is enabled)
};
}
#endif
@@ -0,0 +1,34 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <vector>
#define ATOMFONT_EXPORTS
#include <platform.h>
#include <IFont.h>
#include <ILog.h>
#include <IConsole.h>
#include <IRenderer.h>
#include <CrySizer.h>
#define USE_NULLFONT
#if defined(DEDICATED_SERVER)
#define USE_NULLFONT_ALWAYS 1
#endif
@@ -0,0 +1,92 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Dummy font implementation (dedicated server)
#pragma once
#if defined(USE_NULLFONT)
#include <IFont.h>
namespace AZ
{
class AtomNullFFont
: public IFFont
{
public:
using TextDrawContext = STextDrawContext;
AtomNullFFont() {}
~AtomNullFFont() override {}
int32_t AddRef() override { return 0; };
int32_t Release() override { return 0; };
bool Load([[maybe_unused]] const char* fontFilePath, [[maybe_unused]] unsigned int width, [[maybe_unused]] unsigned int height, [[maybe_unused]] unsigned int widthNumSlots, [[maybe_unused]] unsigned int heightNumSlots, [[maybe_unused]] unsigned int flags, [[maybe_unused]] float sizeRatio) override { return true; }
bool Load([[maybe_unused]] const char* xmlFile) override { return true; }
void Free() override {}
void DrawString([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] const char* str, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const TextDrawContext& ctx) override {}
void DrawString([[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z, [[maybe_unused]] const char* str, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const TextDrawContext& ctx) override {}
Vec2 GetTextSize([[maybe_unused]] const char* str, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const TextDrawContext& ctx) override { return Vec2(0.0f, 0.0f); }
size_t GetTextLength([[maybe_unused]] const char* str, [[maybe_unused]] const bool asciiMultiLine) const override { return 0; }
void WrapText(string& result, [[maybe_unused]] float maxWidth, const char* str, [[maybe_unused]] const TextDrawContext& ctx) override { result = str; }
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const override {}
void GetGradientTextureCoord([[maybe_unused]] float& minU, [[maybe_unused]] float& minV, [[maybe_unused]] float& maxU, [[maybe_unused]] float& maxV) const override {}
unsigned int GetEffectId([[maybe_unused]] const char* effectName) const override { return 0; }
unsigned int GetNumEffects() const override { return 0; }
const char* GetEffectName([[maybe_unused]] unsigned int effectId) const override { return nullptr; }
Vec2 GetMaxEffectOffset([[maybe_unused]] unsigned int effectId) const override { return Vec2(); }
bool DoesEffectHaveTransparency([[maybe_unused]] unsigned int effectId) const override { return false; }
void AddCharsToFontTexture([[maybe_unused]] const char* chars, [[maybe_unused]] int glyphSizeX, [[maybe_unused]] int glyphSizeY) override {}
Vec2 GetKerning([[maybe_unused]] uint32_t leftGlyph, [[maybe_unused]] uint32_t rightGlyph, [[maybe_unused]] const TextDrawContext& ctx) const override { return Vec2(); }
float GetAscender([[maybe_unused]] const TextDrawContext& ctx) const override { return 0.0f; }
float GetBaseline([[maybe_unused]] const TextDrawContext& ctx) const override { return 0.0f; }
float GetSizeRatio() const override { return IFFontConstants::defaultSizeRatio; }
uint32_t GetNumQuadsForText([[maybe_unused]] const char* str, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const TextDrawContext& ctx) override { return 0; }
uint32_t WriteTextQuadsToBuffers([[maybe_unused]] SVF_P2F_C4B_T2F_F4B* verts, [[maybe_unused]] uint16_t* indices, [[maybe_unused]] uint32_t maxQuads, [[maybe_unused]] float x, [[maybe_unused]] float y, [[maybe_unused]] float z, [[maybe_unused]] const char* str, [[maybe_unused]] const bool asciiMultiLine, [[maybe_unused]] const TextDrawContext& ctx) override { return 0; }
int GetFontTextureId() override { return -1; }
uint32_t GetFontTextureVersion() override { return 0; }
};
class AtomNullFont
: public ICryFont
{
public:
virtual void Release() override {}
virtual IFFont* NewFont([[maybe_unused]] const char* fontName) override { return &NullFFont; }
virtual IFFont* GetFont([[maybe_unused]] const char* fontName) const override { return &NullFFont; }
virtual FontFamilyPtr LoadFontFamily([[maybe_unused]] const char* fontFamilyName) override { CRY_ASSERT(false); return nullptr; }
virtual FontFamilyPtr GetFontFamily([[maybe_unused]] const char* fontFamilyName) override { CRY_ASSERT(false); return nullptr; }
virtual void AddCharsToFontTextures([[maybe_unused]] FontFamilyPtr fontFamily, [[maybe_unused]] const char* chars, [[maybe_unused]] int glyphSizeX, [[maybe_unused]] int glyphSizeY) override {};
virtual void SetRendererProperties([[maybe_unused]] IRenderer* pRenderer) override {}
virtual void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const override {}
virtual string GetLoadedFontNames() const override { return ""; }
virtual void OnLanguageChanged() override { }
virtual void ReloadAllFonts() override { }
private:
static AtomNullFFont NullFFont;
};
}
#endif // USE_NULLFONT
@@ -0,0 +1,71 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
namespace AZ
{
class FontBitmap
{
public:
FontBitmap();
~FontBitmap();
int Blur(int iterationCount);
int Scale(float scaleX, float scaleY);
int BlitFrom(FontBitmap* source, int srcX, int srcY, int destX, int destY, int width, int height);
int BlitTo(FontBitmap* destination, int destX, int destY, int srcX, int srcY, int width, int height);
int Create(int width, int height);
int Release();
int SaveBitmap(const string& fileName);
int Get32Bpp(unsigned int** buffer)
{
(*buffer) = new unsigned int[m_width * m_height];
if (!(*buffer))
{
return 0;
}
int dataSize = m_width * m_height;
for (int i = 0; i < dataSize; i++)
{
(*buffer)[i] = (m_data[i] << 24) | (m_data[i] << 16) | (m_data[i] << 8) | (m_data[i]);
}
return 1;
}
int GetWidth() { return m_width; }
int GetHeight() { return m_height; }
void SetRenderData(void* renderData) { m_renderData = renderData; };
void* GetRenderData() { return m_renderData; };
void GetMemoryUsage ([[maybe_unused]] class ICrySizer* sizer) {};
unsigned char* GetData() { return m_data; }
public:
int m_width;
int m_height;
unsigned char* m_data;
void* m_renderData;
};
}
@@ -0,0 +1,380 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Font class.
#pragma once
#if !defined(USE_NULLFONT_ALWAYS)
#include <vector>
#include <CryCommon/Cry_Math.h>
#include <CryCommon/Cry_Color.h>
#include <CryCommon/CryString.h>
#include "AtomFont.h"
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/smart_ptr/intrusive_base.h>
#include <AzCore/std/containers/map.h>
#include <Atom/RHI.Reflect/Base.h>
#include <Atom/RHI/StreamBufferView.h>
#include <Atom/RHI/IndexBufferView.h>
#include <Atom/RHI/PipelineState.h>
#include <Atom/RHI/DrawList.h>
#include <Atom/RHI/Image.h>
#include <Atom/RPI.Public/Buffer/Buffer.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
#include <Atom/RPI.Public/Shader/Shader.h>
#include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/DynamicDraw/DynamicDrawSystemInterface.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/Image/StreamingImage.h>
#include <Atom/Bootstrap/DefaultWindowBus.h>
#include <Atom/Bootstrap/BootstrapNotificationBus.h>
struct ISystem;
namespace AZ
{
class FontTexture;
struct FontDeleter
{
void operator () (const AZStd::intrusive_refcount<AZStd::atomic_uint, FontDeleter>* ptr) const;
};
//! FFont is the implementation of IFFont used to draw text with a particular font (e.g. Consolas Italic)
//! FFont manages creation of a gpu texture to cache the font and generates draw commands that use that texture.
//! FFont's are managed by AtomFont as either individual font instances or a font family
//! that collects all the variations (italic, bold, bold italic, normal).
class FFont
: public IFFont
, public AZStd::intrusive_refcount<AZStd::atomic_uint, FontDeleter>
, private AZ::Render::Bootstrap::NotificationBus::Handler
{
using ref_count = AZStd::intrusive_refcount<AZStd::atomic_uint, FontDeleter>;
friend FontDeleter;
public:
using TextDrawContext = STextDrawContext;
//! Determines how characters of different sizes should be handled during render.
enum class SizeBehavior
{
Scale, //!< Default behavior; glyphs rendered at different sizes are rendered on scaled geometry
Rerender //!< Similar to Scale, but the glyph in the font texture is re-rendered to match the target
//!< size, as long as the size isn't greater than the maximum glyph/slot resolution as
//!< configured for the font texture in the font XML.
};
//! The hinting visual algorithm to be used (when hinting is enabled)
enum class HintStyle
{
Normal, //!< Default hinting behavior provided by font renderer
Light //!< Produces fuzzier glyphs but more accurately tracks glyph shape
};
//! Chooses whether hinting info should be obtained from the font, turned off entirely, or automatically generated
enum class HintBehavior
{
Default, //!< Obtain hinting data from font itself
AutoHint, //!< Procedurally derive hinting information from glyph
NoHinting, //!< Disable hinting entirely
};
//! Simple struct used to communicate font hinting parameters to font renderer.
struct FontHintParams
{
FontHintParams()
: hintStyle(HintStyle::Normal)
, hintBehavior(HintBehavior::Default) { }
HintStyle hintStyle;
HintBehavior hintBehavior;
};
struct FontRenderingPass
{
ColorB m_color;
Vec2 m_posOffset;
int m_blendSrc;
int m_blendDest;
FontRenderingPass()
: m_color(255, 255, 255, 255)
, m_posOffset(0, 0)
, m_blendSrc(GS_BLSRC_SRCALPHA)
, m_blendDest(GS_BLDST_ONEMINUSSRCALPHA)
{
}
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
};
struct FontEffect
{
string m_name;
std::vector<FontRenderingPass> m_passes;
FontEffect(const char* name)
: m_name(name)
{
assert(name);
}
FontRenderingPass* AddPass()
{
m_passes.push_back(FontRenderingPass());
return &m_passes[m_passes.size() - 1];
}
void ClearPasses()
{
m_passes.resize(0);
}
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
};
typedef std::vector<FontEffect> FontEffects;
typedef FontEffects::iterator FontEffectsIterator;
struct FontPipelineStateMapKey
{
AZ::RPI::SceneId m_sceneId; // which scene pipeline state is attached to (via Render Pipeline)
AZ::RHI::DrawListTag m_drawListTag; // which render pass this pipeline draws in by default
bool operator<(const FontPipelineStateMapKey& other) const
{
return m_sceneId < other.m_sceneId
|| (m_sceneId == other.m_sceneId && m_drawListTag < other.m_drawListTag);
}
};
struct FontShaderData
{
const char* m_fontShaderFilepath;
AZ::Data::Instance<AZ::RPI::Shader> m_fontShader;
AZ::Data::Asset<AZ::RPI::ShaderResourceGroupAsset> m_perDrawSrgAsset;
AZ::RPI::ShaderVariantKey m_shaderVariantKeyFallback;
AZ::RHI::ShaderInputImageIndex m_imageInputIndex;
AZ::RHI::ShaderInputConstantIndex m_viewProjInputIndex;
AZ::RPI::ShaderVariantStableId m_fontVariantStableId;
AZ::RHI::DrawListTag m_drawListTag;
AZStd::map<FontPipelineStateMapKey, AZ::RHI::ConstPtr<AZ::RHI::PipelineState>> m_pipelineStates;
};
public:
/////////////////////////////////////////////////////////////////////////////////////////////////
// IFFont interface
int32_t AddRef() override;
int32_t Release() override;
bool Load(const char* fontFilePath, unsigned int width, unsigned int height, unsigned int widthNumSlots, unsigned int heightNumSlots, unsigned int flags, float sizeRatio) override;
bool Load(const char* xmlFile) override;
void Free() override;
void DrawString(float x, float y, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) override;
void DrawString(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) override;
Vec2 GetTextSize(const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) override;
size_t GetTextLength(const char* str, const bool asciiMultiLine) const override;
void WrapText(string& result, float maxWidth, const char* str, const TextDrawContext& ctx) override;
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const override {};
void GetGradientTextureCoord(float& minU, float& minV, float& maxU, float& maxV) const override;
unsigned int GetEffectId(const char* effectName) const override;
unsigned int GetNumEffects() const override;
const char* GetEffectName(unsigned int effectId) const override;
Vec2 GetMaxEffectOffset(unsigned int effectId) const override;
bool DoesEffectHaveTransparency(unsigned int effectId) const override;
void AddCharsToFontTexture(const char* chars, int glyphSizeX = ICryFont::defaultGlyphSizeX, int glyphSizeY = ICryFont::defaultGlyphSizeY) override;
Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph, const TextDrawContext& ctx) const override;
float GetAscender(const TextDrawContext& ctx) const override;
float GetBaseline(const TextDrawContext& ctx) const override;
float GetSizeRatio() const override;
uint32_t GetNumQuadsForText(const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) override;
uint32_t WriteTextQuadsToBuffers(SVF_P2F_C4B_T2F_F4B* verts, uint16_t* indices, uint32_t maxQuads, float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) override;
int GetFontTextureId() override {return -1;} // old Cry Interface, disable
uint32_t GetFontTextureVersion() override;
/////////////////////////////////////////////////////////////////////////////////////////////////////
public:
FFont(AtomFont* atomFont, const char* fontName);
FontTexture* GetFontTexture() const { return m_fontTexture; }
const string& GetName() const { return m_name; }
FontEffect* AddEffect(const char* effectName);
FontEffect* GetDefaultEffect();
private:
virtual ~FFont();
bool InitFont();
bool InitTexture();
bool InitCache();
void Prepare(const char* str, bool updateTexture, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize);
void DrawStringUInternal(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx);
Vec2 GetTextSizeUInternal(const char* str, const bool asciiMultiLine, const TextDrawContext& ctx);
// returns true if add operation was successful, false otherwise
using AddFunction = AZStd::function<bool(const Vec3&, const Vec3&, const Vec3&, const Vec3&, const Vec2&, const Vec2&, const Vec2&, const Vec2&, uint32_t)>;
//! This function is used by both DrawStringUInternal and WriteTextQuadsToBuffers
//! To do this is takes a function pointer that implement the appropriate AddQuad behavior
int CreateQuadsForText(
float x,
float y,
float z,
const char* str,
const bool asciiMultiLine,
const TextDrawContext& ctx,
AddFunction AddQuad);
struct TextScaleInfoInternal
{
TextScaleInfoInternal(const Vec2& _scale, float _rcpCellWidth)
: scale(_scale)
, rcpCellWidth(_rcpCellWidth) { }
Vec2 scale;
float rcpCellWidth;
};
TextScaleInfoInternal CalculateScaleInternal(const TextDrawContext& ctx) const;
Vec2 GetRestoredFontSize(const TextDrawContext& ctx) const;
bool UpdateTexture();
void LoadShader(const char* shaderFilepath);
void CommitDrawGeometry();
void UpdateVertexBuffer();
void MapVertexBuffer();
void UpdateIndexBuffer();
void MapIndexBuffer();
void ScaleCoord(float& x, float& y) const;
void InitWindowContext();
void InitViewportContext();
AZ::RHI::ConstPtr<AZ::RHI::PipelineState> GetPipelineState(const AZ::RPI::Scene* scene, AZ::RHI::DrawListTag drawListTag);
void OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene) override;
private:
static constexpr uint32_t NumBuffers = 2;
static constexpr float WindowScaleWidth = 800.0f;
static constexpr float WindowScaleHeight = 600.0f;
string m_name;
string m_curPath;
FontTexture* m_fontTexture = nullptr;
size_t m_fontBufferSize = 0;
unsigned char* m_fontBuffer = nullptr;
AZStd::shared_ptr<RPI::WindowContext> m_windowContext;
AZStd::shared_ptr<AZ::RPI::ViewportContext> m_viewportContext;
AZ::Data::Instance<AZ::RPI::StreamingImage> m_fontStreamingImage;
AZ::RHI::Ptr<AZ::RHI::Image> m_fontImage;
AZ::RHI::Ptr<const AZ::RHI::ImageView> m_fontImageView;
uint32_t m_fontImageVersion = 0;
AtomFont* m_atomFont;
bool m_fontTexDirty = false;
bool m_fontInitialized = false;
FontEffects m_effects;
// Atom data
AZStd::mutex m_vertexDataMutex;
AZ::RHI::Ptr<AZ::RHI::Buffer> m_vertexBuffer[NumBuffers];
AZ::RHI::StreamBufferView m_streamBufferView[NumBuffers];
SVF_P3F_C4B_T2F* m_mappedVertexPtr = nullptr;
uint16_t m_vertexCount = 0;
AZ::RHI::Ptr<AZ::RHI::Buffer> m_indexBuffer[NumBuffers];
AZ::RHI::IndexBufferView m_indexBufferView[NumBuffers];
uint16_t* m_mappedIndexPtr = nullptr;
uint16_t m_indexCount = 0;
AZ::RHI::Ptr<AZ::RHI::BufferPool> m_inputAssemblyPool;
AZStd::mutex m_pipelineStateCacheMutex;
FontShaderData m_fontShaderData;
AZ::RHI::DrawListTag m_2DPassDrawListTag;
AZ::RPI::DynamicDrawPreRenderNotificationHandler m_preRenderNotificationHandler;
bool m_monospacedFont = false; //!< True if this font is fixed/monospaced, false otherwise (obtained from FreeType)
float m_sizeRatio = IFFontConstants::defaultSizeRatio;
SizeBehavior m_sizeBehavior = SizeBehavior::Scale; //!< Changes how glyphs rendered at different sizes are rendered.
FontHintParams m_fontHintParams; //!< How the font should be hinted when its loaded and rendered to the font texture
AZStd::vector<AZ::Data::Instance<AZ::RPI::ShaderResourceGroup>> m_processSrgs[NumBuffers]; // remember srg's for 2 frames
uint m_activeIndex = 0; // controls which vertex buffer & view, index buffer & view, and process srgs list is active
static constexpr char LogName[] = "AtomFont::FFont";
};
inline float FFont::GetSizeRatio() const
{
return m_sizeRatio;
}
inline void FontDeleter::operator () (const AZStd::intrusive_refcount<AZStd::atomic_uint, FontDeleter>* ptr) const
{
/// Recover the mutable parent object pointer from the refcount base class.
FFont* font = const_cast<FFont*>(static_cast<const FFont*>(ptr));
if (font && font->m_atomFont)
{
font->m_atomFont->UnregisterFont(font->m_name);
}
delete font;
}
}
inline void AZ::FFont::InitWindowContext()
{
if (!m_windowContext)
{
// font is created before window & viewport in the editor so need to do late init
// TODO need to deal with multiple windows, such as the editor
AZ::Render::Bootstrap::DefaultWindowBus::BroadcastResult(m_windowContext, &AZ::Render::Bootstrap::DefaultWindowInterface::GetDefaultWindowContext);
AZ_Assert(m_windowContext, "Unable to get the main window context");
}
}
inline void AZ::FFont::InitViewportContext()
{
if (!m_viewportContext)
{
// font is created before window & viewport in the editor so need to do late init
auto viewContextManager = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get();
m_viewportContext = viewContextManager->GetViewportContextByName(viewContextManager->GetDefaultViewportContextName());
AZ_Assert(m_viewportContext, "Unable to get the viewport context");
}
}
#endif
@@ -0,0 +1,49 @@
/*
* 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/base.h>
namespace AZ
{
using FONT_TEXTURE_TYPE = uint8_t;
// the number of slots in the glyph cache
// each slot ocupies ((glyph_bitmap_width * glyph_bitmap_height) + 24) bytes
#define AZ_FONT_GLYPH_CACHE_SIZE (1)
// the glyph spacing in font texels between characters in proportional font mode (more correct would be to take the value in the character)
#define AZ_FONT_GLYPH_PROP_SPACING (1)
// the size of a rendered space, this value gets multiplied by the default characted width
#define AZ_FONT_SPACE_SIZE (0.5f)
// don't draw this char (used to avoid drawing color codes)
#define AZ_FONT_NOT_DRAWABLE_CHAR (0xffff)
// smoothing methods
enum class FontSmoothMethod
{
None = 0,
Blur = 1,
SuperSample = 2,
};
// smoothing amounts
enum class FontSmoothAmount
{
None = 0,
x2 = 1,
x4 = 2,
};
};
@@ -0,0 +1,108 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Render a glyph outline into a bitmap using FreeType 2
#if !defined(USE_NULLFONT_ALWAYS)
#pragma once
#include <AtomLyIntegration/AtomFont/GlyphBitmap.h>
#include <AtomLyIntegration/AtomFont/FFont.h>
#include <ft2build.h>
#pragma push_macro("generic")
#define generic GenericFromFreeTypeLibrary
#include <freetype/freetype.h>
#undef generic
#pragma pop_macro("generic")
// Corresponds to the Unicode character set. This value covers all versions of the Unicode repertoire,
// including ASCII and Latin-1. Most fonts include a Unicode charmap, but not all of them.
#define AZ_FONT_ENCODING_UNICODE (FT_ENCODING_UNICODE)
// Corresponds to the Microsoft Symbol encoding, used to encode mathematical symbols in the 32..255 character code range.
// For more information, see `http://www.ceviz.net/symbol.htm'.
#define AZ_FONT_ENCODING_SYMBOL (FT_ENCODING_MS_SYMBOL)
// Corresponds to Microsoft's Japanese SJIS encoding.
// More info at `http://langsupport.japanreference.com/encoding.shtml'. See note on multi-byte encodings below.
#define AZ_FONT_ENCODING_SJIS (FT_ENCODING_MS_SJIS)
// Corresponds to the encoding system for Simplified Chinese, as used in China. Only found in some TrueType fonts.
#define AZ_FONT_ENCODING_GB2312 (FT_ENCODING_MS_GB2312)
// Corresponds to the encoding system for Traditional Chinese, as used in Taiwan and Hong Kong. Only found in some TrueType fonts.
#define AZ_FONT_ENCODING_BIG5 (FT_ENCODING_MS_BIG5)
// Corresponds to the Korean encoding system known as Wansung.
// This is a Microsoft encoding that is only found in some TrueType fonts.
// For more information, see `http://www.microsoft.com/typography/unicode/949.txt'.
#define AZ_FONT_ENCODING_WANSUNG (FT_ENCODING_MS_WANSUNG)
// The Korean standard character set (KS C-5601-1992), which corresponds to Windows code page 1361.
// This character set includes all possible Hangeul character combinations. Only found on some rare TrueType fonts.
#define AZ_FONT_ENCODING_JOHAB (FT_ENCODING_MS_JOHAB)
namespace AZ
{
class FontRenderer
{
public:
FontRenderer();
~FontRenderer();
int LoadFromFile(const string& fileName);
int LoadFromMemory(unsigned char* buffer, int bufferSize);
int Release();
int SetGlyphBitmapSize(int width, int height, float sizeRatio);
int GetGlyphBitmapSize(int*width, int* height);
int SetSizeRatio(float sizeRatio) { m_sizeRatio = sizeRatio; return 1; };
float GetSizeRatio() { return m_sizeRatio; };
int SetEncoding(FT_Encoding encoding);
FT_Encoding GetEncoding() { return m_encoding; };
//! Populates the given glyphBitmap's buffer from the FreeType bitmap buffer
//! \param characterCode Used as a character index to retrieve the FreeType glyph and it's associated bitmap buffer for the character
//! \param glyphBitmap The FreeType glyph buffer is essentially copied into this GlyphBitmap buffer
int GetGlyph(GlyphBitmap* glyphBitmap, int* horizontalAdvance, uint8_t* glyphWidth, uint8_t* glyphHeight, int32_t& m_characterOffsetX, int32_t& m_characterOffsetY, int iX, int iY, int characterCode, const FFont::FontHintParams& glyphFlags = FFont::FontHintParams());
int GetGlyphScaled(GlyphBitmap* glyphBitmap, int* glyphWidth, int* glyphHeight, int iX, int iY, float scaleX, float scaleY, int characterCode);
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
bool GetMonospaced() const { return FT_IS_FIXED_WIDTH(m_face) != 0; }
Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph);
float GetAscenderToHeightRatio();
private:
FT_Library m_library;
FT_Face m_face;
FT_GlyphSlot m_glyph;
float m_sizeRatio;
FT_Encoding m_encoding;
int m_glyphBitmapWidth;
int m_glyphBitmapHeight;
};
} // namespace AZ
#endif // #if !defined(USE_NULLFONT_ALWAYS)
@@ -0,0 +1,255 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/FontCommon.h>
#include <AtomLyIntegration/AtomFont/GlyphCache.h>
#include <AtomLyIntegration/AtomFont/GlyphBitmap.h>
#include <AtomLyIntegration/AtomFont/AtomFont.h>
#include <AtomLyIntegration/AtomFont/FFont.h>
namespace AZ
{
//! Stores glyph meta-data read from the font (FreeType).
//!
//! \sa CacheSlot
struct TextureSlot
{
AtomFont::GlyphSize m_glyphSize = AtomFont::defaultGlyphSize; //!< Size of the rendered glyph stored in the font texture
uint16_t m_slotUsage; //!< For LRU strategy, 0xffff is never released
uint32_t m_currentCharacter; //!< ~0 if not used for characters
int32_t m_textureSlot;
int32_t m_horizontalAdvance; //!< Advance width. See FT_Glyph_Metrics::horiAdvance.
float m_texCoords[2]; //!< Character position in the texture (not yet half texel corrected)
uint8_t m_characterWidth; //!< Glyph width (in pixel)
uint8_t m_characterHeight; //!< Glyph height (in pixel)
int32_t m_characterOffsetX; //!< Glyph's left-side bearing (in pixels). See FT_GlyphSlotRec::bitmap_left.
int32_t m_characterOffsetY; //!< Glyph's top bearing (in pixels). See FT_GlyphSlotRec::bitmap_top.
void Reset()
{
m_slotUsage = 0;
m_currentCharacter = ~0;
m_horizontalAdvance = 0;
m_characterWidth = 0;
m_characterHeight = 0;
m_characterOffsetX = 0;
m_characterOffsetY = 0;
}
void SetNotReusable()
{
m_slotUsage = 0xffff;
}
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
};
//! Stores the glyphs of a font within a single cpu texture.
//!
//! The texture resolution is configurable, as is the number of slots within
//! the texture.
//!
//! A texture slot contains a single glyph within the font and are uniform
//! size throughout the font texture (each slot occupies the same size
//! regardless of the size of a glyph being stored, so a '.' occupies the
//! same amount of space as a 'W', for example).
//!
//! Font glyph buffrs are read from FreeType and copied into the texture.
//!
//! \sa TextureSlot, FontRenderer
class FontTexture
{
public:
FontTexture();
~FontTexture();
int CreateFromFile(const string& fileName, int width, int height, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, int widthCharCount = 16, int heightCharCount = 16);
//! Default texture slot width/height is 16x8 slots, allowing for 128 glyphs to be stored in the font texture. This was
//! previously 16x16, allowing 256 glyphs to be stored. For reference, there are 95 printable ASCII characters, so by
//! reducing the number of slots, the height of the font texture can be halved (for some nice memory savings). We may
//! want to make this configurable in the font XML (especially for languages with a large number of printable chars).
int CreateFromMemory(unsigned char* fileData, int dataSize, int width, int height, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, int widthCharCount, int heightCharCount, float sizeRatio);
int Create(int width, int height, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, int widthCharCount = 16, int heightCharCount = 16, float sizeRatio = IFFontConstants::defaultSizeRatio);
int Release();
int SetEncoding(FT_Encoding encoding) { return m_glyphCache.SetEncoding(encoding); }
FT_Encoding GetEncoding() { return m_glyphCache.GetEncoding(); }
int GetCellWidth() { return m_cellWidth; }
int GetCellHeight() { return m_cellHeight; }
int GetWidth() { return m_width; }
int GetHeight() { return m_height; }
int GetWidthCellCount() { return m_widthCellCount; }
int GetHeightCellCount() { return m_heightCellCount; }
float GetTextureCellWidth() { return m_textureCellWidth; }
float GetTextureCellHeight() { return m_textureCellHeight; }
FONT_TEXTURE_TYPE* GetBuffer() { return m_buffer; }
uint32_t GetSlotChar(int slotIndex) const;
TextureSlot* GetCharSlot(uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize);
TextureSlot* GetGradientSlot();
TextureSlot* GetLRUSlot();
TextureSlot* GetMRUSlot();
//! Returns 1 if texture updated, returns 2 if texture not updated, returns 0 on error
//! \param string A string of glyphs (UTF8) to added to the font texture (if they don't already exist in the font texture)
//! \param updated is the number of slots updated
//! \param sizeRatio A sizing scale that gets applied to all glyphs sizes before they are stored in the font texture.
//! \param glyphSize The resolution to render the glyphs in string at.
//! \param glyphFlags Controls hinting behavior for glyphs rendered to the font texture.
int PreCacheString(const char* string, int* updated = 0, float sizeRatio = IFFontConstants::defaultSizeRatio, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize, const FFont::FontHintParams& glyphFlags = FFont::FontHintParams());
// Arguments:
// slot - function does nothing if this pointer is 0
void GetTextureCoord(TextureSlot * slot, float texCoords[4], int& characterSizeX, int& characterSizeY, int& m_characterOffsetX, int& m_characterOffsetY, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize) const;
int GetCharacterWidth(uint32_t character) const;
//! Gets the horizontal advance for the given glyph/char.
//! \param character The glyph (UTF32) to get the horizontal advance for.
//! \param glyphSize The rendered size of the glyph to get the advance for (the same glyph could be stored in the font texture at multiple sizes).
int GetHorizontalAdvance(uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize) const;
// int GetCharHeightByChar(wchar_t character);
// useful for special feature rendering interleaved with fonts (e.g. box behind the text)
void CreateGradientSlot();
int WriteToFile(const string& fileName);
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
bool GetMonospaced() const { return m_glyphCache.GetMonospaced(); }
Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph);
float GetAscenderToHeightRatio();
//! Clamps the given glyph size to the given max cell width and height dimensions.
static AtomFont::GlyphSize ClampGlyphSize(const AtomFont::GlyphSize& glyphSize, int cellWidth, int cellHeight);
private: // ---------------------------------------------------------------
using TextureSlotList = std::vector<TextureSlot*>;
using TextureSlotListItor = std::vector<TextureSlot*>::iterator;
using GlyphSizeType = AtomFont::GlyphSize;
//! Pair for mapping a height and width size to a UTF32 character/glyph
using TextureSlotKey = AZStd::pair<GlyphSizeType, uint32_t>;
//! Hasher for texture slot table keys (glyphsize-char code pair)
//!
//! Instead of creating our own custom hash, the types are broken down to their
//! native types (ints) and passed to existing hashes that handle those types.
struct HashTextureSlotTableKey
{
using ArgumentType = TextureSlotKey;
using ResultType = AZStd::size_t;
using Int32Pair = AZStd::pair<int32_t, int32_t>;
using Int32PairU32Pair = AZStd::pair<Int32Pair, uint32_t>;
ResultType operator()(const ArgumentType& value) const
{
// Utiliize existing hash function for pairs of ints
AZStd::hash<Int32PairU32Pair> pairHash;
return pairHash(Int32PairU32Pair(Int32Pair(value.first.x, value.first.y), value.second));
}
};
//! Maps size-specifc UTF32 glyphs to their corresponding texture slots
using TextureSlotTableEntry = AZStd::pair<TextureSlotKey, TextureSlot*>;
using TextureSlotTable = AZStd::unordered_map<TextureSlotKey, TextureSlot*, HashTextureSlotTableKey>;
using TextureSlotTableItor = TextureSlotTable::iterator;
using TextureSlotTableItorConst = TextureSlotTable::const_iterator;
// --------------------------------
int CreateSlotList(int listSize);
int ReleaseSlotList();
//! Updates the given font texture slot with the given glyph (UTF8) with the given parameters. If the glyph doesn't
//! exist in the font texture at the given size, then the glyph will be rendered to the font texture with the given
//! parameters.
//! \param slotIndex Index of the texture slot to update within the slot list.
//! \param slotUsage Used for LRU strategy to determine how many times a glyph is referenced for retention within the font texture (before eviction).
//! \param character UTF32 glyph to store within the slot.
//! \param sizeRatio A sizing scale that should be applied to the glyph before being stored within the font texture.
//! \param glyphSize The size of the glyph to be rendered at within the font texture.
//! \param glyphFlags Specifies hinting behavior that should be applied to the glyph when rendered to the font texture.
int UpdateSlot(int slotIndex, uint16_t slotUsage, uint32_t character, float sizeRatio, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize, const FFont::FontHintParams& glyphFlags = FFont::FontHintParams());
TextureSlotKey GetTextureSlotKey(uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize) const;
//! Calculates scaling info that should be applied when the rendered glyph size doesn't match the maximum glyph slot resolution.
//!
//! Glyphs can be re-rendered to glyph slots at smaller resolutions for pixel-perfect resolution (rather than applying a scale
//! to glyphs rendered at larger sizes). These scaling values allow clients of the font texture to use the glyphs without regard
//! to whether the glyphs have been re-rendered or not.
float GetRequestSizeWidthScale(const AtomFont::GlyphSize& glyphSize) const
{
const int cellWidth = m_cellWidth == 0 ? 1 : m_cellWidth;
const float invCellWidth = 1.0f / cellWidth;
return glyphSize.x > 0 ? glyphSize.x * invCellWidth : 1.0f;
}
//! Calculates scaling info that should be applied when the rendered glyph size doesn't match the maximum glyph slot resolution.
//!
//! Glyphs can be re-rendered to glyph slots at smaller resolutions for pixel-perfect resolution (rather than applying a scale
//! to glyphs rendered at larger sizes). These scaling values allow clients of the font texture to use the glyphs without regard
//! to whether the glyphs have been re-rendered or not.
float GetRequestSizeHeightScale(const AtomFont::GlyphSize& glyphSize) const
{
const int cellHeight = m_cellHeight == 0 ? 1 : m_cellHeight;
const float invCellHeight = 1.0f / cellHeight;
return glyphSize.y > 0 ? glyphSize.y * invCellHeight : 1.0f;
}
// --------------------------------
int m_width; // whole texture cache width
int m_height; // whole texture cache height
float m_invWidth;
float m_invHeight;
int m_cellWidth;
int m_cellHeight;
float m_textureCellWidth;
float m_textureCellHeight;
int m_widthCellCount;
int m_heightCellCount;
int m_textureSlotCount;
FontSmoothMethod m_smoothMethod;
FontSmoothAmount m_smoothAmount;
GlyphCache m_glyphCache;
TextureSlotList m_slotList;
TextureSlotTable m_slotIndexMap;
FONT_TEXTURE_TYPE* m_buffer; // [y*width * x] x=0..width-1, y=0..height-1
uint16_t m_slotUsage;
};
}
#endif // #if !defined(USE_NULLFONT_ALWAYS)
@@ -0,0 +1,53 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Purpose : Hold a glyph bitmap and blit it to the main texture
#pragma once
#include <AzCore/std/smart_ptr/unique_ptr.h>
#include <AtomLyIntegration/AtomFont/FontCommon.h>
namespace AZ
{
class GlyphBitmap
{
public:
GlyphBitmap();
~GlyphBitmap();
int Create(int width, int height);
int Release();
unsigned char* GetBuffer() { return m_buffer.get(); };
int Blur(AZ::FontSmoothAmount smoothAmount);
int Clear();
int BlitTo8(unsigned char* buffer, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth);
int BlitScaledTo8(unsigned char* buffer, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, int destBufferWidth);
int GetWidth() { return m_width; }
int GetHeight() { return m_height; }
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
private:
AZStd::unique_ptr<uint8_t[]> m_buffer;
int m_width;
int m_height;
};
}
@@ -0,0 +1,179 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Purpose:
// - Manage and cache glyphs, retrieving them from the renderer as needed
#pragma once
#if !defined(USE_NULLFONT_ALWAYS)
#include <vector>
#include <AtomLyIntegration/AtomFont/GlyphBitmap.h>
#include <AtomLyIntegration/AtomFont/FontRenderer.h>
#include <AtomLyIntegration/AtomFont/AtomFont.h>
#include <StlUtils.h>
#include <AtomLyIntegration/AtomFont/FFont.h>
namespace AZ
{
//! Glyph cache slots store the bitmap buffer and glyph metadata from FreeType.
//!
//! This bitmap buffer is eventually copied to a FontTexture texture buffer.
//! A glyph cache slot bitmap buffer only holds a single glyph, whereas the
//! FontTexture stores multiple glyphs in a grid (row/col) format.
struct CacheSlot
{
AtomFont::GlyphSize m_glyphSize = AtomFont::defaultGlyphSize; //!< The render resolution of the glyph in the glyph bitmap
unsigned int m_usage;
int m_slotIndex;
int m_horizontalAdvance; //!< Advance width. See FT_Glyph_Metrics::horiAdvance.
uint32_t m_currentCharacter;
uint8_t m_characterWidth; //!< Glyph width (in pixel)
uint8_t m_characterHeight; //!< Glyph height (in pixel)
int32_t m_characterOffsetX; //!< Glyph's left-side bearing (in pixels). See FT_GlyphSlotRec::bitmap_left.
int32_t m_characterOffsetY; //!< Glyph's top bearing (in pixels). See FT_GlyphSlotRec::bitmap_top.
GlyphBitmap m_glyphBitmap; //!< Contains a buffer storing a copy of the glyph from FreeType
void Reset()
{
m_usage = 0;
m_currentCharacter = ~0;
m_characterWidth = 0;
m_characterHeight = 0;
m_characterOffsetX = 0;
m_characterOffsetY = 0;
m_glyphBitmap.Clear();
}
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
};
//! The glyph cache maps UTF32 codepoints to their corresponding FreeType data.
//!
//! This cache is used to associate font glyph info (read from FreeType) with
//! UTF32 codepoints. Ultimately the glyph info will be read into a font texture
//! (FontTexture) to avoid future FreeType lookups.
//!
//! If a FontTexture is missing a glyph that is currently stored in the glyph
//! cache, the cached data can be returned instead of having to be rendered from
//! FreeType again.
//!
//! \sa FontTexture
class GlyphCache
{
public:
GlyphCache();
~GlyphCache();
int Create(int iCacheSize, int glyphBitmapWidth, int glyphBitmapHeight, FontSmoothMethod smoothMethod, FontSmoothAmount smoothAmount, float sizeRatio);
int Release();
int LoadFontFromFile(const string& fileName);
int LoadFontFromMemory(unsigned char* fileBuffer, int dataSize);
int ReleaseFont();
int SetEncoding(FT_Encoding encoding) { return m_fontRenderer.SetEncoding(encoding); };
FT_Encoding GetEncoding() { return m_fontRenderer.GetEncoding(); };
int GetGlyphBitmapSize(int* width, int* height);
void SetGlyphBitmapSize(int width, int height, float sizeRatio);
int PreCacheGlyph(uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize, const FFont::FontHintParams& glyphFlags = FFont::FontHintParams());
int UnCacheGlyph(uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize);
int GlyphCached(uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize);
CacheSlot* GetLRUSlot();
CacheSlot* GetMRUSlot();
//! Obtains glyph information for the given UTF32 codepoint.
//! This information is obtained from a CacheSlot that corresponds to
//! the given codepoint. If the codepoint doesn't exist within the cache
//! table (m_cacheTable), then the information is obtain from FreeType
//! directly via FontRenderer.
//!
//! Ultimately the glyph bitmap is copied into a font texture
//! (FontTexture). Once the glyph is copied into the font texture then
//! the font texture is referenced directly rather than relying on the
//! glyph cache or FreeType.
//!
//! \sa FontRenderer::GetGlyph, FontTexture::UpdateSlot
int GetGlyph(GlyphBitmap** glyph, int* horizontalAdvance, int* width, int* height, int32_t& m_characterOffsetX, int32_t& m_characterOffsetY, uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize, const FFont::FontHintParams& glyphFlags = FFont::FontHintParams());
void GetMemoryUsage([[maybe_unused]] ICrySizer* sizer) const {}
bool GetMonospaced() const { return m_fontRenderer.GetMonospaced(); }
Vec2 GetKerning(uint32_t leftGlyph, uint32_t rightGlyph);
float GetAscenderToHeightRatio();
private:
//! Height and width pair for glyph size mapping
using CacheTableGlyphSizeType = AtomFont::GlyphSize;
//! Pair for mapping a height and width size to a UTF32 character/glyph
using CacheTableKey = AZStd::pair<CacheTableGlyphSizeType, uint32_t>;
//! Hasher for glyph cache table keys (glyphsize-char code pair)
//!
//! Instead of creating our own custom hash, the types are broken down to their
//! native types (ints) and passed to existing hashes that handle those types.
struct HashGlyphCacheTableKey
{
using ArgumentType = CacheTableKey;
using ResultType = AZStd::size_t;
using Int32Pair = AZStd::pair<int32_t, int32_t>;
using Int32PairU32Pair = AZStd::pair<Int32Pair, uint32_t>;
ResultType operator()(const ArgumentType& value) const
{
AZStd::hash<Int32PairU32Pair> pairHash;
return pairHash(Int32PairU32Pair(Int32Pair(value.first.x, value.first.y), value.second));
}
};
//! Maps size-specifc UTF32 glyphs to their corresponding cache slots
using CacheTable = AZStd::unordered_map<CacheTableKey, CacheSlot*, HashGlyphCacheTableKey>;
using CacheSlotList = std::vector<CacheSlot*>;
using CacheSlotListItor = std::vector<CacheSlot*>::iterator;
//! Returns a key for the cache table where the given char is mapped at the given size.
CacheTableKey GetCacheSlotKey(uint32_t character, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize) const;
int CreateSlotList(int listSize);
int ReleaseSlotList();
CacheSlotList m_slotList;
CacheTable m_cacheTable;
int m_glyphBitmapWidth;
int m_glyphBitmapHeight;
FontSmoothMethod m_smoothMethod;
FontSmoothAmount m_smoothAmount;
GlyphBitmap* m_scaleBitmap;
FontRenderer m_fontRenderer;
unsigned int m_usage;
};
}
#endif // #if !defined(USE_NULLFONT_ALWAYS)
@@ -0,0 +1,25 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#define VS_VERSION_INFO 1
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
@@ -0,0 +1,15 @@
#
# 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.
#
set(FILES
../Common/FFontXML_Common.cpp
../Common/FontTexture_Common.cpp
)
@@ -0,0 +1,20 @@
/*
* 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 <FFontXML_Internal.h>
namespace AtomFontInternal
{
void XmlFontShader::FoundElementImpl()
{
}
}
@@ -0,0 +1,24 @@
/*
* 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 <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/FontTexture.h>
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::WriteToFile([[maybe_unused]] const string& fileName)
{
return 1;
}
#endif
@@ -0,0 +1,15 @@
#
# 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.
#
set(FILES
../Common/FFontXML_Common.cpp
../Common/FontTexture_Common.cpp
)
@@ -0,0 +1,15 @@
#
# 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.
#
set(FILES
../Common/FFontXML_Common.cpp
../Common/FontTexture_Common.cpp
)
@@ -0,0 +1,33 @@
/*
* 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 <FFontXML_Internal.h>
#include <shlobj_core.h>
namespace AtomFontInternal
{
void XmlFontShader::FoundElementImpl()
{
TCHAR sysFontPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(0, CSIDL_FONTS, 0, SHGFP_TYPE_DEFAULT, sysFontPath)))
{
const char* fontPath = m_strFontPath.c_str();
const char* fontName = CryStringUtils::FindFileNameInPath(fontPath);
string newFontPath(sysFontPath);
newFontPath += "/";
newFontPath += fontName;
m_font->Load(newFontPath, m_FontTexSize.x, m_FontTexSize.y, m_slotSizes.x, m_slotSizes.y, CreateTTFFontFlag(m_FontSmoothMethod, m_FontSmoothAmount), m_SizeRatio);
}
}
}
@@ -0,0 +1,67 @@
/*
* 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 <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/FontTexture.h>
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::WriteToFile(const string& fileName)
{
AZ::IO::FileIOStream outputFile(fileName.c_str(), AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeBinary);
if (!outputFile.IsOpen())
{
return 0;
}
BITMAPFILEHEADER pHeader;
BITMAPINFOHEADER pInfoHeader;
memset(&pHeader, 0, sizeof(BITMAPFILEHEADER));
memset(&pInfoHeader, 0, sizeof(BITMAPINFOHEADER));
pHeader.bfType = 0x4D42;
pHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + m_width * m_height * 3;
pHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
pInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
pInfoHeader.biWidth = m_width;
pInfoHeader.biHeight = m_height;
pInfoHeader.biPlanes = 1;
pInfoHeader.biBitCount = 24;
pInfoHeader.biCompression = 0;
pInfoHeader.biSizeImage = m_width * m_height * 3;
outputFile.Write(sizeof(BITMAPFILEHEADER), &pHeader);
outputFile.Write(sizeof(BITMAPINFOHEADER), &pInfoHeader);
unsigned char cRGB[3];
for (int i = m_height - 1; i >= 0; i--)
{
for (int j = 0; j < m_width; j++)
{
cRGB[0] = m_buffer[(i * m_width) + j];
cRGB[1] = *cRGB;
cRGB[2] = *cRGB;
outputFile.Write(3, cRGB);
}
}
return 1;
}
#endif
@@ -0,0 +1,15 @@
#
# 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.
#
set(FILES
FFontXML_Windows.cpp
FontTexture_Windows.cpp
)
@@ -0,0 +1,15 @@
#
# 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.
#
set(FILES
../Common/FFontXML_Common.cpp
../Common/FontTexture_Common.cpp
)
@@ -0,0 +1,827 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : AtomFont class.
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/AtomFont.h>
#include <AtomLyIntegration/AtomFont/FFont.h>
#include <AtomLyIntegration/AtomFont/FontTexture.h>
#include <AtomLyIntegration/AtomFont/FontRenderer.h>
#include <CryCommon/CryPath.h>
#include <CryCommon/ILocalizationManager.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/string/string_view.h>
#include <AzFramework/Archive/IArchive.h>
// Static member definitions
const AZ::AtomFont::GlyphSize AZ::AtomFont::defaultGlyphSize = AZ::AtomFont::GlyphSize(ICryFont::defaultGlyphSizeX, ICryFont::defaultGlyphSizeY);
#if !defined(_RELEASE)
static void DumfontTexture(IConsoleCmdArgs* cmdArgs)
{
if (cmdArgs->GetArgCount() != 2)
{
return;
}
const char* fontName = cmdArgs->GetArg(1);
if (fontName && *fontName && *fontName != '0')
{
string fontFilePath("@devroot@/");
fontFilePath += fontName;
fontFilePath += ".bmp";
AZ::FFont* font = (AZ::FFont*) gEnv->pCryFont->GetFont(fontName);
if (font)
{
font->GetFontTexture()->WriteToFile(fontFilePath.c_str());
gEnv->pLog->LogWithType(IMiniLog::eInputResponse, "Dumped \"%s\" texture to \"%s\"!", fontName, fontFilePath.c_str());
}
}
}
static void DumfontNames([[maybe_unused]] IConsoleCmdArgs* cmdArgs)
{
string names = gEnv->pCryFont->GetLoadedFontNames();
gEnv->pLog->LogWithType(IMiniLog::eInputResponse, "Currently loaded fonts: %s", names.c_str());
}
static void ReloadFonts([[maybe_unused]] IConsoleCmdArgs* cmdArgs)
{
gEnv->pCryFont->ReloadAllFonts();
}
#endif
namespace
{
//! Stores paths to styled font assets for a given set of languages
//! This struct stores the XML data contained within the <font> tag of
//! an enclosing <fontfamily> definition:
//!
//! <fontfamily name="FontFamilyName">
//! <font lang="Language1, Language2">
//! <file path="regular.font" />
//! <file path="bold.font" tags="b" />
//! <file path="italic.font" tags="i" />
//! <file path="bolditalic.font" tags="b,i" />
//! </font>
//! </fontfamily>
struct FontTagXml
{
//! \return True if all font asset paths are non-empty, false otherwise
bool IsValid() const
{
// Note that "lang" can be empty
return !m_fontFilename.empty()
&& !m_boldFontFilename.empty()
&& !m_italicFontFilename.empty()
&& !m_boldItalicFontFilename.empty();
}
string m_lang; //!< Stores a comma-separated list of languages this collection of fonts applies to.
//!< If this is an empty string, it implies that these set of fonts will be applied
//!< by default (when a language is being used but no fonts in the font family are
//!< mapped to that language).
string m_fontFilename; //!< Font used when no styling is applied.
string m_boldFontFilename; //!< Bold-styled font
string m_italicFontFilename; //!< Italic-styled font
string m_boldItalicFontFilename; //!< Bold-italic-styled font
};
//! Stores parsed font family XML data.
//! This struct contains the name of the font family and a list of font
//! file XML data for all the language-specific mappings of this
//! font family.
//!
//! Example XML:
//!
//! <fontfamily name="FontFamilyName">
//! <font>
//! <file path="regular.font" />
//! <file path="bold.font" tags="b" />
//! <file path="italic.font" tags="i" />
//! <file path="bolditalic.font" tags="b,i" />
//! </font>
//! <font lang="korean">
//! <file path="../korean/korean-regular.font" />
//! <file path="../korean/korean-italic.font" tags="b" />
//! <file path="../korean/korean-bold.font" tags="i" />
//! <file path="../korean/korean-bolditalic.font" tags="b,i" />
//! </font>
//! <font lang="chinesesimplified">
//! <file path="../chinesesimplified/chinesesimplified-regular.font" />
//! <file path="../chinesesimplified/chinesesimplified-bold.font" tags="b" />
//! <file path="../chinesesimplified/chinesesimplified-italic.font" tags="i" />
//! <file path="../chinesesimplified/chinesesimplified-bolditalic.font" tags="b,i" />
//! </font>
//! </fontfamily>
struct FontFamilyTagXml
{
//! Returns true if all font file fields were parsed, false otherwise.
bool IsValid() const
{
for (const FontTagXml& fontTagXml : m_fontTagsXml)
{
if (!fontTagXml.IsValid())
{
return false;
}
}
// Every font family must have a name
return !m_fontFamilyName.empty();
}
string m_fontFamilyName; //!< Value of the "name" font-family tag attribute
AZStd::list<FontTagXml> m_fontTagsXml; //!< List of child <font> tag data.
};
//! Returns true if the XML tree was traversed successfully, false otherwise.
//!
//! Note that, if this function returns true, it simply means that there were
//! no unexpected structure issues with the given XML tree, it doesn't
//! necessarily mean that all the required fields were parsed.
bool ParseFontFamilyXml(const XmlNodeRef& node, FontFamilyTagXml& xmlData)
{
if (!node)
{
return false;
}
// <fontfamily>
if (AZStd::string(node->getTag()) == "fontfamily")
{
const int numAttributes = node->getNumAttributes();
if (numAttributes <= 0)
{
// Expecting at least one attribute
return false;
}
string name;
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
{
const char* key = "";
const char* value = "";
if (node->getAttributeByIndex(i, &key, &value))
{
if (string(key) == "name")
{
name = value;
}
else
{
// Unexpected font tag attribute
return false;
}
}
}
name.Trim();
if (!name.empty())
{
xmlData.m_fontFamilyName = name;
}
else
{
// Font family must have a name
return false;
}
}
// <font>
if (AZStd::string(node->getTag()) == "font")
{
xmlData.m_fontTagsXml.push_back(FontTagXml());
string lang;
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
{
const char* key = "";
const char* value = "";
if (node->getAttributeByIndex(i, &key, &value))
{
if (string(key) == "lang")
{
lang = value;
}
else
{
// Unexpected font tag attribute
return false;
}
}
}
lang.Trim();
if (!lang.empty())
{
xmlData.m_fontTagsXml.back().m_lang = lang;
}
}
// <file>
else if (AZStd::string(node->getTag()) == "file")
{
const int numAttributes = node->getNumAttributes();
if (numAttributes <= 0)
{
// Expecting at least one attribute
return false;
}
string path;
string tags;
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
{
const char* key = "";
const char* value = "";
if (node->getAttributeByIndex(i, &key, &value))
{
if (string(key) == "path")
{
path = value;
}
else if (string(key) == "tags")
{
tags = value;
}
else
{
// Unexpected font tag attribute
return false;
}
}
}
tags.Trim();
if (tags.empty())
{
xmlData.m_fontTagsXml.back().m_fontFilename = path;
}
else if (tags == "b")
{
xmlData.m_fontTagsXml.back().m_boldFontFilename = path;
}
else if (tags == "i")
{
xmlData.m_fontTagsXml.back().m_italicFontFilename = path;
}
else
{
// We'll just assume any other tag indicates bold italic
xmlData.m_fontTagsXml.back().m_boldItalicFontFilename = path;
}
}
for (int i = 0, count = node->getChildCount(); i < count; ++i)
{
XmlNodeRef child = node->getChild(i);
if (!ParseFontFamilyXml(child, xmlData))
{
return false;
}
}
return true;
}
//! Only attempt XML file load if file exists.
//! There are use-cases where the XML path is not fully known (such as
//! when referencing font family names from font family XML files), and
//! attempting to load the XML files directly via ISystem() methods can
//! produce a lot of warning noise.
XmlNodeRef SafeLoadXmlFromFile(const string& xmlPath)
{
if (gEnv->pCryPak->IsFileExist(xmlPath.c_str()))
{
return GetISystem()->LoadXmlFromFile(xmlPath.c_str());
}
return XmlNodeRef();
}
}
AZ::AtomFont::AtomFont(ISystem* system)
: m_system(system)
, m_fonts()
{
assert(m_system);
CryLogAlways("Using FreeType %d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
// Persist fonts for application lifetime to prevent unnecessary work
REGISTER_CVAR(r_persistFontFamilies, r_persistFontFamilies, VF_NULL, "Persist loaded font families for lifetime of application.");
#if !defined(_RELEASE)
REGISTER_COMMAND("r_DumfontTexture", DumfontTexture, 0,
"Dumps the specified font's texture to a bitmap file\n"
"Use r_DumfontTexture to get the loaded font names\n"
"Usage: r_DumfontTexture <fontname>");
REGISTER_COMMAND("r_DumfontNames", DumfontNames, 0,
"Logs a list of fonts currently loaded");
REGISTER_COMMAND("r_ReloadFonts", ReloadFonts, VF_NULL,
"Reload all fonts");
#endif
}
AZ::AtomFont::~AtomFont()
{
// Persist fonts for application lifetime to prevent unnecessary work
m_persistedFontFamilies.clear();
for (FontMapItor it = m_fonts.begin(), itEnd = m_fonts.end(); it != itEnd; )
{
FFont* font = it->second;
++it; // iterate as Release() below will remove font from the map
SAFE_RELEASE(font);
}
}
void AZ::AtomFont::Release()
{
delete this;
}
IFFont* AZ::AtomFont::NewFont(const char* fontName)
{
string name = fontName;
name.MakeLower();
FontMapItor it = m_fonts.find(CONST_TEMP_STRING(name.c_str()));
if (it != m_fonts.end())
{
return it->second;
}
FFont* font = new FFont(this, name.c_str());
m_fonts.insert(FontMapItor::value_type(name, font));
return font;
}
IFFont* AZ::AtomFont::GetFont(const char* fontName) const
{
FontMapConstItor it = m_fonts.find(CONST_TEMP_STRING(string(fontName).MakeLower()));
return it != m_fonts.end() ? it->second : 0;
}
FontFamilyPtr AZ::AtomFont::LoadFontFamily(const char* fontFamilyName)
{
FontFamilyPtr fontFamily(nullptr);
string fontFamilyPath;
string fontFamilyFullPath;
XmlNodeRef root = LoadFontFamilyXml(fontFamilyName, fontFamilyPath, fontFamilyFullPath);
if (root)
{
FontFamilyTagXml xmlData;
const bool parseSuccess = ParseFontFamilyXml(root, xmlData);
if (parseSuccess && xmlData.IsValid())
{
const char* currentLanguage = gEnv->pSystem->GetLocalizationManager()->GetLanguage();
FontTagXml* defaultFont = nullptr;
FontTagXml* langSpecificFont = nullptr;
// Note that we don't break out of this for-loop early because we
// want to find both the default font family and the
// language-specific font family. We prefer the lang-specific
// family but will fall back on the default if it doesn't exist.
for (FontTagXml& fontTagXml : xmlData.m_fontTagsXml)
{
if (fontTagXml.m_lang.empty())
{
defaultFont = &fontTagXml;
}
else
{
int searchPos = 0;
string langToken;
// "lang" font-tag attribute could be comma-separated
while (!(langToken = fontTagXml.m_lang.Tokenize(",", searchPos)).empty())
{
if (langToken.Trim() == currentLanguage)
{
langSpecificFont = &fontTagXml;
break;
}
}
}
}
if (langSpecificFont || defaultFont)
{
// Prefer lang-specific font-family over default, if it exists
FontTagXml* fontTagXml = langSpecificFont ? langSpecificFont : defaultFont;
// Pre-pend font family's path to make font family XML paths
// relative to font family file
fontTagXml->m_fontFilename = fontFamilyPath + fontTagXml->m_fontFilename;
fontTagXml->m_boldFontFilename = fontFamilyPath + fontTagXml->m_boldFontFilename;
fontTagXml->m_italicFontFilename = fontFamilyPath + fontTagXml->m_italicFontFilename;
fontTagXml->m_boldItalicFontFilename = fontFamilyPath + fontTagXml->m_boldItalicFontFilename;
IFFont* normal = LoadFont(fontTagXml->m_fontFilename.c_str());
IFFont* bold = LoadFont(fontTagXml->m_boldFontFilename.c_str());
IFFont* italic = LoadFont(fontTagXml->m_italicFontFilename.c_str());
IFFont* boldItalic = LoadFont(fontTagXml->m_boldItalicFontFilename.c_str());
// Only continue if all fonts were created successfully
if (normal && bold && italic && boldItalic)
{
fontFamily.reset(new FontFamily(),
[this](FontFamily* fontFamily)
{
ReleaseFontFamily(fontFamily);
});
// Map the font family name both by path and by name defined
// within the Font Family XML itself. This allows font
// families to also be referenced simply by name.
if (!AddFontFamilyToMaps(fontFamilyFullPath, xmlData.m_fontFamilyName, fontFamily))
{
SAFE_RELEASE(normal);
SAFE_RELEASE(bold);
SAFE_RELEASE(italic);
SAFE_RELEASE(boldItalic);
return nullptr;
}
fontFamily->familyName = xmlData.m_fontFamilyName;
fontFamily->normal = normal;
fontFamily->bold = bold;
fontFamily->italic = italic;
fontFamily->boldItalic = boldItalic;
}
else
{
SAFE_RELEASE(normal);
SAFE_RELEASE(bold);
SAFE_RELEASE(italic);
SAFE_RELEASE(boldItalic);
}
}
}
}
if (!fontFamily)
{
// Unable to load font family XML, so load font normally and associate
// it with a font family
IFFont* font = LoadFont(fontFamilyName);
if (font)
{
// Create a font family from a single font by assigning all the
// font family stylings to the same font
fontFamily.reset(new FontFamily(),
[this](FontFamily* fontFamily)
{
ReleaseFontFamily(fontFamily);
});
// Use filepath as familyName so font loading/unloading doesn't break with duplicate file names
fontFamily->familyName = fontFamilyName;
if (!AddFontFamilyToMaps(fontFamilyName, fontFamily->familyName, fontFamily))
{
SAFE_RELEASE(font);
return nullptr;
}
// Assign all stylings to the same font
fontFamily->normal = font;
fontFamily->bold = font;
fontFamily->italic = font;
fontFamily->boldItalic = font;
// The other three stylings need to have their ref count
// incremented (even though in this particular case its all the
// same font) because when ReleaseFontFamily executes all fonts
// in the family will be (corresondingly) Release'd.
fontFamily->bold->AddRef();
fontFamily->italic->AddRef();
fontFamily->boldItalic->AddRef();
}
}
// Persist fonts for application lifetime to prevent unnecessary work
if (r_persistFontFamilies > 0)
{
m_persistedFontFamilies.emplace_back(FontFamilyPtr(fontFamily));
}
return fontFamily;
}
FontFamilyPtr AZ::AtomFont::GetFontFamily(const char* fontFamilyName)
{
FontFamilyPtr fontFamily = nullptr;
// The given string could either be: a font family name (defined in font
// family XML), a file path (for regular fonts mapped as font families),
// or just the filename of a font itself. Fonts are mapped by font family
// name or by filepath, so attempt lookup using the map first since it's
// the fastest.
string loweredName = string(fontFamilyName).Trim().MakeLower();
auto it = m_fontFamilies.find(PathUtil::MakeGamePath(loweredName).c_str());
if (it != m_fontFamilies.end())
{
fontFamily = FontFamilyPtr(it->second);
}
else
{
// Iterate through all fonts, returning the first match where simply
// the filename of a font could be a match. This case will likely be
// hit when text markup references a font that doesn't belong to a
// font family.
for (const auto& fontFamilyIter : m_fontFamilies)
{
const AZStd::string& mappedFontFamilyName = fontFamilyIter.first;
string mappedFilenameNoExtension = PathUtil::GetFileName(mappedFontFamilyName.c_str());
string searchStringFilenameNoExtension = PathUtil::GetFileName(loweredName);
if (mappedFilenameNoExtension == searchStringFilenameNoExtension)
{
fontFamily = FontFamilyPtr(fontFamilyIter.second);
break;
}
}
}
return fontFamily;
}
void AZ::AtomFont::AddCharsToFontTextures(FontFamilyPtr fontFamily, const char* chars, int glyphSizeX, int glyphSizeY)
{
fontFamily->normal->AddCharsToFontTexture(chars, glyphSizeX, glyphSizeY);
fontFamily->bold->AddCharsToFontTexture(chars, glyphSizeX, glyphSizeY);
fontFamily->italic->AddCharsToFontTexture(chars, glyphSizeX, glyphSizeY);
fontFamily->boldItalic->AddCharsToFontTexture(chars, glyphSizeX, glyphSizeY);
}
string AZ::AtomFont::GetLoadedFontNames() const
{
string ret;
for (FontMapConstItor it = m_fonts.begin(), itEnd = m_fonts.end(); it != itEnd; ++it)
{
FFont* font = it->second;
if (font)
{
if (!ret.empty())
{
ret += ",";
}
ret += font->GetName();
}
}
return ret;
}
void AZ::AtomFont::OnLanguageChanged()
{
ReloadAllFonts();
EBUS_EVENT(LanguageChangeNotificationBus, LanguageChanged);
}
void AZ::AtomFont::ReloadAllFonts()
{
// Persist fonts for application lifetime to prevent unnecessary work
m_persistedFontFamilies.clear();
AZStd::list<AZStd::string> fontFamilyFilenames;
AZStd::list<FontFamily*> fontFamilyWeakPtrs;
// Iterate through all currently loaded font families
for (auto it : m_fontFamilyReverseLookup)
{
fontFamilyWeakPtrs.push_back(it.first);
fontFamilyFilenames.push_back(it.second->first);
}
// Release font-family resources and unmap them
for (auto fontFamily : fontFamilyWeakPtrs)
{
ReleaseFontFamily(fontFamily);
}
// Reload the font families
for (auto familyFilename : fontFamilyFilenames)
{
LoadFontFamily(familyFilename.c_str());
}
// All UI text components need to reload their font assets (both in-game
// and in-editor).
EBUS_EVENT(FontNotificationBus, OnFontsReloaded);
}
void AZ::AtomFont::UnregisterFont(const char* fontName)
{
FontMapItor it = m_fonts.find(CONST_TEMP_STRING(fontName));
#if defined(AZ_ENABLE_TRACING)
IFFont* fontPtr = it->second;
#endif
if (it != m_fonts.end())
{
m_fonts.erase(it);
}
#if defined(AZ_ENABLE_TRACING)
// Make sure the font being released isn't currently in use by a font family.
// If it is, the FontFamily will have a dangling pointer and will cause a
// crash when the FontFamily eventually gets released.
for (auto reverseMapEntry : m_fontFamilyReverseLookup)
{
FontFamily* fontFamily = reverseMapEntry.first;
AZ_Assert(fontFamily->normal != fontPtr,
"The following font is being freed but still in use by a FontFamily: %s",
fontName);
AZ_Assert(fontFamily->italic != fontPtr,
"The following font is being freed but still in use by a FontFamily: %s",
fontName);
AZ_Assert(fontFamily->bold != fontPtr,
"The following font is being freed but still in use by a FontFamily: %s",
fontName);
AZ_Assert(fontFamily->boldItalic != fontPtr,
"The following font is being freed but still in use by a FontFamily: %s",
fontName);
}
#endif
}
IFFont* AZ::AtomFont::LoadFont(const char* fontName)
{
string fontNameLower = fontName;
fontNameLower.MakeLower();
IFFont* font = GetFont(fontNameLower);
if (font)
{
font->AddRef(); // use existing loaded font
}
else
{
// attempt to create and load a new font, use the font pathname as the font name
font = NewFont(fontNameLower);
if (!font)
{
string errorMsg = "Error creating a new font named ";
errorMsg += fontNameLower;
errorMsg += ".";
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, errorMsg.c_str());
}
else
{
// creating font adds one to its refcount so no need for AddRef here
if (!font->Load(fontNameLower))
{
string errorMsg = "Error loading a font from ";
errorMsg += fontNameLower;
errorMsg += ".";
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, errorMsg);
font->Release();
font = nullptr;
}
}
}
return font;
}
void AZ::AtomFont::ReleaseFontFamily(FontFamily* fontFamily)
{
// Ensure that Font Family was mapped prior to destruction
const bool isMapped = m_fontFamilyReverseLookup.find(fontFamily) != m_fontFamilyReverseLookup.end();
if (!isMapped)
{
return;
}
// Note that the FontFamily is mapped both by filename and by "family name"
auto it = m_fontFamilyReverseLookup[fontFamily];
m_fontFamilies.erase(it);
string familyName(fontFamily->familyName);
m_fontFamilies.erase(familyName.MakeLower().c_str());
// Reverse lookup is used to avoid needing to store filename path with
// the font family, so we need to remove that entry also.
m_fontFamilyReverseLookup.erase(fontFamily);
SAFE_RELEASE(fontFamily->normal);
SAFE_RELEASE(fontFamily->bold);
SAFE_RELEASE(fontFamily->italic);
SAFE_RELEASE(fontFamily->boldItalic);
}
bool AZ::AtomFont::AddFontFamilyToMaps(const char* fontFamilyFilename, const char* fontFamilyName, FontFamilyPtr fontFamily)
{
if (!fontFamilyFilename || !fontFamilyName || !fontFamily.get())
{
return false;
}
// We don't support "updating" mapped values.
AZStd::string loweredFilename(PathUtil::MakeGamePath(string(fontFamilyFilename)).c_str());
AZStd::to_lower<AZStd::string::iterator>(loweredFilename.begin(), loweredFilename.end());
if (m_fontFamilies.find(loweredFilename) != m_fontFamilies.end())
{
string warnMsg;
warnMsg.Format("Couldn't load Font Family '%s': already loaded", fontFamilyFilename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, warnMsg.c_str());
return false;
}
// Similarly, we don't support Font Family XMLs that have the same font
// family name (we assume all Font Family names are unique).
AZStd::string loweredFontFamilyName(fontFamilyName);
AZStd::to_lower<AZStd::string::iterator>(loweredFontFamilyName.begin(), loweredFontFamilyName.end());
if (m_fontFamilies.find(loweredFontFamilyName) != m_fontFamilies.end())
{
string warnMsg;
warnMsg.Format("Couldn't load Font Family '%s': already loaded", fontFamilyName);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, warnMsg.c_str());
return false;
}
// First, insert by filename
AZStd::pair<AZStd::string, AZStd::weak_ptr<FontFamily>> insertPair(loweredFilename, fontFamily);
auto iterPosition = m_fontFamilies.insert(insertPair).first;
m_fontFamilyReverseLookup[fontFamily.get()] = iterPosition;
// Then, by Font Family name
AZStd::pair<AZStd::string, AZStd::weak_ptr<FontFamily>> nameInsertPair(loweredFontFamilyName, fontFamily);
m_fontFamilies.insert(nameInsertPair);
return true;
}
XmlNodeRef AZ::AtomFont::LoadFontFamilyXml(const char* fontFamilyName, string& outputDirectory, string& outputFullPath)
{
outputFullPath = fontFamilyName;
outputDirectory = PathUtil::GetPath(fontFamilyName);
XmlNodeRef root = SafeLoadXmlFromFile(outputFullPath);
// When parsing a <font> tag in markup, only the font name is given and
// not a path, so we try to build a "best guess" path from the name.
if (!root)
{
string fileNoExtension(PathUtil::GetFileName(fontFamilyName));
string fileExtension(PathUtil::GetExt(fontFamilyName));
if (fileExtension.empty())
{
fileExtension = ".fontfamily";
}
// Try: "fonts/fontName.fontfamily"
outputDirectory = string("fonts/");
outputFullPath = outputDirectory + fileNoExtension + fileExtension;
root = SafeLoadXmlFromFile(outputFullPath);
// Finally, try: "fonts/fontName/fontName.fontfamily"
if (!root)
{
outputDirectory = string("fonts/") + fileNoExtension + "/";
outputFullPath = outputDirectory + fileNoExtension + fileExtension;
root = SafeLoadXmlFromFile(outputFullPath);
}
}
return root;
}
#endif
@@ -0,0 +1,111 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// Russian resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
#ifdef _WIN32
LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
#pragma code_page(1251)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"..\Include\resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#endif // Russian resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// German (Germany) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
#ifdef _WIN32
LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "000904b0"
BEGIN
VALUE "CompanyName", "Amazon.com, Inc."
VALUE "FileVersion", "1, 0, 0, 1"
VALUE "LegalCopyright", "Portions of this file Copyright (c) Amazon.com, Inc. or its affiliates. All Rights Reserved. Original file Copyright (c) Crytek GMBH. Used under license by Amazon.com, Inc. and its affiliates."
VALUE "ProductName", "Lumberyard"
VALUE "ProductVersion", "1, 0, 0, 1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x9, 1200
END
END
#endif // German (Germany) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
@@ -0,0 +1,115 @@
/*
* 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 <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#include "AtomFontSystemComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzFramework/Components/ConsoleBus.h>
#include <ISystem.h>
#include <AtomLyIntegration/AtomFont/AtomNullFont.h>
#include <AtomLyIntegration/AtomFont/AtomFont.h>
namespace AZ
{
namespace Render
{
void AtomFontSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<AtomFontSystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<AtomFontSystemComponent>("Font", "Manages lifetime of the font subsystem")
->ClassElement(Edit::ClassElements::EditorData, "")
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
->Attribute(Edit::Attributes::AutoExpand, true)
;
}
}
}
void AtomFontSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AtomFontService"));
}
void AtomFontSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("AtomFontService"));
}
void AtomFontSystemComponent::GetRequiredServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& required)
{
}
void AtomFontSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
}
void AtomFontSystemComponent::Activate()
{
AZ::CryFontCreationRequestBus::Handler::BusConnect();
}
void AtomFontSystemComponent::Deactivate()
{
AZ::CryFontCreationRequestBus::Handler::BusDisconnect();
}
bool AtomFontSystemComponent::CreateCryFont(SSystemGlobalEnvironment& env, [[maybe_unused]] const SSystemInitParams& initParams)
{
ISystem* system = env.pSystem;
#if !defined(AZ_MONOLITHIC_BUILD)
// When module is linked dynamically, we must set our gEnv pointer.
// When module is linked statically, we'll share the application's gEnv pointer.
gEnv = system->GetGlobalEnvironment();
#endif
if (env.IsDedicated())
{
#if defined(USE_NULLFONT)
env.pCryFont = new AtomNullFont();
#else
// The NULL font implementation must be present for all platforms
// supporting running as a pure dedicated server.
system->GetILog()->LogError("Missing NULL font implementation for dedicated server");
env.pCryFont = NULL;
#endif
}
else
{
#if defined(USE_NULLFONT) && defined(USE_NULLFONT_ALWAYS)
env.pCryFont = new AtomNullFont();
#else
env.pCryFont = new AtomFont(system);
#endif
}
return env.pCryFont != 0;
}
void AtomFontSystemComponent::OnCrySystemShutdown([[maybe_unused]] ISystem& system)
{
#if !defined(AZ_MONOLITHIC_BUILD)
gEnv = nullptr;
#endif
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,56 @@
/*
* 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/Component/Component.h>
#include <CryCommon/CryFontBus.h>
#include <CryCommon/CrySystemBus.h>
namespace AZ
{
namespace Render
{
class AtomFontSystemComponent
: public AZ::Component
, private AZ::CryFontCreationRequestBus::Handler
, private CrySystemEventBus::Handler
{
public:
AZ_COMPONENT(AtomFontSystemComponent, "{29DC7010-CF2A-4EE4-91F8-8E3C8BE65F41}");
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:
////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// CryFontCreationBus
bool CreateCryFont(SSystemGlobalEnvironment& env, const SSystemInitParams& initParams) override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// CryFontCreationBus
void OnCrySystemShutdown(ISystem& system) override;
////////////////////////////////////////////////////////////////////////
};
} // namespace Render
} // namespace AZ
@@ -0,0 +1,14 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
@@ -0,0 +1,24 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Dummy font implementation (dedicated server)
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if defined(USE_NULLFONT)
#include <AtomLyIntegration/AtomFont//AtomNullFont.h>
AZ::AtomNullFFont AZ::AtomNullFont::NullFFont;
#endif // USE_NULLFONT
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,81 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : XML parsing to load a font.
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include "FFontXML_Internal.h"
#include <AtomLyIntegration/AtomFont/FFont.h>
#include <AtomLyIntegration/AtomFont/FontTexture.h>
#include <CryCommon/Cry_Math.h>
#include <CryCommon/CryPath.h>
#include <AzCore/PlatformIncl.h>
//////////////////////////////////////////////////////////////////////////
// Main loading function
bool AZ::FFont::Load(const char* xmlFile)
{
m_curPath = "";
if (xmlFile)
{
m_curPath = PathUtil::GetPath(xmlFile);
}
XmlNodeRef root = GetISystem()->LoadXmlFromFile(xmlFile);
if (!root)
{
return false;
}
AtomFontInternal::XmlFontShader xmlfs(this);
xmlfs.ScanXmlNodesRecursively(root);
// if this was not a valid font XML file then return false
if (!m_fontTexture || !m_fontBuffer)
{
return false;
}
// if there was a font effect file then parse that for effects
if (!xmlfs.m_strFontEffectPath.empty())
{
XmlNodeRef fontEffectRoot = GetISystem()->LoadXmlFromFile(xmlfs.m_strFontEffectPath.c_str());
if (!fontEffectRoot)
{
AZ_Warning("Font", false, "Error parsing font file %s, 'effectfile' pathname %s could not be found.",
xmlFile, xmlfs.m_strFontEffectPath.c_str());
return false;
}
if (m_effects.size() > 1 || (m_effects.size() == 1 && (m_effects[0].m_name != "default" || m_effects[0].m_passes.size() > 1)))
{
AZ_Warning("Font", false, "Error parsing font file %s, 'effectfile' and 'effect' cannot both be used in the same font file.",
xmlFile);
m_effects.clear();
}
// parse the font effects file, adding to this font object
AtomFontInternal::XmlFontShader xmlfsEffect(this);
xmlfsEffect.ScanXmlNodesRecursively(fontEffectRoot);
}
return true;
}
#endif
@@ -0,0 +1,408 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/FFont.h>
#include <AtomLyIntegration/AtomFont/FontTexture.h>
#include <CryCommon/Cry_Math.h>
#include <CryCommon/CryPath.h>
#include <AzCore/PlatformIncl.h>
//////////////////////////////////////////////////////////////////////////
// Xml parser implementation
namespace AtomFontInternal
{
enum
{
ELEMENT_UNKNOWN = 0,
ELEMENT_FONT = 1,
ELEMENT_EFFECT = 2,
ELEMENT_EFFECTFILE = 3,
ELEMENT_PASS = 4,
ELEMENT_PASS_COLOR = 5,
ELEMENT_PASS_POSOFFSET = 12,
ELEMENT_PASS_BLEND = 14
};
inline int GetBlendModeFromString(const string& str, bool dst)
{
int blend = GS_BLSRC_ONE;
if (str == "zero")
{
blend = dst ? GS_BLDST_ZERO : GS_BLSRC_ZERO;
}
else if (str == "one")
{
blend = dst ? GS_BLDST_ONE : GS_BLSRC_ONE;
}
else if (str == "srcalpha" ||
str == "src_alpha")
{
blend = dst ? GS_BLDST_SRCALPHA : GS_BLSRC_SRCALPHA;
}
else if (str == "invsrcalpha" ||
str == "inv_src_alpha")
{
blend = dst ? GS_BLDST_ONEMINUSSRCALPHA : GS_BLSRC_ONEMINUSSRCALPHA;
}
else if (str == "dstalpha" ||
str == "dst_alpha")
{
blend = dst ? GS_BLDST_DSTALPHA : GS_BLSRC_DSTALPHA;
}
else if (str == "invdstalpha" ||
str == "inv_dst_alpha")
{
blend = dst ? GS_BLDST_ONEMINUSDSTALPHA : GS_BLSRC_ONEMINUSDSTALPHA;
}
else if (str == "dstcolor" ||
str == "dst_color")
{
blend = GS_BLSRC_DSTCOL;
}
else if (str == "srccolor" ||
str == "src_color")
{
blend = GS_BLDST_SRCCOL;
}
else if (str == "invdstcolor" ||
str == "inv_dst_color")
{
blend = GS_BLSRC_ONEMINUSDSTCOL;
}
else if (str == "invsrccolor" ||
str == "inv_src_color")
{
blend = GS_BLDST_ONEMINUSSRCCOL;
}
return blend;
}
inline int CreateTTFFontFlag(AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount)
{
return (
((static_cast<int>(smoothMethod) << TTFFLAG_SMOOTH_SHIFT) & TTFFLAG_SMOOTH_MASK) |
((static_cast<int>(smoothAmount) << TTFFLAG_SMOOTH_AMOUNT_SHIFT) & TTFFLAG_SMOOTH_AMOUNT_MASK)
);
}
inline AZ::FontSmoothMethod TranslateSmoothMethod(const string& value)
{
AZ::FontSmoothMethod smoothMethod = AZ::FontSmoothMethod::None;
if (value == "blur")
{
smoothMethod = AZ::FontSmoothMethod::Blur;
}
else if (value == "supersample")
{
smoothMethod = AZ::FontSmoothMethod::SuperSample;
}
return smoothMethod;
}
inline AZ::FontSmoothAmount TranslateSmoothAmount(int value)
{
AZ::FontSmoothAmount smoothAmount = AZ::FontSmoothAmount::None;
if (value == 1)
{
smoothAmount = AZ::FontSmoothAmount::x2;
}
else if (value > 1)
{
smoothAmount = AZ::FontSmoothAmount::x4;
}
return smoothAmount;
}
class XmlFontShader
{
static const int DefaultSlotWidthSize = 16;
static const int DefaultSlotHeightSize = 8;
public:
XmlFontShader(AZ::FFont* font)
: m_font(font)
, m_nElement(ELEMENT_UNKNOWN)
, m_slotSizes(DefaultSlotWidthSize, DefaultSlotHeightSize)
, m_effect(NULL)
, m_pass(NULL)
, m_FontTexSize(0, 0)
, m_FontSmoothAmount(AZ::FontSmoothAmount::None)
, m_FontSmoothMethod(AZ::FontSmoothMethod::None)
{
}
~XmlFontShader()
{
}
void ScanXmlNodesRecursively(XmlNodeRef node)
{
if (!node)
{
return;
}
FoundElement(node->getTag());
for (int i = 0, count = node->getNumAttributes(); i < count; ++i)
{
const char* key = "";
const char* value = "";
if (node->getAttributeByIndex(i, &key, &value))
{
FoundAttribute(key, value);
}
}
for (int i = 0, count = node->getChildCount(); i < count; ++i)
{
XmlNodeRef child = node->getChild(i);
ScanXmlNodesRecursively(child);
}
}
private:
void FoundElementImpl();
// notify methods
void FoundElement(const string& name)
{
//MessageBox(NULL, string("[" + name + "]").c_str(), "FoundElement", MB_OK);
// process the previous element
switch (m_nElement)
{
case ELEMENT_FONT:
{
if (!m_FontTexSize.x || !m_FontTexSize.y)
{
m_FontTexSize.set(512, 512);
}
bool fontLoaded = m_font->Load(m_strFontPath.c_str(), m_FontTexSize.x, m_FontTexSize.y, m_slotSizes.x, m_slotSizes.y, CreateTTFFontFlag(m_FontSmoothMethod, m_FontSmoothAmount), m_SizeRatio);
if (!fontLoaded)
{
FoundElementImpl();
}
}
break;
default:
break;
}
// Translate the m_nElement name to a define
if (name == "font")
{
m_nElement = ELEMENT_FONT;
}
else if (name == "effect")
{
m_nElement = ELEMENT_EFFECT;
}
else if (name == "effectfile")
{
m_nElement = ELEMENT_EFFECTFILE;
}
else if (name == "pass")
{
m_pass = NULL;
m_nElement = ELEMENT_PASS;
if (m_effect)
{
m_pass = m_effect->AddPass();
}
}
else if (name == "color")
{
m_nElement = ELEMENT_PASS_COLOR;
}
else if (name == "pos" ||
name == "offset")
{
m_nElement = ELEMENT_PASS_POSOFFSET;
}
else if (name == "blend" ||
name == "blending")
{
m_nElement = ELEMENT_PASS_BLEND;
}
else
{
m_nElement = ELEMENT_UNKNOWN;
}
}
void FoundAttribute(const string& name, const string& value)
{
//MessageBox(NULL, string(name + "\n" + value).c_str(), "FoundAttribute", MB_OK);
switch (m_nElement)
{
case ELEMENT_FONT:
if (name == "path")
{
m_strFontPath = value;
}
else if (name == "w")
{
m_FontTexSize.x = (long)atof(value.c_str());
}
else if (name == "h")
{
m_FontTexSize.y = (long)atof(value.c_str());
}
else if (name == "widthslots")
{
m_slotSizes.x = (int)atoi(value.c_str());
}
else if (name == "heightslots")
{
m_slotSizes.y = (int)atoi(value.c_str());
}
else if (name == "sizeratio")
{
m_SizeRatio = static_cast<float>(atof(value.c_str()));
}
else if (name == "smooth")
{
m_FontSmoothMethod = TranslateSmoothMethod(value);
}
else if (name == "smooth_amount")
{
m_FontSmoothAmount = TranslateSmoothAmount((int)atof(value.c_str()));
}
break;
case ELEMENT_EFFECT:
if (name == "name")
{
if (value == "default")
{
m_effect = m_font->GetDefaultEffect();
m_effect->ClearPasses();
}
else
{
m_effect = m_font->AddEffect(value.c_str());
}
}
break;
case ELEMENT_EFFECTFILE:
if (name == "path")
{
m_strFontEffectPath = value;
}
break;
case ELEMENT_PASS_COLOR:
if (!m_pass)
{
break;
}
if (name == "r")
{
m_pass->m_color.r = (uint8_t)((float)atof(value.c_str()) * 255.0f);
}
else if (name == "g")
{
m_pass->m_color.g = (uint8_t)((float)atof(value.c_str()) * 255.0f);
}
else if (name == "b")
{
m_pass->m_color.b = (uint8_t)((float)atof(value.c_str()) * 255.0f);
}
else if (name == "a")
{
m_pass->m_color.a = (uint8_t)((float)atof(value.c_str()) * 255.0f);
}
break;
case ELEMENT_PASS_POSOFFSET:
if (!m_pass)
{
break;
}
if (name == "x")
{
m_pass->m_posOffset.x = (float)atoi(value.c_str());
}
else if (name == "y")
{
m_pass->m_posOffset.y = (float)atoi(value.c_str());
}
break;
case ELEMENT_PASS_BLEND:
if (!m_pass)
{
break;
}
if (name == "src")
{
m_pass->m_blendSrc = GetBlendModeFromString(value, false);
}
else if (name == "dst")
{
m_pass->m_blendDest = GetBlendModeFromString(value, true);
}
else if (name == "type")
{
if (value == "modulate")
{
m_pass->m_blendSrc = GS_BLSRC_SRCALPHA;
m_pass->m_blendDest = GS_BLDST_ONEMINUSSRCALPHA;
}
else if (value == "additive")
{
m_pass->m_blendSrc = GS_BLSRC_SRCALPHA;
m_pass->m_blendDest = GS_BLDST_ONE;
}
}
break;
default:
case ELEMENT_UNKNOWN:
break;
}
}
public:
AZ::FFont* m_font;
unsigned long m_nElement;
AZ::FFont::FontEffect* m_effect;
AZ::FFont::FontRenderingPass* m_pass;
string m_strFontPath;
string m_strFontEffectPath;
vector2l m_FontTexSize;
AZ::AtomFont::GlyphSize m_slotSizes;
float m_SizeRatio = IFFontConstants::defaultSizeRatio;
AZ::FontSmoothMethod m_FontSmoothMethod;
AZ::FontSmoothAmount m_FontSmoothAmount;
};
}
#endif
@@ -0,0 +1,332 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
//
// Purpose:
// - Render a glyph outline into a bitmap using FreeType 2
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/FontRenderer.h>
#include <freetype/ftoutln.h>
#include <freetype/ftglyph.h>
#include <freetype/ftimage.h>
#include <AzCore/Casting/lossy_cast.h>
// Sizes are defined in in 26.6 fixed float format (TT_F26Dot6), where
// 1 unit is 1/64 of a pixel.
constexpr int FractionalPixelUnits = 64;
namespace
{
FT_Int32 GetLoadFlags(AZ::FFont::HintBehavior hintBehavior)
{
switch (hintBehavior)
{
case AZ::FFont::HintBehavior::NoHinting:
{
return FT_LOAD_NO_HINTING;
break;
}
case AZ::FFont::HintBehavior::AutoHint:
{
return FT_LOAD_FORCE_AUTOHINT;
break;
}
}
return FT_LOAD_DEFAULT;
}
FT_Int32 GetLoadTarget(AZ::FFont::HintStyle hintStyle)
{
if (hintStyle == AZ::FFont::HintStyle::Light)
{
return FT_LOAD_TARGET_LIGHT;
}
return FT_LOAD_TARGET_NORMAL;
}
FT_Render_Mode GetRenderMode(AZ::FFont::HintStyle hintStyle)
{
// We use the hint style to drive the render mode also. These should
// usually be correlated with each other for best results, even though
// they could technically be different.
if (hintStyle == AZ::FFont::HintStyle::Light)
{
return FT_RENDER_MODE_LIGHT;
}
return FT_RENDER_MODE_NORMAL;
}
}
//-------------------------------------------------------------------------------------------------
AZ::FontRenderer::FontRenderer()
: m_library(0)
, m_face(0)
, m_glyph(0)
, m_sizeRatio(IFFontConstants::defaultSizeRatio)
, m_encoding(AZ_FONT_ENCODING_UNICODE)
, m_glyphBitmapWidth(0)
, m_glyphBitmapHeight(0)
{
}
//-------------------------------------------------------------------------------------------------
AZ::FontRenderer::~FontRenderer()
{
FT_Done_Face(m_face);
;
FT_Done_FreeType(m_library);
m_face = NULL;
m_library = NULL;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontRenderer::LoadFromFile(const string& fileName)
{
int iError = FT_Init_FreeType(&m_library);
if (iError)
{
return 0;
}
if (m_face)
{
FT_Done_Face(m_face);
m_face = 0;
}
iError = FT_New_Face(m_library, fileName.c_str(), 0, &m_face);
if (iError)
{
return 0;
}
SetEncoding(AZ_FONT_ENCODING_UNICODE);
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontRenderer::LoadFromMemory(unsigned char* buffer, int bufferSize)
{
int iError = FT_Init_FreeType(&m_library);
if (iError)
{
return 0;
}
if (m_face)
{
FT_Done_Face(m_face);
m_face = 0;
}
iError = FT_New_Memory_Face(m_library, buffer, bufferSize, 0, &m_face);
if (iError)
{
return 0;
}
SetEncoding(AZ_FONT_ENCODING_UNICODE);
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontRenderer::Release()
{
FT_Done_Face(m_face);
;
FT_Done_FreeType(m_library);
m_face = NULL;
m_library = NULL;
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontRenderer::SetGlyphBitmapSize(int width, int height, float sizeRatio)
{
m_glyphBitmapWidth = width;
m_glyphBitmapHeight = height;
// Assign the given scale for texture slots as long as its positive
m_sizeRatio = sizeRatio > 0.0f ? sizeRatio : m_sizeRatio;
FT_Set_Pixel_Sizes(m_face, (int)(m_glyphBitmapWidth * m_sizeRatio), (int)(m_glyphBitmapHeight * m_sizeRatio));
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontRenderer::GetGlyphBitmapSize(int* width, int* height)
{
if (width)
{
*width = m_glyphBitmapWidth;
}
if (height)
{
*height = m_glyphBitmapHeight;
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontRenderer::SetEncoding(FT_Encoding encoding)
{
if (FT_Select_Charmap(m_face, encoding))
{
return 0;
}
return 1;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
int AZ::FontRenderer::GetGlyph(GlyphBitmap* glyphBitmap, int* horizontalAdvance, uint8_t* glyphWidth, uint8_t* glyphHeight, int32_t& m_characterOffsetX, int32_t& m_characterOffsetY, int iX, int iY, int characterCode, const FFont::FontHintParams& fontHintParams)
{
FT_Int32 loadFlags = GetLoadFlags(fontHintParams.hintBehavior);
loadFlags |= GetLoadTarget(fontHintParams.hintStyle);
int iError = FT_Load_Char(m_face, characterCode, loadFlags);
if (iError)
{
return 0;
}
FT_Render_Mode renderMode = GetRenderMode(fontHintParams.hintStyle);
m_glyph = m_face->glyph;
iError = FT_Render_Glyph(m_glyph, renderMode);
if (iError)
{
return 0;
}
if (horizontalAdvance)
{
*horizontalAdvance = m_glyph->metrics.horiAdvance / FractionalPixelUnits;
}
if (glyphWidth)
{
*glyphWidth = m_glyph->bitmap.width;
}
if (glyphHeight)
{
*glyphHeight = m_glyph->bitmap.rows;
}
unsigned char* buffer = glyphBitmap->GetBuffer();
AZ_Assert(buffer, "GlyphBitmap: bad buffer");
uint32_t dwGlyphWidth = glyphBitmap->GetWidth();
m_characterOffsetX = m_glyph->bitmap_left;
m_characterOffsetY = (static_cast<int32_t>(round(m_glyphBitmapHeight * m_sizeRatio)) - m_glyph->bitmap_top);
const int textureSlotBufferWidth = glyphBitmap->GetWidth();
const int textureSlotBufferHeight = glyphBitmap->GetHeight();
// might happen if font characters are too big or cache dimenstions in font.xml is too small "<font path="VeraMono.ttf" w="320" h="368"/>"
const bool charWidthFits = iX + m_glyph->bitmap.width <= textureSlotBufferWidth;
const bool charHeightFits = iY + m_glyph->bitmap.rows <= textureSlotBufferHeight;
const bool charFitsInSlot = charWidthFits && charHeightFits;
AZ_Error("Font", charFitsInSlot, "Character code %d doesn't fit in font texture; check 'sizeRatio' attribute in font XML or adjust this character's sizing in the font.", characterCode);
// Since we might be re-rendering/overwriting a glyph that already exists
// in the font texture, clear the contents of this particular slot so no
// artifacts of the previous glyph remain.
glyphBitmap->Clear();
// Restrict iteration to smallest of either the texture slot or glyph
// bitmap buffer ranges
const int bufferMaxIterWidth = AZStd::GetMin<int>(textureSlotBufferWidth, m_glyph->bitmap.width);
const int bufferMaxIterHeight = AZStd::GetMin<int>(textureSlotBufferHeight, m_glyph->bitmap.rows);
for (int i = 0; i < bufferMaxIterHeight; i++)
{
int iNewY = i + iY;
for (int j = 0; j < bufferMaxIterWidth; j++)
{
unsigned char cColor = m_glyph->bitmap.buffer[(i * m_glyph->bitmap.width) + j];
int iOffset = iNewY * dwGlyphWidth + iX + j;
if (iOffset >= (int)dwGlyphWidth * m_glyphBitmapHeight)
{
continue;
}
buffer[iOffset] = cColor;
// buffer[iOffset] = cColor/2+32; // debug - visualize character in a block
}
}
return 1;
}
int AZ::FontRenderer::GetGlyphScaled([[maybe_unused]] GlyphBitmap* glyphBitmap, [[maybe_unused]] int* glyphWidth, [[maybe_unused]] int* glyphHeight, [[maybe_unused]] int iX, [[maybe_unused]] int iY, [[maybe_unused]] float scaleX, [[maybe_unused]] float scaleY, [[maybe_unused]] int characterCode)
{
return 1;
}
Vec2 AZ::FontRenderer::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
{
FT_Vector kerningOffsets;
kerningOffsets.x = kerningOffsets.y = 0;
if (FT_HAS_KERNING(m_face))
{
const FT_UInt leftGlyphIndex = FT_Get_Char_Index(m_face, leftGlyph);
const FT_UInt rightGlyphIndex = FT_Get_Char_Index(m_face, rightGlyph);
FT_Error ftError = FT_Get_Kerning(m_face, leftGlyphIndex, rightGlyphIndex, FT_KERNING_DEFAULT, &kerningOffsets);
#if !defined(_RELEASE)
if (0 != ftError)
{
string warnMsg;
warnMsg.Format("FT_Get_Kerning returned %d", ftError);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, warnMsg.c_str());
}
#endif
}
return Vec2(azlossy_cast<float>(kerningOffsets.x / FractionalPixelUnits), azlossy_cast<float>(kerningOffsets.y / FractionalPixelUnits));
}
float AZ::FontRenderer::GetAscenderToHeightRatio()
{
return (static_cast<float>(m_face->ascender) / static_cast<float>(m_face->height));
}
#endif // #if !defined(USE_NULLFONT_ALWAYS)
@@ -0,0 +1,575 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Purpose:
// - Create and update a texture with the most recently used glyphs
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/FontTexture.h>
#include <CryCommon/UnicodeIterator.h>
#include <AzCore/IO/FileIO.h>
//-------------------------------------------------------------------------------------------------
AZ::FontTexture::FontTexture()
: m_slotUsage(1)
, m_width(0)
, m_height(0)
, m_invWidth(0.0f)
, m_invHeight(0.0f)
, m_cellWidth(0)
, m_cellHeight(0)
, m_textureCellWidth(0)
, m_textureCellHeight(0)
, m_widthCellCount(0)
, m_heightCellCount(0)
, m_textureSlotCount(0)
, m_buffer(0)
, m_smoothMethod(AZ::FontSmoothMethod::None)
, m_smoothAmount(AZ::FontSmoothAmount::None)
{
}
//-------------------------------------------------------------------------------------------------
AZ::FontTexture::~FontTexture()
{
Release();
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::CreateFromFile(const string& fileName, int width, int height, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, int widthCellCount, int heightCellCount)
{
if (!m_glyphCache.LoadFontFromFile(fileName))
{
Release();
return 0;
}
if (!Create(width, height, smoothMethod, smoothAmount, widthCellCount, heightCellCount))
{
return 0;
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::CreateFromMemory(unsigned char* fileData, int dataSize, int width, int height, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, int widthCellCount, int heightCellCount, float sizeRatio)
{
if (!m_glyphCache.LoadFontFromMemory(fileData, dataSize))
{
Release();
return 0;
}
if (!Create(width, height, smoothMethod, smoothAmount, widthCellCount, heightCellCount, sizeRatio))
{
return 0;
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::Create(int width, int height, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, int widthCellCount, int heightCellCount, float sizeRatio)
{
m_buffer = new FONT_TEXTURE_TYPE[width * height];
if (!m_buffer)
{
return 0;
}
memset(m_buffer, 0, width * height * sizeof(FONT_TEXTURE_TYPE));
if (!(widthCellCount * heightCellCount))
{
return 0;
}
m_width = width;
m_height = height;
m_invWidth = 1.0f / (float)width;
m_invHeight = 1.0f / (float)height;
m_widthCellCount = widthCellCount;
m_heightCellCount = heightCellCount;
m_textureSlotCount = m_widthCellCount * m_heightCellCount;
m_smoothMethod = smoothMethod;
m_smoothAmount = smoothAmount;
m_cellWidth = m_width / m_widthCellCount;
m_cellHeight = m_height / m_heightCellCount;
m_textureCellWidth = m_cellWidth * m_invWidth;
m_textureCellHeight = m_cellHeight * m_invHeight;
if (!m_glyphCache.Create(AZ_FONT_GLYPH_CACHE_SIZE, m_cellWidth, m_cellHeight, smoothMethod, smoothAmount, sizeRatio))
{
Release();
return 0;
}
if (!CreateSlotList(m_textureSlotCount))
{
Release();
return 0;
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::Release()
{
delete[] m_buffer;
m_buffer = 0;
ReleaseSlotList();
m_slotIndexMap.clear();
m_glyphCache.Release();
m_widthCellCount = 0;
m_heightCellCount = 0;
m_textureSlotCount = 0;
m_width = 0;
m_height = 0;
m_invWidth = 0.0f;
m_invHeight = 0.0f;
m_cellWidth = 0;
m_cellHeight = 0;
m_smoothMethod = AZ::FontSmoothMethod::None;
m_smoothAmount = AZ::FontSmoothAmount::None;
m_textureCellWidth = 0.0f;
m_textureCellHeight = 0.0f;
m_slotUsage = 1;
return 1;
}
//-------------------------------------------------------------------------------------------------
uint32_t AZ::FontTexture::GetSlotChar(int slotIndex) const
{
return m_slotList[slotIndex]->m_currentCharacter;
}
//-------------------------------------------------------------------------------------------------
AZ::TextureSlot* AZ::FontTexture::GetCharSlot(uint32_t character, const AZ::AtomFont::GlyphSize& glyphSize)
{
TextureSlotKey slotKey = GetTextureSlotKey(character, glyphSize);
TextureSlotTableItor pItor = m_slotIndexMap.find(slotKey);
if (pItor != m_slotIndexMap.end())
{
return pItor->second;
}
return 0;
}
//-------------------------------------------------------------------------------------------------
AZ::TextureSlot* AZ::FontTexture::GetLRUSlot()
{
uint16_t wMaxSlotAge = 0;
TextureSlot* pLRUSlot = 0;
TextureSlot* slot;
TextureSlotListItor pItor = m_slotList.begin();
while (pItor != m_slotList.end())
{
slot = *pItor;
if (slot->m_slotUsage == 0)
{
return slot;
}
else
{
uint16_t slotAge = m_slotUsage - slot->m_slotUsage;
if (slotAge > wMaxSlotAge)
{
pLRUSlot = slot;
wMaxSlotAge = slotAge;
}
}
++pItor;
}
return pLRUSlot;
}
//-------------------------------------------------------------------------------------------------
AZ::TextureSlot* AZ::FontTexture::GetMRUSlot()
{
uint16_t wMinSlotAge = 0xFFFF;
TextureSlot* pMRUSlot = 0;
TextureSlot* slot;
TextureSlotListItor pItor = m_slotList.begin();
while (pItor != m_slotList.end())
{
slot = *pItor;
if (slot->m_slotUsage != 0)
{
uint16_t slotAge = m_slotUsage - slot->m_slotUsage;
if (slotAge > wMinSlotAge)
{
pMRUSlot = slot;
wMinSlotAge = slotAge;
}
}
++pItor;
}
return pMRUSlot;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::PreCacheString(const char* string, int* updated, float sizeRatio, const AZ::AtomFont::GlyphSize& glyphSize, const FFont::FontHintParams& fontHintParams)
{
AZ::AtomFont::GlyphSize clampedGlyphSize = ClampGlyphSize(glyphSize, m_cellWidth, m_cellHeight);
uint16_t slotUsage = m_slotUsage++;
int updateCount = 0;
uint32_t character;
for (Unicode::CIterator<const char*, false> it(string); character = *it; ++it)
{
TextureSlot* slot = GetCharSlot(character, clampedGlyphSize);
if (!slot)
{
slot = GetLRUSlot();
if (!slot)
{
return 0;
}
if (!UpdateSlot(slot->m_textureSlot, slotUsage, character, sizeRatio, clampedGlyphSize, fontHintParams))
{
return 0;
}
++updateCount;
}
else
{
slot->m_slotUsage = slotUsage;
}
}
if (updated)
{
*updated = updateCount;
}
if (updated)
{
return 1;
}
return 2;
}
//-------------------------------------------------------------------------------------------------
void AZ::FontTexture::GetTextureCoord(AZ::TextureSlot* slot, float texCoords[4],
int& characterSizeX, int& characterSizeY, int& m_characterOffsetX, int& m_characterOffsetY,
const AZ::AtomFont::GlyphSize& glyphSize) const
{
if (!slot)
{
return; // expected behavior
}
// Re-rendered glyphs are stored at smaller sizes than glyphs rendered at
// the (maximum) font texture slot resolution. We scale the returned width
// and height of the (actual) rendered glyph sizes so its transparent to
// callers that the glyph is actually smaller (from being re-rendered).
const float requestSizeWidthScale = AZ::GetMin<float>(1.0f, GetRequestSizeWidthScale(glyphSize));
const float requestSizeHeightScale = AZ::GetMin<float>(1.0f, GetRequestSizeHeightScale(glyphSize));
const float invRequestSizeWidthScale = 1.0f / requestSizeWidthScale;
const float invRequestSizeHeightScale = 1.0f / requestSizeHeightScale;
// The inverse scale grows as the glyph size decreases. Once the glyph size
// reaches the font texture's max slot dimensions, we cap width/height scale
// since the text draw context will apply normal (as opposed to re-rendered)
// scaling.
int iChWidth = static_cast<int>(slot->m_characterWidth * invRequestSizeWidthScale);
int iChHeight = static_cast<int>(slot->m_characterHeight * invRequestSizeHeightScale);
float slotCoord0 = slot->m_texCoords[0];
float slotCoord1 = slot->m_texCoords[1];
texCoords[0] = slotCoord0 - m_invWidth; // extra pixel for nicer bilinear filter
texCoords[1] = slotCoord1 - m_invHeight; // extra pixel for nicer bilinear filter
// UV coordinates also must be scaled relative to the re-rendered glyph size
// as well. Width scale must be capped at 1.0f since glyph can't grow
// beyond the slot's resolution.
texCoords[2] = slotCoord0 + (((float)iChWidth * m_invWidth) * requestSizeWidthScale);
texCoords[3] = slotCoord1 + (((float)iChHeight * m_invHeight) * requestSizeHeightScale);
characterSizeX = iChWidth + 1; // extra pixel for nicer bilinear filter
characterSizeY = iChHeight + 1; // extra pixel for nicer bilinear filter
// Offsets are scaled accordingly when the rendered glyph size is smaller
// than the glyph/slot dimensions, but otherwise we expect the text draw
// context to apply scaling beyond that.
m_characterOffsetX = static_cast<int>(slot->m_characterOffsetX * invRequestSizeWidthScale);
m_characterOffsetY = static_cast<int>(slot->m_characterOffsetY * invRequestSizeHeightScale);
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::GetCharacterWidth(uint32_t character) const
{
TextureSlotTableItorConst pItor = m_slotIndexMap.find(GetTextureSlotKey(character));
if (pItor == m_slotIndexMap.end())
{
return 0;
}
const TextureSlot& rSlot = *pItor->second;
// For proportional fonts, add one pixel of spacing for aesthetic reasons
int proportionalOffset = GetMonospaced() ? 0 : 1;
return rSlot.m_characterWidth + proportionalOffset;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::GetHorizontalAdvance(uint32_t character, const AZ::AtomFont::GlyphSize& glyphSize) const
{
TextureSlotTableItorConst pItor = m_slotIndexMap.find(GetTextureSlotKey(character, glyphSize));
if (pItor == m_slotIndexMap.end())
{
return 0;
}
const TextureSlot& rSlot = *pItor->second;
// Re-rendered glyphs are stored at smaller sizes than glyphs rendered at
// the (maximum) font texture slot resolution. We scale the returned width
// and height of the (actual) rendered glyph sizes so its transparent to
// callers that the glyph is actually smaller (from being re-rendered).
const float requestSizeWidthScale = GetRequestSizeWidthScale(glyphSize);
const float invRequestSizeWidthScale = 1.0f / requestSizeWidthScale;
// Only multiply by 1.0f when glyphsize is greater than cell width because we assume that callers
// will use the font draw text context to scale the value appropriately.
return static_cast<int>(rSlot.m_horizontalAdvance * AZ::GetMax<float>(1.0f, invRequestSizeWidthScale));
}
//-------------------------------------------------------------------------------------------------
/*
int AZ::FontTexture::GetCharHeightByChar(wchar_t character)
{
TextureSlotTableItor pItor = m_slotIndexMap.find(character);
if (pItor != m_slotIndexMap.end())
{
return pItor->second->m_characterHeight;
}
return 0;
}
*/
//-------------------------------------------------------------------------------------------------
Vec2 AZ::FontTexture::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
{
return m_glyphCache.GetKerning(leftGlyph, rightGlyph);
}
//-------------------------------------------------------------------------------------------------
float AZ::FontTexture::GetAscenderToHeightRatio()
{
return m_glyphCache.GetAscenderToHeightRatio();
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::CreateSlotList(int listSize)
{
int y, x;
for (int i = 0; i < listSize; i++)
{
TextureSlot* pTextureSlot = new TextureSlot;
if (!pTextureSlot)
{
return 0;
}
pTextureSlot->m_textureSlot = i;
pTextureSlot->Reset();
y = i / m_widthCellCount;
x = i % m_widthCellCount;
pTextureSlot->m_texCoords[0] = (float)(x * m_textureCellWidth) + (0.5f / (float)m_width);
pTextureSlot->m_texCoords[1] = (float)(y * m_textureCellHeight) + (0.5f / (float)m_height);
m_slotList.push_back(pTextureSlot);
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::ReleaseSlotList()
{
TextureSlotListItor pItor = m_slotList.begin();
while (pItor != m_slotList.end())
{
delete (*pItor);
pItor = m_slotList.erase(pItor);
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::FontTexture::UpdateSlot(int slotIndex, uint16_t slotUsage, uint32_t character, float sizeRatio, const AZ::AtomFont::GlyphSize& glyphSize, const FFont::FontHintParams& fontHintParams)
{
TextureSlot* slot = m_slotList[slotIndex];
if (!slot)
{
return 0;
}
TextureSlotTableItor pItor = m_slotIndexMap.find(GetTextureSlotKey(slot->m_currentCharacter, slot->m_glyphSize));
if (pItor != m_slotIndexMap.end())
{
m_slotIndexMap.erase(pItor);
}
m_slotIndexMap.insert(TextureSlotTableEntry(GetTextureSlotKey(character, glyphSize), slot));
slot->m_glyphSize = glyphSize;
slot->m_slotUsage = slotUsage;
slot->m_currentCharacter = character;
int width = 0;
int height = 0;
// blit the char glyph into the texture
int x = slot->m_textureSlot % m_widthCellCount;
int y = slot->m_textureSlot / m_widthCellCount;
GlyphBitmap* glyphBitmap;
if (glyphSize.x > 0 && glyphSize.y > 0)
{
m_glyphCache.SetGlyphBitmapSize(glyphSize.x, glyphSize.y, sizeRatio);
}
if (!m_glyphCache.GetGlyph(&glyphBitmap, &slot->m_horizontalAdvance, &width, &height, slot->m_characterOffsetX, slot->m_characterOffsetY, character, glyphSize, fontHintParams))
{
return 0;
}
slot->m_characterWidth = width;
slot->m_characterHeight = height;
// Add a pixel along width and height to avoid artifacts being rendered
// from a previous glyph in this slot due to bilinear filtering. The source
// glyph bitmap buffer is presumed to be cleared prior to FreeType rendering
// to the bitmap.
const int blitWidth = AZ::GetMin<int>(width + 1, m_cellWidth);
const int blitHeight = AZ::GetMin<int>(height + 1, m_cellHeight);
glyphBitmap->BlitTo8(m_buffer, 0, 0,
blitWidth, blitHeight, x * m_cellWidth, y * m_cellHeight, m_width);
return 1;
}
//-------------------------------------------------------------------------------------------------
void AZ::FontTexture::CreateGradientSlot()
{
TextureSlot* slot = GetGradientSlot();
assert(slot->m_currentCharacter == (uint32_t)~0); // 0 needs to be unused spot
slot->Reset();
slot->m_characterWidth = m_cellWidth - 2;
slot->m_characterHeight = m_cellHeight - 2;
slot->SetNotReusable();
int x = slot->m_textureSlot % m_widthCellCount;
int y = slot->m_textureSlot / m_widthCellCount;
assert(sizeof(*m_buffer) == sizeof(uint8_t));
uint8_t* buffer = &m_buffer[x * m_cellWidth + y * m_cellHeight * m_width];
for (uint32_t dwY = 0; dwY < slot->m_characterHeight; ++dwY)
{
for (uint32_t dwX = 0; dwX < slot->m_characterWidth; ++dwX)
{
buffer[dwX + dwY * m_width] = dwY * 255 / (slot->m_characterHeight - 1);
}
}
}
//-------------------------------------------------------------------------------------------------
AZ::TextureSlot* AZ::FontTexture::GetGradientSlot()
{
return m_slotList[0];
}
//-------------------------------------------------------------------------------------------------
AZ::FontTexture::TextureSlotKey AZ::FontTexture::GetTextureSlotKey(uint32_t character, const AZ::AtomFont::GlyphSize& glyphSize) const
{
const AZ::AtomFont::GlyphSize clampedGlyphSize(ClampGlyphSize(glyphSize, m_cellWidth, m_cellHeight));
return AZ::FontTexture::TextureSlotKey(clampedGlyphSize, character);
}
AZ::AtomFont::GlyphSize AZ::FontTexture::ClampGlyphSize(const AZ::AtomFont::GlyphSize& glyphSize, int cellWidth, int cellHeight)
{
const AZ::AtomFont::GlyphSize maxCellDimensions(cellWidth, cellHeight);
AZ::AtomFont::GlyphSize clampedGlyphSize(glyphSize);
const bool hasZeroDimension = glyphSize.x == 0 || glyphSize.y == 0;
const bool isDefaultSize = glyphSize == AZ::AtomFont::defaultGlyphSize;
const bool exceedsDimensions = glyphSize.x > cellWidth || glyphSize.y > cellHeight;
const bool useMaxCellDimension = hasZeroDimension || isDefaultSize || exceedsDimensions;
if (useMaxCellDimension)
{
clampedGlyphSize = maxCellDimensions;
}
return clampedGlyphSize;
}
#endif // #if !defined(USE_NULLFONT_ALWAYS)
@@ -0,0 +1,242 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Purpose:
// - Hold a glyph bitmap and blit it to the main texture
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#include <AtomLyIntegration/AtomFont/GlyphBitmap.h>
#include <math.h>
//-------------------------------------------------------------------------------------------------
AZ::GlyphBitmap::GlyphBitmap()
: m_width(0)
, m_height(0)
, m_buffer(nullptr)
{
}
//-------------------------------------------------------------------------------------------------
AZ::GlyphBitmap::~GlyphBitmap()
{
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphBitmap::Create(int width, int height)
{
Release();
m_buffer = AZStd::unique_ptr<uint8_t[]>(new uint8_t[width * height]);
if (!m_buffer)
{
return 0;
}
m_width = width;
m_height = height;
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphBitmap::Release()
{
m_buffer = nullptr;
m_width = m_height = 0;
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphBitmap::Blur(AZ::FontSmoothAmount smoothAmount)
{
int iterationCount = 0;
switch(smoothAmount)
{
case AZ::FontSmoothAmount::x2:
iterationCount = 1;
break;
case AZ::FontSmoothAmount::x4:
iterationCount = 2;
break;
}
int colorSum;
int yOffset;
int yUpOffset;
int yDownOffset;
for (int i = 0; i < iterationCount; i++)
{
for (int y = 0; y < m_height; y++)
{
yOffset = y * m_width;
if (y - 1 >= 0)
{
yUpOffset = (y - 1) * m_width;
}
else
{
yUpOffset = (y) * m_width;
}
if (y + 1 < m_height)
{
yDownOffset = (y + 1) * m_width;
}
else
{
yDownOffset = (y) * m_width;
}
for (int x = 0; x < m_width; x++)
{
colorSum = m_buffer[yUpOffset + x] + m_buffer[yDownOffset + x];
if (x - 1 >= 0)
{
colorSum += m_buffer[yOffset + x - 1];
}
else
{
colorSum += m_buffer[yOffset + x];
}
if (x + 1 < m_width)
{
colorSum += m_buffer[yOffset + x + 1];
}
else
{
colorSum += m_buffer[yOffset + x];
}
m_buffer[yOffset + x] = colorSum >> 2;
}
}
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphBitmap::Clear()
{
memset(m_buffer.get(), 0, m_width * m_height);
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphBitmap::BlitTo8(unsigned char* destBuffer, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth)
{
int ySrcOffset;
int yDestOffset;
for (int y = 0; y < srcHeight; y++)
{
ySrcOffset = (srcY + y) * m_width;
yDestOffset = (destY + y) * destWidth;
for (int x = 0; x < srcWidth; x++)
{
destBuffer[yDestOffset + destX + x] = m_buffer[ySrcOffset + srcX + x];
}
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphBitmap::BlitScaledTo8(unsigned char* destBuffer, [[maybe_unused]] int srcReadXOffset, int srcReadYOffset, int srcWidth, int srcHeight, int destX, [[maybe_unused]] int destY, int destWidth, int destHeight, int destBufferWidth)
{
int newWidth = (int)destWidth;
int newHeight = (int)destHeight;
float destToSrcXScale = srcWidth / (float)newWidth;
float destToSrcYScale = srcHeight / (float)newHeight;
float srcReadX;
float srcReadY;
float srcReadXFraction;
float srcReadYFraction;
float oneMinusX;
float oneMinusY;
float fR0;
float fR1;
int srcReadXCeil;
int srcReadYCeil;
int srcReadXFloor;
int srcReadYFloor;
int destOffsetY;
uint8_t color0;
uint8_t color1;
uint8_t color2;
uint8_t color3;
for (int y = 0; y < newHeight; ++y)
{
srcReadY = y * destToSrcYScale;
srcReadYFloor = (int)floor_tpl(srcReadY);
srcReadYCeil = srcReadYFloor + 1;
srcReadYFraction = srcReadY - srcReadYFloor;
oneMinusY = 1.0f - srcReadYFraction;
destOffsetY = y * destBufferWidth;
srcReadYFloor += srcReadYOffset;
srcReadYCeil += srcReadYOffset;
if (srcReadYCeil >= m_height)
{
srcReadYCeil = srcReadYFloor;
}
for (int x = 0; x < newWidth; ++x)
{
srcReadX = x * destToSrcXScale;
srcReadXFloor = (int)floor_tpl(srcReadX);
srcReadXCeil = srcReadXFloor + 1;
srcReadXFraction = srcReadX - srcReadXFloor;
oneMinusX = 1.0f - srcReadXFraction;
// possible bug from Cry, using the y offset here
srcReadXFloor += srcReadYOffset;
srcReadXCeil += srcReadYOffset;
if (srcReadXCeil >= m_width)
{
srcReadXCeil = srcReadXFloor;
}
color0 = m_buffer[srcReadYFloor * m_width + srcReadXFloor];
color1 = m_buffer[srcReadYFloor * m_width + srcReadXCeil];
color2 = m_buffer[srcReadYCeil * m_width + srcReadXFloor];
color3 = m_buffer[srcReadYCeil * m_width + srcReadXCeil];
fR0 = (oneMinusX * color0 + srcReadXFraction * color1);
fR1 = (oneMinusX * color2 + srcReadXFraction * color3);
destBuffer[destOffsetY + x + destX] = (unsigned char)((oneMinusY * fR0) + (srcReadYFraction * fR1));
}
}
return 1;
}
//-------------------------------------------------------------------------------------------------
@@ -0,0 +1,433 @@
/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Purpose:
// - Manage and cache glyphs, retrieving them from the renderer as needed
#include <AtomLyIntegration/AtomFont/AtomFont_precompiled.h>
#if !defined(USE_NULLFONT_ALWAYS)
#include <AtomLyIntegration/AtomFont/GlyphCache.h>
#include <AtomLyIntegration/AtomFont/FontTexture.h>
//-------------------------------------------------------------------------------------------------
AZ::GlyphCache::GlyphCache()
: m_usage(1)
, m_glyphBitmapWidth(0)
, m_glyphBitmapHeight(0)
, m_scaleBitmap(0)
{
m_cacheTable.clear();
m_slotList.clear();
}
//-------------------------------------------------------------------------------------------------
AZ::GlyphCache::~GlyphCache()
{
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::Create(int iCacheSize, int glyphBitmapWidth, int glyphBitmapHeight, AZ::FontSmoothMethod smoothMethod, AZ::FontSmoothAmount smoothAmount, float sizeRatio)
{
m_smoothMethod = smoothMethod;
m_smoothAmount = smoothAmount;
m_glyphBitmapWidth = glyphBitmapWidth;
m_glyphBitmapHeight = glyphBitmapHeight;
if (!CreateSlotList(iCacheSize))
{
ReleaseSlotList();
return 0;
}
int iScaledGlyphWidth = 0;
int iScaledGlyphHeight = 0;
switch (m_smoothMethod)
{
case AZ::FontSmoothMethod::SuperSample:
{
switch (m_smoothAmount)
{
case AZ::FontSmoothAmount::x2:
iScaledGlyphWidth = m_glyphBitmapWidth << 1;
iScaledGlyphHeight = m_glyphBitmapHeight << 1;
break;
case AZ::FontSmoothAmount::x4:
iScaledGlyphWidth = m_glyphBitmapWidth << 2;
iScaledGlyphHeight = m_glyphBitmapHeight << 2;
break;
}
}
break;
}
if (iScaledGlyphWidth)
{
m_scaleBitmap = new GlyphBitmap;
if (!m_scaleBitmap)
{
Release();
return 0;
}
if (!m_scaleBitmap->Create(iScaledGlyphWidth, iScaledGlyphHeight))
{
Release();
return 0;
}
m_fontRenderer.SetGlyphBitmapSize(iScaledGlyphWidth, iScaledGlyphHeight, sizeRatio);
}
else
{
m_fontRenderer.SetGlyphBitmapSize(m_glyphBitmapWidth, m_glyphBitmapHeight, sizeRatio);
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::Release()
{
ReleaseSlotList();
m_cacheTable.clear();
if (m_scaleBitmap)
{
m_scaleBitmap->Release();
delete m_scaleBitmap;
m_scaleBitmap = 0;
}
m_glyphBitmapWidth = 0;
m_glyphBitmapHeight = 0;
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::LoadFontFromFile(const string& fileName)
{
return m_fontRenderer.LoadFromFile(fileName);
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::LoadFontFromMemory(unsigned char* fileBuffer, int dataSize)
{
return m_fontRenderer.LoadFromMemory(fileBuffer, dataSize);
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::ReleaseFont()
{
m_fontRenderer.Release();
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::GetGlyphBitmapSize(int* width, int* height)
{
if (width)
{
*width = m_glyphBitmapWidth;
}
if (height)
{
*height = m_glyphBitmapHeight;
}
return 1;
}
//-------------------------------------------------------------------------------------------------
void AZ::GlyphCache::SetGlyphBitmapSize(int width, int height, float sizeRatio)
{
m_fontRenderer.SetGlyphBitmapSize(width, height, sizeRatio);
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::PreCacheGlyph(uint32_t character, const AtomFont::GlyphSize& glyphSize, const FFont::FontHintParams& fontHintParams)
{
CacheTable::iterator pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
if (pItor != m_cacheTable.end())
{
pItor->second->m_usage = m_usage;
return 1;
}
CacheSlot* slot = GetLRUSlot();
if (!slot)
{
return 0;
}
if (slot->m_usage > 0)
{
UnCacheGlyph(slot->m_currentCharacter, slot->m_glyphSize);
}
if (m_scaleBitmap)
{
int iOffsetMult = 1;
switch (m_smoothAmount)
{
case AZ::FontSmoothAmount::x2:
iOffsetMult = 2;
break;
case AZ::FontSmoothAmount::x4:
iOffsetMult = 4;
break;
}
m_scaleBitmap->Clear();
if (!m_fontRenderer.GetGlyph(m_scaleBitmap, &slot->m_horizontalAdvance, &slot->m_characterWidth, &slot->m_characterHeight, slot->m_characterOffsetX, slot->m_characterOffsetY, 0, 0, character, fontHintParams))
{
return 0;
}
slot->m_characterWidth >>= iOffsetMult >> 1;
slot->m_characterHeight >>= iOffsetMult >> 1;
m_scaleBitmap->BlitScaledTo8(slot->m_glyphBitmap.GetBuffer(), 0, 0, m_scaleBitmap->GetWidth(), m_scaleBitmap->GetHeight(), 0, 0, slot->m_glyphBitmap.GetWidth(), slot->m_glyphBitmap.GetHeight(), slot->m_glyphBitmap.GetWidth());
}
else
{
if (!m_fontRenderer.GetGlyph(&slot->m_glyphBitmap, &slot->m_horizontalAdvance, &slot->m_characterWidth, &slot->m_characterHeight, slot->m_characterOffsetX, slot->m_characterOffsetY, 0, 0, character, fontHintParams))
{
return 0;
}
}
if (m_smoothMethod == AZ::FontSmoothMethod::Blur)
{
slot->m_glyphBitmap.Blur(m_smoothAmount);
}
slot->m_usage = m_usage;
slot->m_currentCharacter = character;
slot->m_glyphSize = glyphSize;
m_cacheTable.insert(AZStd::pair<CacheTableKey, CacheSlot*>(GetCacheSlotKey(character, glyphSize), slot));
return 1;
}
int AZ::GlyphCache::UnCacheGlyph(uint32_t character, const AtomFont::GlyphSize& glyphSize)
{
CacheTable::iterator pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
if (pItor != m_cacheTable.end())
{
CacheSlot* slot = pItor->second;
slot->Reset();
m_cacheTable.erase(pItor);
return 1;
}
return 0;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::GlyphCached(uint32_t character, const AtomFont::GlyphSize& glyphSize)
{
return (m_cacheTable.find(GetCacheSlotKey(character, glyphSize)) != m_cacheTable.end());
}
//-------------------------------------------------------------------------------------------------
AZ::CacheSlot* AZ::GlyphCache::GetLRUSlot()
{
unsigned int dwMinUsage = 0xffffffff;
CacheSlot* pLRUSlot = 0;
CacheSlot* slot;
CacheSlotListItor pItor = m_slotList.begin();
while (pItor != m_slotList.end())
{
slot = *pItor;
if (slot->m_usage == 0)
{
return slot;
}
else
{
if (slot->m_usage < dwMinUsage)
{
pLRUSlot = slot;
dwMinUsage = slot->m_usage;
}
}
pItor++;
}
return pLRUSlot;
}
//-------------------------------------------------------------------------------------------------
AZ::CacheSlot* AZ::GlyphCache::GetMRUSlot()
{
unsigned int dwMaxUsage = 0;
CacheSlot* pMRUSlot = 0;
CacheSlot* slot;
CacheSlotListItor pItor = m_slotList.begin();
while (pItor != m_slotList.end())
{
slot = *pItor;
if (slot->m_usage != 0)
{
if (slot->m_usage > dwMaxUsage)
{
pMRUSlot = slot;
dwMaxUsage = slot->m_usage;
}
}
pItor++;
}
return pMRUSlot;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::GetGlyph(AZ::GlyphBitmap** glyph, int* horizontalAdvance, int* width, int* height, int32_t& m_characterOffsetX, int32_t& m_characterOffsetY, uint32_t character, const AZ::AtomFont::GlyphSize& glyphSize, const AZ::FFont::FontHintParams& fontHintParams)
{
CacheTable::iterator pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
if (pItor == m_cacheTable.end())
{
if (!PreCacheGlyph(character, glyphSize, fontHintParams))
{
return 0;
}
}
pItor = m_cacheTable.find(GetCacheSlotKey(character, glyphSize));
pItor->second->m_usage = m_usage++;
(*glyph) = &pItor->second->m_glyphBitmap;
if (horizontalAdvance)
{
*horizontalAdvance = pItor->second->m_horizontalAdvance;
}
if (width)
{
*width = pItor->second->m_characterWidth;
}
if (height)
{
*height = pItor->second->m_characterHeight;
}
m_characterOffsetX = pItor->second->m_characterOffsetX;
m_characterOffsetY = pItor->second->m_characterOffsetY;
return 1;
}
//-------------------------------------------------------------------------------------------------
Vec2 AZ::GlyphCache::GetKerning(uint32_t leftGlyph, uint32_t rightGlyph)
{
return m_fontRenderer.GetKerning(leftGlyph, rightGlyph);
}
//-------------------------------------------------------------------------------------------------
float AZ::GlyphCache::GetAscenderToHeightRatio()
{
return m_fontRenderer.GetAscenderToHeightRatio();
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::CreateSlotList(int listSize)
{
for (int i = 0; i < listSize; i++)
{
CacheSlot* cacheSlot = new CacheSlot;
if (!cacheSlot)
{
return 0;
}
if (!cacheSlot->m_glyphBitmap.Create(m_glyphBitmapWidth, m_glyphBitmapHeight))
{
delete cacheSlot;
return 0;
}
cacheSlot->Reset();
cacheSlot->m_slotIndex = i;
m_slotList.push_back(cacheSlot);
}
return 1;
}
//-------------------------------------------------------------------------------------------------
int AZ::GlyphCache::ReleaseSlotList()
{
CacheSlotListItor pItor = m_slotList.begin();
while (pItor != m_slotList.end())
{
(*pItor)->m_glyphBitmap.Release();
delete (*pItor);
pItor = m_slotList.erase(pItor);
}
return 1;
}
//-------------------------------------------------------------------------------------------------
AZ::GlyphCache::CacheTableKey AZ::GlyphCache::GetCacheSlotKey(uint32_t character, const AZ::AtomFont::GlyphSize& glyphSize) const
{
const AZ::AtomFont::GlyphSize clampedGlyphSize = AZ::FontTexture::ClampGlyphSize(glyphSize, m_glyphBitmapWidth, m_glyphBitmapHeight);
return CacheTableKey(clampedGlyphSize, character);
}
#endif // #if !defined(USE_NULLFONT_ALWAYS)
@@ -0,0 +1,51 @@
/*
* 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 <AzCore/Memory/SystemAllocator.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Module/Module.h>
#include "AtomFontSystemComponent.h"
namespace AZ
{
namespace Render
{
class AtomFontModule
: public AZ::Module
{
public:
AZ_RTTI(AtomFontModule, "{E5EDF3B2-F85D-441B-8D0B-21D44D177799}", AZ::Module);
AZ_CLASS_ALLOCATOR(AtomFontModule, AZ::SystemAllocator, 0);
AtomFontModule()
: AZ::Module()
{
m_descriptors.insert(m_descriptors.end(), {
AtomFontSystemComponent::CreateDescriptor(),
});
}
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
return AZ::ComponentTypeList{
azrtti_typeid<AtomFontSystemComponent>(),
};
}
};
} // namespace Render
} // namespace AZ
// 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_AtomFont, AZ::Render::AtomFontModule)
@@ -0,0 +1,20 @@
/*
* 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 <AzTest/AzTest.h>
AZ_UNIT_TEST_HOOK(DEFAULT_UNIT_TEST_ENV);
TEST(AtomFontSanityTest, Sanity)
{
EXPECT_EQ(1, 1);
}
@@ -0,0 +1,37 @@
#
# 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.
#
set(FILES
Source/AtomFont.cpp
Source/AtomFontSystemComponent.cpp
Source/AtomFontSystemComponent.h
Source/FFont.cpp
Source/FFontXML_Internal.h
Source/FFontXML.cpp
Source/FontRenderer.cpp
Source/FontTexture.cpp
Source/GlyphBitmap.cpp
Source/GlyphCache.cpp
Source/AtomNullFont.cpp
Source/Module.cpp
Include/AtomLyIntegration/AtomFont/AtomFont.h
Include/AtomLyIntegration/AtomFont/FBitmap.h
Include/AtomLyIntegration/AtomFont/FFont.h
Include/AtomLyIntegration/AtomFont/FontRenderer.h
Include/AtomLyIntegration/AtomFont/FontCommon.h
Include/AtomLyIntegration/AtomFont/FontTexture.h
Include/AtomLyIntegration/AtomFont/GlyphBitmap.h
Include/AtomLyIntegration/AtomFont/GlyphCache.h
Include/AtomLyIntegration/AtomFont/AtomNullFont.h
Include/AtomLyIntegration/AtomFont/resource.h
Include/AtomLyIntegration/AtomFont/AtomFont_precompiled.h
Source/AtomFont_precompiled.cpp
)
@@ -0,0 +1,14 @@
#
# 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.
#
set(FILES
Source/Tests/test_Main.cpp
)
+18
View File
@@ -0,0 +1,18 @@
{
"Dependencies": [
],
"GemFormatVersion": 4,
"Uuid": "{16ef36f2e3fc4e6ca15fcc484ec895fc}",
"Name": "AtomLyIntegration_AtomFont",
"DisplayName": "AtomLyIntegration.AtomFont",
"Version": "0.1.0",
"LinkType": "Dynamic",
"Summary": "Implement ICryFont & IFFont interfaces on Atom. Uses duplicated CryFont code",
"Tags": [ "Atom", "Font" ],
"IconPath": "preview.png",
"Modules": [
{
"Type": "GameModule"
}
]
}
@@ -0,0 +1,12 @@
#
# 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.
#
add_subdirectory(Code)
@@ -0,0 +1,43 @@
#
# 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.
#
ly_add_target(
NAME AtomImGuiTools.Static STATIC
NAMESPACE Gem
FILES_CMAKE
atomimguitools_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PUBLIC
AZ::AzCore
Gem::ImguiAtom.Static
Gem::Atom_Utils.Static
)
ly_add_target(
NAME AtomImGuiTools ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
OUTPUT_NAME Gem.AtomImGuiTools.1a9d10de1b8a45fab2fe04517f613962.v0.1.0
FILES_CMAKE
atomimguitools_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PRIVATE
Gem::AtomImGuiTools.Static
)
@@ -0,0 +1,51 @@
/*
* 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 <AzCore/Memory/SystemAllocator.h>
#include <AzCore/Module/Module.h>
#include <AtomImGuiToolsSystemComponent.h>
namespace AtomImGuiTools
{
class AtomImGuiToolsModule
: public AZ::Module
{
public:
AZ_RTTI(AtomImGuiToolsModule, "{1B65F246-7977-4DC4-B5D9-BDAD374388FF}", AZ::Module);
AZ_CLASS_ALLOCATOR(AtomImGuiToolsModule, AZ::SystemAllocator, 0);
AtomImGuiToolsModule()
: AZ::Module()
{
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
AtomImGuiToolsSystemComponent::CreateDescriptor(),
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
return AZ::ComponentTypeList {
azrtti_typeid<AtomImGuiToolsSystemComponent>(),
};
}
};
}
// 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_AtomImGuiTools, AtomImGuiTools::AtomImGuiToolsModule)
@@ -0,0 +1,113 @@
/*
* 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 <AtomImGuiToolsSystemComponent.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <AzFramework/Components/ConsoleBus.h>
namespace AtomImGuiTools
{
void AtomImGuiToolsSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<AtomImGuiToolsSystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<AtomImGuiToolsSystemComponent>("AtomImGuiTools", "[Manager of various Atom ImGui tools.]")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
}
void AtomImGuiToolsSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AtomImGuiToolsService"));
}
void AtomImGuiToolsSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("AtomImGuiToolsService"));
}
void AtomImGuiToolsSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
AZ_UNUSED(required);
}
void AtomImGuiToolsSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
}
void AtomImGuiToolsSystemComponent::Activate()
{
#if defined(IMGUI_ENABLED)
ImGui::ImGuiUpdateListenerBus::Handler::BusConnect();
#endif
CrySystemEventBus::Handler::BusConnect();
}
void AtomImGuiToolsSystemComponent::Deactivate()
{
#if defined(IMGUI_ENABLED)
m_imguiPassTree.Reset();
ImGui::ImGuiUpdateListenerBus::Handler::BusDisconnect();
#endif
CrySystemEventBus::Handler::BusDisconnect();
}
#if defined(IMGUI_ENABLED)
void AtomImGuiToolsSystemComponent::OnImGuiUpdate()
{
if (m_showPassTree)
{
m_imguiPassTree.Draw(m_showPassTree, AZ::RPI::PassSystemInterface::Get()->GetRootPass().get());
}
if (m_showGpuProfiler)
{
m_imguiGpuProfiler.Draw(m_showGpuProfiler, AZ::RPI::PassSystemInterface::Get()->GetRootPass().get());
}
}
void AtomImGuiToolsSystemComponent::OnImGuiMainMenuUpdate()
{
if (ImGui::BeginMenu("Atom Tools"))
{
if (ImGui::MenuItem("Pass Viewer", "", &m_showPassTree))
{
}
if (ImGui::MenuItem("Gpu Profiler", "", &m_showGpuProfiler))
{
}
ImGui::EndMenu();
}
}
#endif
void AtomImGuiToolsSystemComponent::OnCryEditorInitialized()
{
AzFramework::ConsoleRequestBus::Broadcast(&AzFramework::ConsoleRequestBus::Events::ExecuteConsoleCommand, "imgui_DiscreteInputMode 1");
}
} // namespace AtomImGuiTools
@@ -0,0 +1,69 @@
/*
* 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/Component/Component.h>
#include <Atom/RPI.Public/Pass/Pass.h>
#include <CrySystemBus.h>
#if defined(IMGUI_ENABLED)
#include <ImGuiBus.h>
#include <imgui/imgui.h>
#include <Atom/Utils/ImGuiGpuProfiler.h>
#include <Atom/Utils/ImGuiPassTree.h>
#endif
namespace AtomImGuiTools
{
class AtomImGuiToolsSystemComponent
: public AZ::Component
#if defined(IMGUI_ENABLED)
, public ImGui::ImGuiUpdateListenerBus::Handler
#endif
, public CrySystemEventBus::Handler
{
public:
AZ_COMPONENT(AtomImGuiToolsSystemComponent, "{AFA2493D-DF1C-4DBB-BC13-0AF990B3D5FC}");
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);
// AZ::Component interface implementation
void Activate() override;
void Deactivate() override;
#if defined(IMGUI_ENABLED)
// ImGuiUpdateListenerBus overrides...
void OnImGuiUpdate() override;
void OnImGuiMainMenuUpdate() override;
#endif
// CrySystemEventBus overrides...
void OnCryEditorInitialized() override;
private:
#if defined(IMGUI_ENABLED)
AZ::Render::ImGuiPassTree m_imguiPassTree;
bool m_showPassTree = false;
AZ::Render::ImGuiGpuProfiler m_imguiGpuProfiler;
bool m_showGpuProfiler = false;
#endif
};
} // namespace AtomImGuiTools
@@ -0,0 +1,15 @@
#
# 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.
#
set(FILES
Source/AtomImGuiToolsSystemComponent.cpp
Source/AtomImGuiToolsSystemComponent.h
)
@@ -0,0 +1,14 @@
#
# 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.
#
set(FILES
Source/AtomImGuiToolsModule.cpp
)
@@ -0,0 +1,24 @@
{
"GemFormatVersion": 4,
"Uuid": "1a9d10de1b8a45fab2fe04517f613962",
"Name": "AtomImGuiTools",
"DisplayName": "Atom ImGui Tools",
"Version": "0.1.0",
"Summary": "ImGui tools for Atom renderer.",
"Tags": [ "Atom", "ImGui" ],
"IconPath": "preview.png",
"Modules": [
{
"Type": "GameModule"
}
],
"Dependencies": [
{
"Uuid": "9986e22e14184f2fb6bb1e7dd185b2f9",
"VersionConstraints": [
"~>0.1"
],
"_comment": "ImGui.Atom"
}
]
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6d6204c6730e5675791765ca194e9b1cbec282208e280507de830afc2805e5fa
size 41127
+19
View File
@@ -0,0 +1,19 @@
#
# 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.
#
add_subdirectory(CommonFeatures)
add_subdirectory(ImguiAtom)
add_subdirectory(AtomImGuiTools)
add_subdirectory(EMotionFXAtom)
add_subdirectory(AtomFont)
add_subdirectory(TechnicalArt)
add_subdirectory(CryRenderAtomShim)
add_subdirectory(AtomBridge)
@@ -0,0 +1,4 @@
[RC PostFxLayerCategories]
glob=*.postfxlayercategories
params=copy
productAssetType={A18B1B11-4C1E-4C1B-9643-178E8ED27019}
@@ -0,0 +1,130 @@
{
"configurations": [
{
"autoSelect": false,
"displayName": "Photo Studio 01",
"skyboxImageAsset": {
"assetId": {
"guid": "{B78C84E9-45BE-5A50-8898-177B33B8DA84}",
"subId": 1000
},
"assetHint": "envhdri/photo_studio_01_4k_iblskyboxcm.exr.streamingimage"
},
"iblSpecularImageAsset": {
"assetId": {
"guid": "{B78C84E9-45BE-5A50-8898-177B33B8DA84}",
"subId": 2000
},
"assetHint": "envhdri/photo_studio_01_4k_iblskyboxcm_iblspecular.exr.streamingimage"
},
"iblDiffuseImageAsset": {
"assetId": {
"guid": "{B78C84E9-45BE-5A50-8898-177B33B8DA84}",
"subId": 3000
},
"assetHint": "envhdri/photo_studio_01_4k_iblskyboxcm_ibldiffuse.exr.streamingimage"
},
"iblExposure": 0.0,
"skyboxExposure": 0.0,
"exposure": {
"compensateValue": 0.0,
"exposureControlType": 0,
"lightAdaptationSensitivity": 0.949999988079071,
"lightAdaptationScale": 0.8500000238418579,
"lightAdaptationSpeedLimit": 8.0,
"darkAdaptationSensitivity": 0.949999988079071,
"darkAdaptationScale": 0.8500000238418579,
"darkAdaptationSpeedLimit": 8.0,
"lightDarkExposureBorder": 0.0,
"autoExposureMin": -10.0,
"autoExposureMax": 10.0,
"eyeAdaptationDelayTime": 0.5
},
"lights": [
{
"direction": [
0.15000000596046449,
-0.15000000596046449,
-1.0
],
"color": [
1.0,
1.0,
1.0,
1.0
],
"intensity": 1.0,
"shadowCascadeCount": 4,
"shadowRatioLogarithmUniform": 1.0,
"shadowFarClipDistance": 20.0,
"shadowmapSize": "Size2048",
"enableShadowDebugColoring": false
}
],
"shadowCatcherOpacity": 0.25
},
{
"autoSelect": false,
"displayName": "Photo Studio 01 (Alt)",
"skyboxImageAsset": {
"assetId": {
"guid": "{B78C84E9-45BE-5A50-8898-177B33B8DA84}",
"subId": 3000
},
"assetHint": "envhdri/photo_studio_01_4k_iblskyboxcm_ibldiffuse.exr.streamingimage"
},
"iblSpecularImageAsset": {
"assetId": {
"guid": "{B78C84E9-45BE-5A50-8898-177B33B8DA84}",
"subId": 2000
},
"assetHint": "envhdri/photo_studio_01_4k_iblskyboxcm_iblspecular.exr.streamingimage"
},
"iblDiffuseImageAsset": {
"assetId": {
"guid": "{B78C84E9-45BE-5A50-8898-177B33B8DA84}",
"subId": 3000
},
"assetHint": "envhdri/photo_studio_01_4k_iblskyboxcm_ibldiffuse.exr.streamingimage"
},
"iblExposure": 0.0,
"skyboxExposure": 0.0,
"exposure": {
"compensateValue": 0.0,
"exposureControlType": 0,
"lightAdaptationSensitivity": 0.949999988079071,
"lightAdaptationScale": 0.8500000238418579,
"lightAdaptationSpeedLimit": 8.0,
"darkAdaptationSensitivity": 0.949999988079071,
"darkAdaptationScale": 0.8500000238418579,
"darkAdaptationSpeedLimit": 8.0,
"lightDarkExposureBorder": 0.0,
"autoExposureMin": -10.0,
"autoExposureMax": 10.0,
"eyeAdaptationDelayTime": 0.5
},
"lights": [
{
"direction": [
0.15000000596046449,
-0.15000000596046449,
-1.0
],
"color": [
1.0,
1.0,
1.0,
1.0
],
"intensity": 1.0,
"shadowCascadeCount": 4,
"shadowRatioLogarithmUniform": 1.0,
"shadowFarClipDistance": 20.0,
"shadowmapSize": "Size2048",
"enableShadowDebugColoring": false
}
],
"shadowCatcherOpacity": 0.15000000596046449
}
]
}
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:3791948b506c80c89ab9524f30a96514fb20d855d2391740707f48e1515effcd
size 50364729
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:b96d93f587d8d4d97912e7b84f147f830bc3437fa2ae1fcb5455e0401245d347
size 31264
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6fea35d103f199d8cf44f14bc08092ddce76ad1882569b9d068309bc40f73a43
size 5794788
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:95b46ba4980344b6121603f0f24bba91bafac99f6c907ead78dc2b0aeb969e57
size 2479648
@@ -0,0 +1,19 @@
<ObjectStream version="3">
<Class name="EditorPostFxLayerCategoriesAsset" type="{A18B1B11-4C1E-4C1B-9643-178E8ED27019}">
<Class name="AZStd::map" field="Layer Categories" type="{5B4970CC-26DE-51A3-83E7-1BC3A7E8E3C3}">
<Class name="AZStd::pair" field="element" type="{279D3EEE-F9CE-57FA-986E-D24E57211795}">
<Class name="AZStd::string" field="value1" value="Camera" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="int" field="value2" value="100" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{279D3EEE-F9CE-57FA-986E-D24E57211795}">
<Class name="AZStd::string" field="value1" value="Level" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="int" field="value2" value="1000" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
</Class>
<Class name="AZStd::pair" field="element" type="{279D3EEE-F9CE-57FA-986E-D24E57211795}">
<Class name="AZStd::string" field="value1" value="Volume" type="{03AAAB3F-5C47-5A66-9EBC-D5FA4DB353C9}"/>
<Class name="int" field="value2" value="10" type="{72039442-EB38-4D42-A1AD-CB68F7E0EEF6}"/>
</Class>
</Class>
</Class>
</ObjectStream>
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:513f47f6fea5105f603170a8881b7e3b1cd2c4258636d64a6399c725032b500d
size 38689
@@ -0,0 +1,12 @@
#
# 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.
#
add_subdirectory(Code)
@@ -0,0 +1,97 @@
#
# 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.
#
ly_get_list_relative_pal_filename(pal_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/${PAL_PLATFORM_NAME})
ly_get_list_relative_pal_filename(common_source_dir ${CMAKE_CURRENT_LIST_DIR}/Source/Platform/Common)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Public HEADERONLY
NAMESPACE Gem
FILES_CMAKE
atomlyintegration_commonfeatures_public_files.cmake
INCLUDE_DIRECTORIES
INTERFACE
Include
BUILD_DEPENDENCIES
INTERFACE
Gem::Atom_Feature_Common.Public
)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Static STATIC
NAMESPACE Gem
FILES_CMAKE
atomlyintegration_commonfeatures_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PUBLIC
AZ::AzCore
AZ::AzFramework
Gem::AtomLyIntegration_CommonFeatures.Public
Gem::LmbrCentral.Static
Gem::GradientSignal.Static
Gem::Atom_Feature_Common.Static
Gem::Atom_Bootstrap.Headers
)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures ${PAL_TRAIT_MONOLITHIC_DRIVEN_MODULE_TYPE}
NAMESPACE Gem
OUTPUT_NAME Gem.AtomLyIntegration_CommonFeatures.4e981f3b17394f5d84d674fff0f54f4f.v0.1.0
FILES_CMAKE
atomlyintegration_commonfeatures_shared_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PRIVATE
Gem::AtomLyIntegration_CommonFeatures.Static
)
if(PAL_TRAIT_BUILD_HOST_TOOLS)
ly_add_target(
NAME AtomLyIntegration_CommonFeatures.Editor MODULE
NAMESPACE Gem
OUTPUT_NAME Gem.AtomLyIntegration_CommonFeatures.Editor.4e981f3b17394f5d84d674fff0f54f4f.v0.1.0
AUTOUIC
AUTOMOC
AUTORCC
FILES_CMAKE
atomlyintegration_commonfeatures_editor_files.cmake
${pal_source_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
.
Source
PUBLIC
Include
COMPILE_DEFINITIONS
PRIVATE
ATOMLYINTEGRATION_FEATURE_COMMON_EDITOR
BUILD_DEPENDENCIES
PRIVATE
Gem::AtomLyIntegration_CommonFeatures.Static
Gem::Atom_RPI.Edit
Gem::AtomToolsFramework.Static
Gem::AtomToolsFramework.Editor
AZ::SceneCore
AZ::SceneData
Legacy::EditorLib
Legacy::CryCommon
)
endif()
@@ -0,0 +1,125 @@
/*
* 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/Component/ComponentBus.h>
#include <AzCore/Math/Color.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/AreaLightComponentConfig.h>
namespace AZ
{
namespace Render
{
class AreaLightRequests
: public ComponentBus
{
public:
AZ_RTTI(AZ::Render::AreaLightRequests, "{BC54532C-F3C8-4942-99FC-58D2E3D3DD54}");
//! Overrides the default AZ::EBusTraits handler policy to allow one listener only.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
virtual ~AreaLightRequests() {}
//! Gets an area light's color. This value is indepedent from its intensity.
virtual const Color& GetColor() const = 0;
//! Sets an area light's color. This value is indepedent from its intensity.
virtual void SetColor(const Color& color) = 0;
//! Gets an area light's intensity. This value is indepedent from its color.
virtual float GetIntensity() const = 0;
//! Gets whether an area light emits light in both directions from a 2D surface. Only applies to 2D shape types.
virtual bool GetLightEmitsBothDirections() const = 0;
//! Sets whether an area light emits light in both directions from a 2D surface. Only applies to 2D shape types.
virtual void SetLightEmitsBothDirections(bool value) = 0;
//! Gets whether the light is using the default high quality linearly transformed cosine lights (false) or a faster approximation (true).
virtual bool GetUseFastApproximation() const = 0;
//! Sets whether the light should use the default high quality linearly transformed cosine lights (false) or a faster approximation (true).
virtual void SetUseFastApproximation(bool useFastApproximation) = 0;
//! Gets an area light's photometric type.
virtual PhotometricUnit GetIntensityMode() const = 0;
//! Sets an area light's intensity and intensity mode. This value is indepedent from its color.
virtual void SetIntensity(float intensity, PhotometricUnit intensityMode) = 0;
//! Sets an area light's intensity. This value is indepedent from its color.
//! Assumes no change in the current photometric unit of the intensity.
virtual void SetIntensity(float intensity) = 0;
//! Gets the distance at which the area light will no longer affect lighting.
virtual float GetAttenuationRadius() const = 0;
//! Set the distance and which an area light will no longer affect lighitng. Setting this forces the RadiusCalculation to Explicit mode.
virtual void SetAttenuationRadius(float radius) = 0;
/*
* If this is set to Automatic, the radius will immediately be recalculated based on the intensity.
* If this is set to Explicit, the radius value will be unchanged from its previous value.
*/
virtual void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) = 0;
//! Sets the photometric unit to the one provided and converts the intensity to the photometric unit so actual light intensity remains constant.
virtual void ConvertToIntensityMode(PhotometricUnit intensityMode) = 0;
};
//! The EBus for requests to for setting and getting light component properties.
typedef AZ::EBus<AreaLightRequests> AreaLightRequestBus;
class AreaLightNotifications
: public ComponentBus
{
public:
AZ_RTTI(AZ::Render::AreaLightNotifications, "{7363728D-E3EE-4AC8-AAA7-C299782763F0}");
virtual ~AreaLightNotifications() {}
/**
* Signals that the color of the light changed.
* @param color A reference to the new color of the light.
*/
virtual void OnColorChanged(const Color& /*color*/) { }
/**
* Signals that the intensity of the light changed.
* @param intensity A reference to the new intensity of the light.
* @param intenstiyMode A reference to the intensity mode of the light (lux or lumens).
*/
virtual void OnIntensityChanged(float /*intensity*/, PhotometricUnit /*intenstiyMode*/) { }
/**
* Signals that the color or intensity of the light changed. This is useful when both the color and intensity are need in the same call.
* @param color A reference to the new color of the light.
* @param color A reference to the new intensity of the light.
*/
virtual void OnColorOrIntensityChanged(const Color& /*color*/, float /*intensity*/) { }
/**
* Signals that the attenuation radius of the light changed.
* @param attenuationRadius The distance at which this light no longer affects lighting.
*/
virtual void OnAttenutationRadiusChanged(float /*attenuationRadius*/) { }
};
//! The EBus for light notification events.
typedef AZ::EBus<AreaLightNotifications> AreaLightNotificationBus;
} // namespace Render
} // namespace AZ
@@ -0,0 +1,70 @@
/*
* 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/Component/Component.h>
#include <AzCore/Math/Color.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
#include <AzCore/Serialization/EditContext.h>
namespace AZ
{
namespace Render
{
struct AreaLightComponentConfig final
: public ComponentConfig
{
AZ_RTTI(AZ::Render::AreaLightComponentConfig, "{11C08FED-7F94-4926-8517-46D08E4DD837}", ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
static constexpr float CutoffIntensity = 0.1f;
AZ::Color m_color = AZ::Color::CreateOne();
float m_intensity = 100.0f;
float m_attenuationRadius = 0.0f;
PhotometricUnit m_intensityMode = PhotometricUnit::Lumen;
LightAttenuationRadiusMode m_attenuationRadiusMode = LightAttenuationRadiusMode::Automatic;
bool m_lightEmitsBothDirections = false;
bool m_useFastApproximation = false;
AZ::Crc32 m_shapeType;
// The following functions provide information to an EditContext...
//! Returns true if m_attenuationRadiusMode is set to LightAttenuationRadiusMode::Automatic
bool IsAttenuationRadiusModeAutomatic() const;
//! Returns true if the shape type is a 2D surface
bool Is2DSurface() const;
//! Returns true if the light type supports a faster and less accurate approximation for the lighting algorithm.
bool SupportsFastApproximation() const;
//! Returns characters for a suffix for the light type including a space. " lm" for lumens for example.
const char* GetIntensitySuffix() const;
//! Returns the minimum intensity value allowed depending on the m_intensityMode
float GetIntensityMin() const;
//! Returns the maximum intensity value allowed depending on the m_intensityMode
float GetIntensityMax() const;
//! Returns the minimum intensity value for UI depending on the m_intensityMode, but users may still type in a lesser value depending on GetIntensityMin().
float GetIntensitySoftMin() const;
//! Returns the maximum intensity value for UI depending on the m_intensityMode, but users may still type in a greater value depending on GetIntensityMin().
float GetIntensitySoftMax() const;
};
}
}
@@ -0,0 +1,50 @@
/*
* 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/MathUtils.h>
#include <AzCore/RTTI/BehaviorContext.h>
#include <Atom/Feature/CoreLights/CoreLightsConstants.h>
namespace AZ
{
namespace Render
{
static constexpr const char* const AreaLightComponentTypeId = "{744B3961-6242-4461-983F-2817D9D29C30}";
static constexpr const char* const EditorAreaLightComponentTypeId = "{8B605C0C-9027-4E0B-BA8C-19E396F8F262}";
static constexpr const char* const PointLightComponentTypeId = "{0A0E44AB-F583-481F-8AE8-68C4B1F9CD05}";
static constexpr const char* const EditorPointLightComponentTypeId = "{C4D354BE-5247-41FD-9A8D-550C6772EE5B}";
static constexpr const char* const SpotLightComponentTypeId = "{441DF0EC-6B70-451E-AEBE-6452A17BB852}";
static constexpr const char* const EditorSpotLightComponentTypeId = "{9A32D37B-C5D2-43A7-B574-E2EA1CDC7D64}";
static constexpr const char* const DirectionalLightComponentTypeId = "{13054592-2753-46C2-B19E-59670D4CE03D}";
static constexpr const char* const EditorDirectionalLightComponentTypeId = "{45B97527-6E72-411B-BC23-00068CF01580}";
enum class LightAttenuationRadiusMode : uint8_t
{
Explicit,
Automatic,
};
inline void CoreLightConstantsReflect(ReflectContext* context)
{
if (auto behaviorContext = azrtti_cast<BehaviorContext*>(context))
{
behaviorContext
->Enum<(int)LightAttenuationRadiusMode::Automatic>("LightAttenuationRadiusMode_Automatic")
->Enum<(int)LightAttenuationRadiusMode::Explicit>("LightAttenuationRadiusMode_Explicit")
;
}
}
} // namespace Render
} // namespace AZ
@@ -0,0 +1,189 @@
/*
* 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/Component/ComponentBus.h>
#include <AzCore/Component/EntityId.h>
#include <AzCore/Math/Color.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <Atom/Feature/CoreLights/ShadowConstants.h>
namespace AZ
{
namespace Render
{
class DirectionalLightRequests
: public ComponentBus
{
public:
//! Gets a directional light's color. This value is independent from its intensity.
//! @return directional light's color
virtual const Color& GetColor() const = 0;
//! Sets a directional light's color. This value is independent from its intensity.
//! @param color directional light's color
virtual void SetColor(const Color& color) = 0;
//! Gets a directional light's intensity. This value is independent from its color.
//! @return directional light's intensity
virtual float GetIntensity() const = 0;
//! Sets a directional light's intensity. This value is independent from its color.
//! @param intensity directional light's intensity
//! @param type The photometric unit of the intensity.
virtual void SetIntensity(float intensity, PhotometricUnit unit) = 0;
//! Sets a directional light's intensity. This value is independent from its color.
//! Assumes no change in the current photometric unit of the intensity.
//! @param intensity directional light's intensity
virtual void SetIntensity(float intensity) = 0;
//! Gets a directional light's angular diameter.
//! @return directional light's angular diameter in degrees.
virtual float GetAngularDiameter() const = 0;
//! Sets a directional light's angular diameter. This value should be small, for instance the sun is 0.5 degrees across.
//! @param angularDiameter Directional light's angular diameter in degrees.
virtual void SetAngularDiameter(float angularDiameter) = 0;
//! This gets shadowmap size (width/height).
//! @return shadowmap size.
virtual ShadowmapSize GetShadowmapSize() const = 0;
//! This specifies the size of shadowmaps (for each cascade) to size x size.
virtual void SetShadowmapSize(ShadowmapSize size) = 0;
//! This gets cascade count of the shadowmap.
//! @return cascade count
virtual uint32_t GetCascadeCount() const = 0;
//! This sets cascade count of the shadowmap
//! @param cascadeCount cascade count
virtual void SetCascadeCount(uint32_t cascadeCount) = 0;
//! This gets ratio between logarithm/uniform scheme to split view frustum.
//! @return the ratio (in [0,1]) between uniform scheme and logarithm scheme for splitting the view frustum into cascades.
//! ratio==0 means uniform and ratio==1 means logarithm.
//! uniform: the most detailed cascade covers wider area but less detailed.
//! logarithm: the most detailed cascade covers narrower area but more detailed.
//! The least detailed cascade is not affected by this parameter.
virtual float GetShadowmapFrustumSplitSchemeRatio() const = 0;
//! This sets ratio between logarithm/uniform scheme to split view frustum.
//! If this is called, frustum splitting becomes automatic
//! and the far depths given by SetCascadeFarDepth() is discarded.
//! @param ratio the ratio (in [0,1])
virtual void SetShadowmapFrustumSplitSchemeRatio(float ratio) = 0;
//! This gets the far depth of the cascade.
//! @return the far depth for each cascade.
virtual const Vector4& GetCascadeFarDepth() = 0;
//! This sets the far depth of the cascade.
//! If this is called, the ratio of frustum split scheme will be ignored.
//! @param farDepth the far depth to be set.
virtual void SetCascadeFarDepth(const Vector4& farDepth) = 0;
//! This gets the flag split of shadowmap frustum is automatic.
//! @return it is automatic if true, and it is manual if false.
virtual bool GetShadowmapFrustumSplitAutomatic() const = 0;
//! This sets the flag split of shadowmap frustum is automatic.
//! @param isAutomatic the flag to be set.
virtual void SetShadowmapFrustumSplitAutomatic(bool isAutomatic) = 0;
//! This gets the entity ID of the camera used for specifying view frustum to create shadowmaps.
//! @return camera entity ID.
virtual EntityId GetCameraEntityId() const = 0;
//! This sets the entity ID of the camera used for specifying view frustum to create shadowmaps.
//! @param entityId camera entity ID.
virtual void SetCameraEntityId(EntityId entityId) = 0;
//! This gets shadow specific far clip distance.
//! Pixels further than this value won't have shadows
//! Smaller values result in higher quality shadows
//! @return far clip distance
virtual float GetShadowFarClipDistance() const = 0;
//! This sets shadow specific far clip distance.
//! @param farDist the far clip distance for each cascade.
virtual void SetShadowFarClipDistance(float farDist) = 0;
//! This gets the height of the ground.
//! The position of view frustum is corrected using ground height
//! to get better quality of shadow around the area close to the camera.
//! To enable the correction, SetViewFrustumCorrectionEnabled(true) is required.
//! @return ground height
virtual float GetGroundHeight() const = 0;
//! This specifies the height of the ground.
//! @param groundHeight height of the ground
virtual void SetGroundHeight(float groundHeight) = 0;
//! This gets the flag whether view frustum correction is enabled not not.
//! The calculation of it is caused when position or configuration of the camera is changed.
//! @return flag of view frustum correction is enbled or not
virtual bool GetViewFrustumCorrectionEnabled() const = 0;
//! This specifies whether view frustum correction is enabled or not.
//! @param enabled flag specifying whether view frustum positions are corrected.
virtual void SetViewFrustumCorrectionEnabled(bool enabled) = 0;
//! This gets the flag whether debug coloring is enabled or not.
//! By debug coloring, we can see how cascading of shadowmaps works.
//! @return the flag whether debug coloring is enabled or not.
virtual bool GetDebugColoringEnabled() const = 0;
//! This specifies whether debug coloring is enabled or not.
//! @param enabled flag specifying whether debug coloring is added.
virtual void SetDebugColoringEnabled(bool enabled) = 0;
//! This gets the filter method of shadows.
//! @return filter method
virtual ShadowFilterMethod GetShadowFilterMethod() const = 0;
//! This specifies filter method of shadows.
//! @param method filter method.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! This gets the width of boundary between shadowed area and lit area.
//! @return Boundary width. The shadow is gradually changed the degree of shadowed.
virtual float GetSofteningBoundaryWidth() const = 0;
//! This specifies the width of boundary between shadowed area and lit area.
//! @param width Boundary width. The shadow is gradually changed the degree of shadowed.
//! If width == 0, softening edge is disabled. Units are in meters.
virtual void SetSofteningBoundaryWidth(float width) = 0;
//! This gets sample count to predict boundary of shadow.
//! @return Sample Count for prediction of whether the pixel is on the boundary (up to 16)
virtual uint32_t GetPredictionSampleCount() const = 0;
//! This sets sample count to predict boundary of shadow.
//! @param count Sample Count for prediction of whether the pixel is on the boundary (up to 16)
//! The value should be less than or equal to m_filteringSampleCount.
virtual void SetPredictionSampleCount(uint32_t count) = 0;
//! This gets the sample count for filtering of the shadow boundary.
//! @return Sample Count for filtering (up to 64)
virtual uint32_t GetFilteringSampleCount() const = 0;
//! This sets the sample count for filtering of the shadow boundary.
//! @param count Sample Count for filtering (up to 64)
virtual void SetFilteringSampleCount(uint32_t count) = 0;
};
using DirectionalLightRequestBus = EBus<DirectionalLightRequests>;
} // namespace Render
} // namespace AZ
@@ -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.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzCore/Math/Color.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
namespace AZ
{
namespace Render
{
struct DirectionalLightComponentConfig final
: public ComponentConfig
{
AZ_RTTI(DirectionalLightConfiguration, "EB01B835-F9FE-4FF0-BDC4-455462BFE769", ComponentConfig);
static void Reflect(ReflectContext* context);
// The following functions provide information to an EditContext...
//! Returns characters for a suffix for the light type including a space. " lm" for lumens for example.
const char* GetIntensitySuffix() const;
//! Returns the minimum intensity value allowed depending on the m_intensityMode
float GetIntensityMin() const;
//! Returns the maximum intensity value allowed depending on the m_intensityMode
float GetIntensityMax() const;
//! Returns the minimum intensity value for UI depending on the m_intensityMode, but users may still type in a lesser value depending on GetIntensityMin().
float GetIntensitySoftMin() const;
//! Returns the maximum intensity value for UI depending on the m_intensityMode, but users may still type in a greater value depending on GetIntensityMin().
float GetIntensitySoftMax() const;
AZ::Color m_color = AZ::Color::CreateOne();
//! Lux or Ev100
PhotometricUnit m_intensityMode = PhotometricUnit::Ev100Illuminance;
//! Intensity in lux or Ev100 (depending on m_intensityMode)
float m_intensity = 4.0f;
//! Angular diameter of light in degrees, should be small. The sun is about 0.5.
float m_angularDiameter = 0.5f;
//! EntityId of the camera specifying view frustum to create shadowmaps.
EntityId m_cameraEntityId{ EntityId::InvalidEntityId };
//! Far depth clips for shadows.
float m_shadowFarClipDistance = 100.f;
//! Width/Height of shadowmap images.
ShadowmapSize m_shadowmapSize = MaxShadowmapImageSize;
//! Number of cascades.
uint32_t m_cascadeCount = 4;
//! Flag to switch splitting of shadowmap frustum to cascades automatically or not.
//! If true, m_shadowmapFrustumSplitSchemeRatio is used.
//! If false, m_cascadeFarDepths is used.
bool m_isShadowmapFrustumSplitAutomatic = true;
//! Ratio to lerp between the two types of frustum splitting scheme.
//! 0 = Uniform scheme which will split the Frustum evenly across all cascades.
//! 1 = Logarithmic scheme which is designed to split the frustum in a logarithmic fashion
//! in order to enable us to produce a more optimal perspective aliasing across the frustum.
//! This is valid only when m_shadowmapFrustumSplitIsAutomatic = true.
float m_shadowmapFrustumSplitSchemeRatio = 0.9f;
//! Far depth for each cascade.
//! Note that near depth of a cascade equals the far depth of the previous cascade.
//! This is valid only when m_shadowmapFrustumSplitIsAutomatic = false.
AZ::Vector4 m_cascadeFarDepths
{
m_shadowFarClipDistance * 1 / Shadow::MaxNumberOfCascades,
m_shadowFarClipDistance * 2 / Shadow::MaxNumberOfCascades,
m_shadowFarClipDistance * 3 / Shadow::MaxNumberOfCascades,
m_shadowFarClipDistance * 4 / Shadow::MaxNumberOfCascades
};
//! Height of camera from the ground.
//! The position of view frustum is corrected using cameraHeight
//! to get better quality of shadow around the area close to the camera.
//! To enable the correction, m_isCascadeCorrectionEnabled=true is required.
float m_groundHeight = 0.f;
//! Flag specifying whether view frustum positions are corrected.
//! The calculation of it is caused when the position of configuration of the camera is changed.
bool m_isCascadeCorrectionEnabled = false;
//! Flag specifying whether debug coloring is added.
bool m_isDebugColoringEnabled = false;
//! Method of shadow's filtering.
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
//! Width of the boundary between shadowed area and lit one.
//! If this is 0, edge softening is disabled. Units are in meters.
float m_boundaryWidth = 0.03f; // 3cm
//! Sample Count for prediction of whether the pixel is on the boundary (from 4 to 16)
//! The value should be less than or equal to m_filteringSampleCount.
uint16_t m_predictionSampleCount = 4;
//! Sample Count for filtering (from 4 to 64)
//! It is used only when the pixel is predicted as on the boundary.
uint16_t m_filteringSampleCount = 32;
bool IsSplitManual() const;
bool IsSplitAutomatic() const;
bool IsCascadeCorrectionDisabled() const;
bool IsShadowFilteringDisabled() const;
bool IsShadowPcfDisabled() const;
};
} // namespace Render
} // namespace AZ
@@ -0,0 +1,130 @@
/*
* 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 <AzCore/Component/ComponentBus.h>
#include <AzCore/Math/Color.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/PointLightComponentConfig.h>
namespace AZ
{
namespace Render
{
class PointLightRequests
: public ComponentBus
{
public:
AZ_RTTI(PointLightRequests, "{359BE514-DBEB-4D6A-B283-F8C5E83CD477}");
/// Overrides the default AZ::EBusTraits handler policy to allow one listener only.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
virtual ~PointLightRequests() {}
/// Gets a point light's color. This value is indepedent from its intensity.
virtual const Color& GetColor() const = 0;
/// Sets a point light's color. This value is indepedent from its intensity.
virtual void SetColor(const Color& color) = 0;
/// Gets a point light's intensity. This value is indepedent from its color.
virtual float GetIntensity() const = 0;
//! Gets a point light's photometric type.
virtual PhotometricUnit GetIntensityMode() const = 0;
/// Sets a point light's intensity. This value is indepedent from its color.
virtual void SetIntensity(float intensity) = 0;
//! Sets a point light's intensity and intensity mode. This value is indepedent from its color.
virtual void SetIntensity(float intensity, PhotometricUnit intensityMode) = 0;
/// Gets the distance at which the point light will no longer affect lighting.
virtual float GetAttenuationRadius() const = 0;
/// Set the distance and which a point light will no longer affect lighitng. Setting this forces the RadiusCalculation to Explicit mode.
virtual void SetAttenuationRadius(float radius) = 0;
/// Gets the size in meters of the sphere representing the light bulb.
virtual float GetBulbRadius() const = 0;
/// Sets the size in meters of the sphere representing the light bulb in meters.
virtual void SetBulbRadius(float bulbSize) = 0;
/*
* If this is set to Automatic, the radius will immediately be recalculated based on the intensity.
* If this is set to Explicit, the radius value will be unchanged from its previous value.
*/
virtual void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) = 0;
/// Gets the flag whether attenuation radius calculation is automatic or not.
virtual bool GetAttenuationRadiusIsAutomatic() const = 0;
/// Sets the flag whether attenuation radius calculation is automatic or not.
virtual void SetAttenuationRadiusIsAutomatic(bool flag)
{
SetAttenuationRadiusMode(flag ? LightAttenuationRadiusMode::Automatic : LightAttenuationRadiusMode::Explicit);
}
//! Sets the photometric unit to the one provided and converts the intensity to the photometric unit so actual light intensity remains constant.
virtual void ConvertToIntensityMode(PhotometricUnit intensityMode) = 0;
};
/// The EBus for requests to for setting and getting light component properties.
typedef AZ::EBus<PointLightRequests> PointLightRequestBus;
class PointLightNotifications
: public ComponentBus
{
public:
AZ_RTTI(PointLightNotifications, "{7363728D-E3EE-4AC8-AAA7-C299782763F0}");
virtual ~PointLightNotifications() {}
/**
* Signals that the color of the light changed.
* @param color A reference to the new color of the light.
*/
virtual void OnColorChanged(const Color& /*color*/) { }
/**
* Signals that the intensity of the light changed.
* @param color A reference to the new intensity of the light.
*/
virtual void OnIntensityChanged(float /*intensity*/) { }
/**
* Signals that the color or intensity of the light changed. This is useful when both the color and intensity are need in the same call.
* @param color A reference to the new color of the light.
* @param color A reference to the new intensity of the light.
*/
virtual void OnColorOrIntensityChanged(const Color& /*color*/, float /*intensity*/) { }
/**
* Signals that the attenuation radius of the light changed.
* @param attenuationRadius The distance at which this light no longer affects lighting.
*/
virtual void OnAttenutationRadiusChanged(float /*attenuationRadius*/) { }
/**
* Signals that the bulb size of the light changed.
* @param bulbRadius The size in meters of the sphere representing the light bulb in meters.
*/
virtual void OnBulbRadiusChanged(float /*bulbRadius*/) { }
};
/// The EBus for light notification events.
typedef AZ::EBus<PointLightNotifications> PointLightNotificationBus;
} // namespace Render
} // namespace AZ
@@ -0,0 +1,113 @@
/*
* 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/Component/Component.h>
#include <AzCore/Math/Color.h>
#include <AzCore/Math/MathUtils.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
namespace AZ
{
namespace Render
{
struct PointLightComponentConfig final
: public ComponentConfig
{
AZ_RTTI(PointLightComponentConfig, "{B6FC35BA-D22F-4C20-BFFC-3FE7A48858FA}", ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
static constexpr float DefaultIntensity = 800.0f; // 800 lumes is roughly equivalent to a 60 watt incandescent bulb
static constexpr float DefaultBulbRadius = 0.05f; // 5cm
AZ::Color m_color = AZ::Color::CreateOne();
PhotometricUnit m_intensityMode = PhotometricUnit::Lumen;
float m_intensity = DefaultIntensity;
float m_attenuationRadius = 0.0f;
float m_bulbRadius = DefaultBulbRadius;
LightAttenuationRadiusMode m_attenuationRadiusMode = LightAttenuationRadiusMode::Automatic;
// Not serialized, but used to keep scaled and unscaled properties in sync.
float m_scale = 1.0f;
// These values are used to deal adjusting the brightness and bulb radius based on the transform component's scale
// so that point lights scale concistently with meshes. Not serialized.
float m_unscaledIntensity = DefaultIntensity;
float m_unscaledBulbRadius = DefaultBulbRadius;
//! Updates scale and adjusts the values of intensity and bulb radius based on the new scale and the unscaled values.
void UpdateScale(float newScale)
{
m_scale = newScale;
m_intensity = m_unscaledIntensity;
// Lumens & Candela aren't based on surface area, so scale them.
if (!IsAreaBasedIntensityMode())
{
// Light surface area and brightness increases at scale^2 because of equation of sphere surface area.
m_intensity *= m_scale * m_scale;
}
m_bulbRadius = m_unscaledBulbRadius * m_scale;
}
//! Updates the unscaled intensity based on the current scaled value.
void UpdateUnscaledIntensity()
{
m_unscaledIntensity = m_intensity;
// Lumens & Candela aren't based on surface area, so scale them.
if (!IsAreaBasedIntensityMode())
{
// Light surface area and brightness increases at scale^2 because of equation of sphere surface area.
m_unscaledIntensity /= m_scale * m_scale;
}
}
//! Updates the unscaled bulb radius based on the current scaled value.
void UpdateUnscaledBulbRadius()
{
m_unscaledBulbRadius = m_bulbRadius / m_scale;
}
// Returns true if the intensity mode is an area based light unit (not lumens or candela)
bool IsAreaBasedIntensityMode()
{
return m_intensityMode != PhotometricUnit::Lumen && m_intensityMode != PhotometricUnit::Candela;
}
// Returns the surface area of the light bulb. 4.0 * pi * m_bulbRadius^2
float GetArea()
{
return 4.0f * Constants::Pi * m_bulbRadius * m_bulbRadius;
}
// The following functions provide information to an EditContext...
//! Returns true if m_attenuationRadiusMode is set to LightAttenuationRadiusMode::Automatic
bool IsAttenuationRadiusModeAutomatic() const
{
return m_attenuationRadiusMode == LightAttenuationRadiusMode::Automatic;
}
//! Returns characters for a suffix for the light type including a space. " lm" for lumens for example.
const char* GetIntensitySuffix() const
{
return PhotometricValue::GetTypeSuffix(m_intensityMode);
}
};
}
}
@@ -0,0 +1,165 @@
/*
* 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/Component/ComponentBus.h>
#include <AzCore/Math/Color.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/SpotLightComponentConfig.h>
#include <Atom/Feature/CoreLights/ShadowConstants.h>
namespace AZ
{
namespace Render
{
class SpotLightRequests
: public ComponentBus
{
public:
//! Overrides the default AZ::EBusTraits handler policy to allow one listener only.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
virtual ~SpotLightRequests() = default;
//! Gets a spot light's color. This value is independent from its intensity.
virtual const Color& GetColor() const = 0;
//! Sets a spot light's color. This value is independent from its intensity.
virtual void SetColor(const Color& color) = 0;
//! Gets a spot light's intensity. This value is independent from its color.
virtual float GetIntensity() const = 0;
//! Sets a spot light's intensity. This value is independent from its color.
virtual void SetIntensity(float intensity) = 0;
//! Gets a spot light's bulb radius in meters.
virtual float GetBulbRadius() const = 0;
//! Sets a spot light's bulb radius in meters.
virtual void SetBulbRadius(float bulbRadius) = 0;
//! @return Returns inner cone angle of the spot light in degrees.
virtual float GetInnerConeAngleInDegrees() const = 0;
//! @brief Sets inner cone angle of the spot light in degrees.
virtual void SetInnerConeAngleInDegrees(float degrees) = 0;
//! @return Returns outer cone angle of the spot light in degrees.
virtual float GetOuterConeAngleInDegrees() const = 0;
//! @brief Sets outer cone angle of the spot light in degrees.
virtual void SetOuterConeAngleInDegrees(float degrees) = 0;
//! @return Returns penumbra bias for the falloff curve of the spot light.
virtual float GetPenumbraBias() const = 0;
//! @brief Sets penumbra bias for the falloff curve of the spot light.
virtual void SetPenumbraBias(float penumbraBias) = 0;
//! @return Returns radius attenuation of the spot light.
virtual float GetAttenuationRadius() const = 0;
//! @return Sets radius attenuation of the spot light.
virtual void SetAttenuationRadius(float radius) = 0;
//! @return Returns radius attenuation mode (Auto or Explicit).
virtual LightAttenuationRadiusMode GetAttenuationRadiusMode() const = 0;
//! If this is set to Automatic, the radius will immediately be recalculated based on the intensity.
//! If this is set to Explicit, the radius value will be unchanged from its previous value.
virtual void SetAttenuationRadiusMode(LightAttenuationRadiusMode attenuationRadiusMode) = 0;
//! @return the flag whether attenuation radius calculation is automatic or not.
virtual bool GetAttenuationRadiusIsAutomatic() const
{
return (GetAttenuationRadiusMode() == LightAttenuationRadiusMode::Automatic);
}
//! This sets flag whether attenuation radius calculation is automatic or not.
//! @param flag flag whether attenuation radius calculation is automatic or not.
virtual void SetAttenuationRadiusIsAutomatic(bool flag)
{
SetAttenuationRadiusMode(flag ? LightAttenuationRadiusMode::Automatic : LightAttenuationRadiusMode::Explicit);
}
//! @return the flag indicates this light have shadow or not.
virtual bool GetEnableShadow() const = 0;
//! This specify this spot light uses shadow or not.
//! @param enabled true if shadow is used, false otherwise.
virtual void SetEnableShadow(bool enabled) = 0;
//! @return the size of shadowmap (width and height).
virtual ShadowmapSize GetShadowmapSize() const = 0;
//! This specifies the size of shadowmap to size x size.
virtual void SetShadowmapSize(ShadowmapSize size) = 0;
//! This gets the filter method of shadows.
//! @return filter method
virtual ShadowFilterMethod GetShadowFilterMethod() const = 0;
//! This specifies filter method of shadows.
//! @param method Filter method.
virtual void SetShadowFilterMethod(ShadowFilterMethod method) = 0;
//! This gets the width of boundary between shadowed area and lit area.
//! The width is given by the angle, and the units are in degrees.
//! @return Boundary width. The degree of the shadowed region is gradually changed on the boundary.
virtual float GetSofteningBoundaryWidthAngle() const = 0;
//! This specifies the width of boundary between shadowed area and lit area.
//! @param width Boundary width. The degree of shadowed is gradually changed on the boundary.
//! If width == 0, softening edge is disabled. Units are in degrees.
virtual void SetSofteningBoundaryWidthAngle(float degrees) = 0;
//! This gets the sample count to predict boundary of shadow.
//! @return Sample Count for prediction of whether the pixel is on the boundary (up to 16)
virtual uint32_t GetPredictionSampleCount() const = 0;
//! This sets the sample count to predict boundary of shadow.
//! @param count Sample count for prediction of whether the pixel is on the boundary (up to 16)
//! This value should be less than or equal to m_filteringSampleCount.
virtual void SetPredictionSampleCount(uint32_t count) = 0;
//! This gets the sample count for filtering of the shadow boundary.
//! @return Sample Count for filtering (up to 64)
virtual uint32_t GetFilteringSampleCount() const = 0;
//! This sets the sample count for filtering of the shadow boundary.
//! @param count Sample Count for filtering (up to 64)
virtual void SetFilteringSampleCount(uint32_t count) = 0;
};
/// The EBus for requests to for setting and getting spot light component properties.
typedef AZ::EBus<SpotLightRequests> SpotLightRequestBus;
class SpotLightNotifications
: public ComponentBus
{
public:
virtual ~SpotLightNotifications() = default;
//! @brief Signals that the intensity of the light changed.
virtual void OnIntensityChanged(float intensity) { AZ_UNUSED(intensity); }
//! @brief Signals that the color of the light changed.
virtual void OnColorChanged(const Color& color) { AZ_UNUSED(color); }
//! @brief Signals that the cone angles of the spot light have changed.
virtual void OnConeAnglesChanged(float innerConeAngleDegrees, float outerConeAngleDegrees) { AZ_UNUSED(innerConeAngleDegrees); AZ_UNUSED(outerConeAngleDegrees); }
//! @brief Signals that the attenuation radius has changed.
virtual void OnAttenuationRadiusChanged(float attenuationRadius) { AZ_UNUSED(attenuationRadius); }
//! @brief Signals that the penumbra bias has changed.
virtual void OnPenumbraBiasChanged(float penumbraBias) { AZ_UNUSED(penumbraBias); }
};
//! The EBus for spot light notification events.
typedef AZ::EBus<SpotLightNotifications> SpotLightNotificationBus;
} // namespace Render
} // namespace AZ
@@ -0,0 +1,60 @@
/*
* 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/Component/Component.h>
#include <AzCore/Math/Color.h>
#include <Atom/Feature/CoreLights/PhotometricValue.h>
#include <Atom/Feature/CoreLights/ShadowConstants.h>
#include <AtomLyIntegration/CommonFeatures/CoreLights/CoreLightsConstants.h>
namespace AZ
{
namespace Render
{
struct SpotLightComponentConfig final
: ComponentConfig
{
AZ_RTTI(SpotLightComponentConfig, "{20C882C8-615E-4272-93A8-BE9102E6EFED}", ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
AZ::Color m_color = AZ::Color::CreateOne();
float m_intensity = 100.0f;
PhotometricUnit m_intensityMode = PhotometricUnit::Lumen;
float m_bulbRadius = 0.075;
float m_innerConeDegrees = 45.0f;
float m_outerConeDegrees = 55.0f;
float m_attenuationRadius = 20.0f;
float m_penumbraBias = 0.0f;
LightAttenuationRadiusMode m_attenuationRadiusMode = LightAttenuationRadiusMode::Automatic;
bool m_enabledShadow = false;
ShadowmapSize m_shadowmapSize = MaxShadowmapImageSize;
ShadowFilterMethod m_shadowFilterMethod = ShadowFilterMethod::None;
float m_boundaryWidthInDegrees = 0.25f;
uint16_t m_predictionSampleCount = 4;
uint16_t m_filteringSampleCount = 32;
// The following functions provide information to an EditContext...
//! Returns true if m_attenuationRadiusMode is set to LightAttenuationRadiusMode::Automatic
bool IsAttenuationRadiusModeAutomatic() const;
//! Returns characters for a suffix for the light type including a space. " lm" for lumens for example.
const char* GetIntensitySuffix() const;
float GetConeDegrees() const;
bool IsShadowFilteringDisabled() const;
bool IsShadowPcfDisabled() const;
};
}
}
@@ -0,0 +1,87 @@
/*
* 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 <AzCore/Component/ComponentBus.h>
#include <AtomLyIntegration/CommonFeatures/Decals/DecalComponentConfig.h>
namespace AZ
{
namespace Render
{
class DecalRequests
: public ComponentBus
{
public:
AZ_RTTI(DecalRequests, "{E9FC84EC-C63A-4241-B284-B8B72487F269}");
//! Overrides the default AZ::EBusTraits handler policy to allow one listener only.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
virtual ~DecalRequests() {}
//! Gets the attenuation angle. This controls how much the angle between geometry and the decal affects decal opacity.
virtual float GetAttenuationAngle() const = 0;
//! Sets the attenuation angle. This controls how much the angle between geometry and the decal affects decal opacity.
virtual void SetAttenuationAngle(float angle) = 0;
//! Gets the decal opacity
virtual float GetOpacity() const = 0;
//! Sets the decal opacity
virtual void SetOpacity(float opacity) = 0;
//! Gets the decal sort key. Decals with a larger sort key appear over top of smaller sort keys.
virtual uint8_t GetSortKey() const = 0;
//! Sets the decal sort key. Decals with a larger sort key appear over top of smaller sort keys.
virtual void SetSortKey(uint8_t sortKey) = 0;
//! Sets the material asset Id for this decal
virtual void SetMaterialAssetId(Data::AssetId) = 0;
//! Gets the material assert Id for this decal
virtual Data::AssetId GetMaterialAssetId() const = 0;
};
/// The EBus for requests to for setting and getting decal component properties.
typedef AZ::EBus<DecalRequests> DecalRequestBus;
class DecalNotifications
: public ComponentBus
{
public:
AZ_RTTI(DecalNotifications, "{BA81FBF5-FF66-4868-AD85-6B7954941B6B}");
virtual ~DecalNotifications() {}
//! Signals that the attenuation angle has changed.
//! @param attenuationAngle This controls how much the angle between geometry and the decal affects decal opacity.
virtual void OnAttenuationAngleChanged([[maybe_unused]] float attenuationAngle) { }
//! Signals that the opacity has changed.
//! @param opacity The opaqueness of the decal.
virtual void OnOpacityChanged([[maybe_unused]] float opacity){ }
//! Signals that the sortkey has changed.
//! @param sortKey Decals with a larger sort key appear over top of smaller sort keys.
virtual void OnSortKeyChanged([[maybe_unused]] uint8_t sortKey){ }
//! Signals that the material has changed
//! @param materialAsset The material asset of the decal
virtual void OnMaterialChanged(Data::Asset<RPI::MaterialAsset> materialAsset){ }
};
/// The EBus for decal notification events.
typedef AZ::EBus<DecalNotifications> DecalNotificationBus;
} // namespace Render
} // namespace AZ
@@ -0,0 +1,37 @@
/*
* 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/Component/Component.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
namespace AZ
{
namespace Render
{
struct DecalComponentConfig final
: public ComponentConfig
{
AZ_RTTI(DecalComponentConfig, "{5DFDC832-38B6-4F46-8C53-4CA0C82BC0AB}", ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
static const uint8_t DefaultDecalSortKey = 16;
Data::Asset<RPI::MaterialAsset> m_materialAsset;
float m_attenuationAngle = 1.0f;
float m_opacity = 1.0f;
// Decals with a larger sort key appear over top of smaller sort keys
uint8_t m_sortKey = DefaultDecalSortKey;
};
}
}

Some files were not shown because too many files have changed in this diff Show More