Merge pull request #734 from aws-lumberyard-dev/nvsickle/DebugInfoDisplay

Restore debug rendering to the viewport
main
Nicholas Van Sickle 5 years ago committed by GitHub
commit 46c0c35c26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -145,6 +145,7 @@ struct STextDrawContext
Vec2 m_size; Vec2 m_size;
Vec2i m_requestSize; Vec2i m_requestSize;
float m_widthScale; float m_widthScale;
float m_lineSpacing;
float m_clipX; float m_clipX;
float m_clipY; float m_clipY;
@ -175,6 +176,7 @@ struct STextDrawContext
, m_size(16.0f, 16.0f) , m_size(16.0f, 16.0f)
, m_requestSize(static_cast<int32>(m_size.x), static_cast<int32>(m_size.y)) , m_requestSize(static_cast<int32>(m_size.x), static_cast<int32>(m_size.y))
, m_widthScale(1.0f) , m_widthScale(1.0f)
, m_lineSpacing(0.f)
, m_clipX(0) , m_clipX(0)
, m_clipY(0) , m_clipY(0)
, m_clipWidth(0) , m_clipWidth(0)
@ -209,11 +211,13 @@ struct STextDrawContext
void SetTransform(const Matrix34& transform) { m_transform = transform; } void SetTransform(const Matrix34& transform) { m_transform = transform; }
void SetBaseState(int baseState) { m_baseState = baseState; } void SetBaseState(int baseState) { m_baseState = baseState; }
void SetOverrideViewProjMatrices(bool overrideViewProjMatrices) { m_overrideViewProjMatrices = overrideViewProjMatrices; } void SetOverrideViewProjMatrices(bool overrideViewProjMatrices) { m_overrideViewProjMatrices = overrideViewProjMatrices; }
void SetLineSpacing(float lineSpacing) { m_lineSpacing = lineSpacing; }
float GetCharWidth() const { return m_size.x; } float GetCharWidth() const { return m_size.x; }
float GetCharHeight() const { return m_size.y; } float GetCharHeight() const { return m_size.y; }
float GetCharWidthScale() const { return m_widthScale; } float GetCharWidthScale() const { return m_widthScale; }
int GetFlags() const { return m_drawTextFlags; } int GetFlags() const { return m_drawTextFlags; }
float GetLineSpacing() const { return m_lineSpacing; }
bool IsColorOverridden() const { return m_colorOverride.a != 0; } bool IsColorOverridden() const { return m_colorOverride.a != 0; }
}; };

@ -24,9 +24,7 @@ namespace AZ
AZ_TYPE_INFO_SPECIALIZE(AZStd::chrono::system_clock::time_point, "{5C48FD59-7267-405D-9C06-1EA31379FE82}"); AZ_TYPE_INFO_SPECIALIZE(AZStd::chrono::system_clock::time_point, "{5C48FD59-7267-405D-9C06-1EA31379FE82}");
/** //! Wrapper that reflects a AZStd::chrono::system_clock::time_point to script.
* Wrapper that reflects a AZStd::chrono::system_clock::time_point to script.
*/
class ScriptTimePoint class ScriptTimePoint
{ {
public: public:
@ -38,33 +36,45 @@ namespace AZ
explicit ScriptTimePoint(AZStd::chrono::system_clock::time_point timePoint) explicit ScriptTimePoint(AZStd::chrono::system_clock::time_point timePoint)
: m_timePoint(timePoint) {} : m_timePoint(timePoint) {}
AZStd::string ToString() const //! Formats the time point in a string formatted as: "Time <seconds since epoch>".
{ AZStd::string ToString() const;
return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count());
}
const AZStd::chrono::system_clock::time_point& Get() { return m_timePoint; } //! Returns the time point.
const AZStd::chrono::system_clock::time_point& Get() const;
// Returns the time point in seconds //! Returns the time point in seconds
double GetSeconds() const double GetSeconds() const;
{
typedef AZStd::chrono::duration<double> double_seconds;
return AZStd::chrono::duration_cast<double_seconds>(m_timePoint.time_since_epoch()).count();
}
// Returns the time point in milliseconds //! Returns the time point in milliseconds
double GetMilliseconds() const double GetMilliseconds() const;
{
typedef AZStd::chrono::duration<double, AZStd::milli> double_ms;
return AZStd::chrono::duration_cast<double_ms>(m_timePoint.time_since_epoch()).count();
}
static void Reflect(ReflectContext* reflection); static void Reflect(ReflectContext* reflection);
protected: protected:
AZStd::chrono::system_clock::time_point m_timePoint; AZStd::chrono::system_clock::time_point m_timePoint;
}; };
inline AZStd::string ScriptTimePoint::ToString() const
{
return AZStd::string::format("Time %llu", m_timePoint.time_since_epoch().count());
}
inline const AZStd::chrono::system_clock::time_point& ScriptTimePoint::Get() const
{
return m_timePoint;
}
inline double ScriptTimePoint::GetSeconds() const
{
typedef AZStd::chrono::duration<double> double_seconds;
return AZStd::chrono::duration_cast<double_seconds>(m_timePoint.time_since_epoch()).count();
}
inline double ScriptTimePoint::GetMilliseconds() const
{
typedef AZStd::chrono::duration<double, AZStd::milli> double_ms;
return AZStd::chrono::duration_cast<double_ms>(m_timePoint.time_since_epoch()).count();
}
} }

@ -40,17 +40,18 @@ namespace AzFramework
//! Standard parameters for drawing text on screen //! Standard parameters for drawing text on screen
struct TextDrawParameters struct TextDrawParameters
{ {
ViewportId m_drawViewportId = InvalidViewportId; //! Viewport to draw into ViewportId m_drawViewportId = InvalidViewportId; //!< Viewport to draw into
AZ::Vector3 m_position; //! world space position for 3d draws, screen space x,y,depth for 2d. AZ::Vector3 m_position; //!< world space position for 3d draws, screen space x,y,depth for 2d.
AZ::Color m_color = AZ::Colors::White; //! Color to draw the text AZ::Color m_color = AZ::Colors::White; //!< Color to draw the text
AZ::Vector2 m_scale = AZ::Vector2(1.0f); //! font scale AZ::Vector2 m_scale = AZ::Vector2(1.0f); //!< font scale
TextHorizontalAlignment m_hAlign = TextHorizontalAlignment::Left; //! Horizontal text alignment float m_lineSpacing; //!< Spacing between new lines, as a percentage of m_scale.
TextVerticalAlignment m_vAlign = TextVerticalAlignment::Top; //! Vertical text alignment TextHorizontalAlignment m_hAlign = TextHorizontalAlignment::Left; //!< Horizontal text alignment
bool m_monospace = false; //! disable character proportional spacing TextVerticalAlignment m_vAlign = TextVerticalAlignment::Top; //!< Vertical text alignment
bool m_depthTest = false; //! Test character against the depth buffer bool m_monospace = false; //!< disable character proportional spacing
bool m_virtual800x600ScreenSize = true; //! Text placement and size are scaled relative to a virtual 800x600 resolution bool m_depthTest = false; //!< Test character against the depth buffer
bool m_scaleWithWindow = false; //! Font gets bigger as the window gets bigger bool m_virtual800x600ScreenSize = true; //!< Text placement and size are scaled relative to a virtual 800x600 resolution
bool m_multiline = true; //! text respects ascii newline characters bool m_scaleWithWindow = false; //!< Font gets bigger as the window gets bigger
bool m_multiline = true; //!< text respects ascii newline characters
}; };
class FontDrawInterface class FontDrawInterface
@ -63,10 +64,13 @@ namespace AzFramework
virtual void DrawScreenAlignedText2d( virtual void DrawScreenAlignedText2d(
const TextDrawParameters& params, const TextDrawParameters& params,
const AZStd::string_view& string) = 0; AZStd::string_view text) = 0;
virtual void DrawScreenAlignedText3d( virtual void DrawScreenAlignedText3d(
const TextDrawParameters& params, const TextDrawParameters& params,
const AZStd::string_view& string) = 0; AZStd::string_view text) = 0;
virtual AZ::Vector2 GetTextSize(
const TextDrawParameters& params,
AZStd::string_view text) = 0;
}; };
class FontQueryInterface class FontQueryInterface

@ -254,7 +254,7 @@ namespace AzToolsFramework
m_localTransformDirty = true; m_localTransformDirty = true;
m_worldTransformDirty = true; m_worldTransformDirty = true;
if (GetEntity()) if (const AZ::Entity* entity = GetEntity())
{ {
SetDirty(); SetDirty();
@ -273,6 +273,22 @@ namespace AzToolsFramework
{ {
boundsUnion->OnTransformUpdated(GetEntity()); boundsUnion->OnTransformUpdated(GetEntity());
} }
// Fire a property changed notification for this component
if (const AZ::Component* component = entity->FindComponent<Components::TransformComponent>())
{
PropertyEditorEntityChangeNotificationBus::Event(
GetEntityId(), &PropertyEditorEntityChangeNotifications::OnEntityComponentPropertyChanged, component->GetId());
}
// Refresh the property editor if we're selected
bool selected = false;
ToolsApplicationRequestBus::BroadcastResult(
selected, &AzToolsFramework::ToolsApplicationRequests::IsSelected, GetEntityId());
if (selected)
{
ToolsApplicationEvents::Bus::Broadcast(
&ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values);
}
} }
} }

@ -123,6 +123,7 @@ ly_add_target(
Gem::Atom_RPI.Public Gem::Atom_RPI.Public
Gem::Atom_Feature_Common.Static Gem::Atom_Feature_Common.Static
Gem::AtomToolsFramework.Static Gem::AtomToolsFramework.Static
Gem::AtomViewportDisplayInfo
${additional_dependencies} ${additional_dependencies}
PUBLIC PUBLIC
3rdParty::AWSNativeSDK::Core 3rdParty::AWSNativeSDK::Core

@ -13,7 +13,7 @@
// Description : CViewportTitleDlg implementation file // Description : CViewportTitleDlg implementation file
#if !defined(Q_MOC_RUN)
#include "EditorDefs.h" #include "EditorDefs.h"
#include "ViewportTitleDlg.h" #include "ViewportTitleDlg.h"
@ -36,10 +36,13 @@
#include "UsedResources.h" #include "UsedResources.h"
#include "Include/IObjectManager.h" #include "Include/IObjectManager.h"
#include <AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h>
AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING AZ_PUSH_DISABLE_DLL_EXPORT_MEMBER_WARNING
#include "ui_ViewportTitleDlg.h" #include "ui_ViewportTitleDlg.h"
AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING AZ_POP_DISABLE_DLL_EXPORT_MEMBER_WARNING
#endif //!defined(Q_MOC_RUN)
// CViewportTitleDlg dialog // CViewportTitleDlg dialog
@ -63,6 +66,32 @@ inline namespace Helpers
} }
} }
namespace
{
class CViewportTitleDlgDisplayInfoHelper
: public QObject
, public AZ::AtomBridge::AtomViewportInfoDisplayNotificationBus::Handler
{
Q_OBJECT
public:
CViewportTitleDlgDisplayInfoHelper(CViewportTitleDlg* parent)
: QObject(parent)
{
AZ::AtomBridge::AtomViewportInfoDisplayNotificationBus::Handler::BusConnect();
}
signals:
void ViewportInfoStatusUpdated(int newIndex);
private:
void OnViewportInfoDisplayStateChanged(AZ::AtomBridge::ViewportInfoDisplayState state)
{
emit ViewportInfoStatusUpdated(static_cast<int>(state));
}
};
} //end anonymous namespace
CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent) CViewportTitleDlg::CViewportTitleDlg(QWidget* pParent)
: QWidget(pParent) : QWidget(pParent)
, m_ui(new Ui::ViewportTitleDlg) , m_ui(new Ui::ViewportTitleDlg)
@ -115,14 +144,11 @@ void CViewportTitleDlg::OnInitDialog()
m_ui->m_toggleHelpersBtn->setChecked(GetIEditor()->GetDisplaySettings()->IsDisplayHelpers()); m_ui->m_toggleHelpersBtn->setChecked(GetIEditor()->GetDisplaySettings()->IsDisplayHelpers());
ICVar* pDisplayInfo(gEnv->pConsole->GetCVar("r_displayInfo"));
if (pDisplayInfo) // Add a child parented to us that listens for r_displayInfo changes.
{ auto displayInfoHelper = new CViewportTitleDlgDisplayInfoHelper(this);
SFunctor oFunctor; connect(displayInfoHelper, &CViewportTitleDlgDisplayInfoHelper::ViewportInfoStatusUpdated, this, &CViewportTitleDlg::UpdateDisplayInfo);
oFunctor.Set(OnChangedDisplayInfo, pDisplayInfo, m_ui->m_toggleDisplayInfoBtn); UpdateDisplayInfo();
m_displayInfoCallbackIndex = pDisplayInfo->AddOnChangeFunctor(oFunctor);
OnChangedDisplayInfo(pDisplayInfo, m_ui->m_toggleDisplayInfoBtn);
}
connect(m_ui->m_toggleHelpersBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleHelpers); connect(m_ui->m_toggleHelpersBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleHelpers);
connect(m_ui->m_toggleDisplayInfoBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleDisplayInfo); connect(m_ui->m_toggleDisplayInfoBtn, &QToolButton::clicked, this, &CViewportTitleDlg::OnToggleDisplayInfo);
@ -156,6 +182,29 @@ void CViewportTitleDlg::OnToggleHelpers()
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void CViewportTitleDlg::OnToggleDisplayInfo() void CViewportTitleDlg::OnToggleDisplayInfo()
{ {
AZ::AtomBridge::ViewportInfoDisplayState state = AZ::AtomBridge::ViewportInfoDisplayState::NoInfo;
AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::BroadcastResult(
state,
&AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState
);
state = aznumeric_cast<AZ::AtomBridge::ViewportInfoDisplayState>(
(aznumeric_cast<int>(state)+1) % aznumeric_cast<int>(AZ::AtomBridge::ViewportInfoDisplayState::Invalid));
// SetDisplayState will fire OnViewportInfoDisplayStateChanged and notify us, no need to call UpdateDisplayInfo.
AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast(
&AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState,
state
);
}
//////////////////////////////////////////////////////////////////////////
void CViewportTitleDlg::UpdateDisplayInfo()
{
AZ::AtomBridge::ViewportInfoDisplayState state = AZ::AtomBridge::ViewportInfoDisplayState::NoInfo;
AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::BroadcastResult(
state,
&AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Events::GetDisplayState
);
m_ui->m_toggleDisplayInfoBtn->setChecked(state != AZ::AtomBridge::ViewportInfoDisplayState::NoInfo);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -544,10 +593,6 @@ void CViewportTitleDlg::UpdateCustomPresets(const QString& text, QStringList& cu
} }
} }
void CViewportTitleDlg::OnChangedDisplayInfo([[maybe_unused]] ICVar* pDisplayInfo, [[maybe_unused]] QAbstractButton* pDisplayInfoButton)
{
}
bool CViewportTitleDlg::eventFilter(QObject* object, QEvent* event) bool CViewportTitleDlg::eventFilter(QObject* object, QEvent* event)
{ {
bool consumeEvent = false; bool consumeEvent = false;
@ -609,4 +654,5 @@ namespace AzToolsFramework
} }
} }
#include "ViewportTitleDlg.moc"
#include <moc_ViewportTitleDlg.cpp> #include <moc_ViewportTitleDlg.cpp>

@ -60,7 +60,6 @@ public:
static void LoadCustomPresets(const QString& section, const QString& keyName, QStringList& outCustompresets); static void LoadCustomPresets(const QString& section, const QString& keyName, QStringList& outCustompresets);
static void SaveCustomPresets(const QString& section, const QString& keyName, const QStringList& custompresets); static void SaveCustomPresets(const QString& section, const QString& keyName, const QStringList& custompresets);
static void UpdateCustomPresets(const QString& text, QStringList& custompresets); static void UpdateCustomPresets(const QString& text, QStringList& custompresets);
static void OnChangedDisplayInfo(ICVar* pDisplayInfo, QAbstractButton* pDisplayInfoButton);
bool eventFilter(QObject* object, QEvent* event) override; bool eventFilter(QObject* object, QEvent* event) override;
@ -77,6 +76,7 @@ protected:
void OnMaximize(); void OnMaximize();
void OnToggleHelpers(); void OnToggleHelpers();
void OnToggleDisplayInfo(); void OnToggleDisplayInfo();
void UpdateDisplayInfo();
QString m_title; QString m_title;
@ -87,8 +87,6 @@ protected:
QStringList m_customFOVPresets; QStringList m_customFOVPresets;
QStringList m_customAspectRatioPresets; QStringList m_customAspectRatioPresets;
uint64 m_displayInfoCallbackIndex;
void OnMenuFOVCustom(); void OnMenuFOVCustom();
void CreateFOVMenu(); void CreateFOVMenu();

@ -609,14 +609,6 @@ void CComponentEntityObject::InvalidateTM(int nWhyFlags)
{ {
Matrix34 worldTransform = GetWorldTM(); Matrix34 worldTransform = GetWorldTM();
EBUS_EVENT_ID(m_entityId, AZ::TransformBus, SetWorldTM, LYTransformToAZTransform(worldTransform)); EBUS_EVENT_ID(m_entityId, AZ::TransformBus, SetWorldTM, LYTransformToAZTransform(worldTransform));
// When transformed via the editor, make sure the entity is marked dirty for undo capture.
EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus, AddDirtyEntity, m_entityId);
if (CheckFlags(OBJFLAG_SELECTED))
{
EBUS_EVENT(AzToolsFramework::ToolsApplicationEvents::Bus, InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values);
}
} }
} }
} }

@ -91,6 +91,8 @@ namespace AZ
const AZ::Matrix4x4& GetViewToWorldMatrix() const; const AZ::Matrix4x4& GetViewToWorldMatrix() const;
const AZ::Matrix4x4& GetViewToClipMatrix() const; const AZ::Matrix4x4& GetViewToClipMatrix() const;
const AZ::Matrix4x4& GetWorldToClipMatrix() const; const AZ::Matrix4x4& GetWorldToClipMatrix() const;
//! Get the camera's world transform, converted from the viewToWorld matrix's native y-up to z-up
AZ::Transform GetCameraTransform() const;
//! Finalize draw lists in this view. This function should only be called when all //! Finalize draw lists in this view. This function should only be called when all
//! draw packets for current frame are added. //! draw packets for current frame are added.

@ -92,6 +92,8 @@ namespace AZ
virtual ViewPtr GetCurrentView(const Name& contextName) const = 0; virtual ViewPtr GetCurrentView(const Name& contextName) const = 0;
}; };
using ViewportContextRequests = AZ::Interface<ViewportContextRequestsInterface>;
class ViewportContextManagerNotifications class ViewportContextManagerNotifications
: public AZ::EBusTraits : public AZ::EBusTraits
{ {

@ -110,6 +110,15 @@ namespace AZ
InvalidateSrg(); InvalidateSrg();
} }
AZ::Transform View::GetCameraTransform() const
{
static const Quaternion yUpToZUp = Quaternion::CreateRotationX(-AZ::Constants::HalfPi);
return AZ::Transform::CreateFromQuaternionAndTranslation(
Quaternion::CreateFromMatrix4x4(m_viewToWorldMatrix) * yUpToZUp,
m_viewToWorldMatrix.GetTranslation()
).GetOrthogonalized();
}
void View::SetCameraTransform(const AZ::Matrix3x4& cameraTransform) void View::SetCameraTransform(const AZ::Matrix3x4& cameraTransform)
{ {
m_position = cameraTransform.GetTranslation(); m_position = cameraTransform.GetTranslation();
@ -118,7 +127,7 @@ namespace AZ
// is in a Z-up world and an identity matrix means that it faces along the positive-Y axis and Z is up. // is in a Z-up world and an identity matrix means that it faces along the positive-Y axis and Z is up.
// An identity view matrix on the other hand looks along the negative Z-axis. // An identity view matrix on the other hand looks along the negative Z-axis.
// So we adjust for this by rotating the camera world matrix by 90 degrees around the X axis. // So we adjust for this by rotating the camera world matrix by 90 degrees around the X axis.
AZ::Matrix3x4 zUpToYUp = AZ::Matrix3x4::CreateRotationX(AZ::Constants::HalfPi); static AZ::Matrix3x4 zUpToYUp = AZ::Matrix3x4::CreateRotationX(AZ::Constants::HalfPi);
AZ::Matrix3x4 yUpWorld = cameraTransform * zUpToYUp; AZ::Matrix3x4 yUpWorld = cameraTransform * zUpToYUp;
float viewToWorldMatrixRaw[16] = { float viewToWorldMatrixRaw[16] = {

@ -194,12 +194,7 @@ namespace AZ
AZ::Transform ViewportContext::GetCameraTransform() const AZ::Transform ViewportContext::GetCameraTransform() const
{ {
const Matrix4x4& worldToViewMatrix = GetDefaultView()->GetViewToWorldMatrix(); return GetDefaultView()->GetCameraTransform();
const Quaternion zUpToYUp = Quaternion::CreateRotationX(-AZ::Constants::HalfPi);
return AZ::Transform::CreateFromQuaternionAndTranslation(
Quaternion::CreateFromMatrix4x4(worldToViewMatrix) * zUpToYUp,
worldToViewMatrix.GetTranslation()
).GetOrthogonalized();
} }
void ViewportContext::SetCameraTransform(const AZ::Transform& transform) void ViewportContext::SetCameraTransform(const AZ::Transform& transform)

@ -63,6 +63,7 @@ ly_add_target(
Gem::EMotionFX_Atom Gem::EMotionFX_Atom
Gem::ImguiAtom Gem::ImguiAtom
Gem::AtomFont Gem::AtomFont
Gem::AtomViewportDisplayInfo
) )
if(PAL_TRAIT_BUILD_HOST_TOOLS) if(PAL_TRAIT_BUILD_HOST_TOOLS)
@ -104,5 +105,6 @@ if(PAL_TRAIT_BUILD_HOST_TOOLS)
Gem::ImguiAtom Gem::ImguiAtom
Gem::AtomFont Gem::AtomFont
Gem::AtomToolsFramework.Editor Gem::AtomToolsFramework.Editor
Gem::AtomViewportDisplayInfo
) )
endif() endif()

@ -207,11 +207,15 @@ namespace AZ
// AzFramework::FontDrawInterface implementation // AzFramework::FontDrawInterface implementation
void DrawScreenAlignedText2d( void DrawScreenAlignedText2d(
const AzFramework::TextDrawParameters& params, const AzFramework::TextDrawParameters& params,
const AZStd::string_view& string) override; AZStd::string_view text) override;
void DrawScreenAlignedText3d( void DrawScreenAlignedText3d(
const AzFramework::TextDrawParameters& params, const AzFramework::TextDrawParameters& params,
const AZStd::string_view& string) override; AZStd::string_view text) override;
AZ::Vector2 GetTextSize(
const AzFramework::TextDrawParameters& params,
AZStd::string_view text) override;
public: public:
FFont(AtomFont* atomFont, const char* fontName); FFont(AtomFont* atomFont, const char* fontName);
@ -233,7 +237,7 @@ namespace AZ
void Prepare(const char* str, bool updateTexture, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize); void Prepare(const char* str, bool updateTexture, const AtomFont::GlyphSize& glyphSize = AtomFont::defaultGlyphSize);
void DrawStringUInternal( void DrawStringUInternal(
const RHI::Viewport& viewport, const RHI::Viewport& viewport,
RPI::ViewportContext* viewportContext, RPI::ViewportContextPtr viewportContext,
float x, float x,
float y, float y,
float z, float z,
@ -282,6 +286,16 @@ namespace AZ
RPI::WindowContextSharedPtr GetDefaultWindowContext() const; RPI::WindowContextSharedPtr GetDefaultWindowContext() const;
RPI::ViewportContextPtr GetDefaultViewportContext() const; RPI::ViewportContextPtr GetDefaultViewportContext() const;
struct DrawParameters
{
TextDrawContext m_ctx;
AZ::Vector2 m_position;
AZ::Vector2 m_size;
AZ::RPI::ViewportContextPtr m_viewportContext;
const AZ::RHI::Viewport* m_viewport;
};
DrawParameters ExtractDrawParameters(const AzFramework::TextDrawParameters& params, AZStd::string_view text, bool forceCalculateSize);
private: private:
static constexpr uint32_t NumBuffers = 2; static constexpr uint32_t NumBuffers = 2;
static constexpr float WindowScaleWidth = 800.0f; static constexpr float WindowScaleWidth = 800.0f;

@ -280,7 +280,7 @@ void AZ::FFont::DrawString(float x, float y, const char* str, const bool asciiMu
return; return;
} }
DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext().get(), x, y, 1.0f, str, asciiMultiLine, ctx); DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext(), x, y, 1.0f, str, asciiMultiLine, ctx);
} }
void AZ::FFont::DrawString(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx) void AZ::FFont::DrawString(float x, float y, float z, const char* str, const bool asciiMultiLine, const TextDrawContext& ctx)
@ -290,12 +290,12 @@ void AZ::FFont::DrawString(float x, float y, float z, const char* str, const boo
return; return;
} }
DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext().get(), x, y, z, str, asciiMultiLine, ctx); DrawStringUInternal(GetDefaultWindowContext()->GetViewport(), GetDefaultViewportContext(), x, y, z, str, asciiMultiLine, ctx);
} }
void AZ::FFont::DrawStringUInternal( void AZ::FFont::DrawStringUInternal(
const RHI::Viewport& viewport, const RHI::Viewport& viewport,
RPI::ViewportContext* viewportContext, RPI::ViewportContextPtr viewportContext,
float x, float x,
float y, float y,
float z, float z,
@ -505,7 +505,7 @@ Vec2 AZ::FFont::GetTextSizeUInternal(
} }
charX = offset.x; charX = offset.x;
charY += size.y; charY += size.y * (1.f + ctx.GetLineSpacing());
if (charY > maxH) if (charY > maxH)
{ {
@ -944,7 +944,7 @@ int AZ::FFont::CreateQuadsForText(const RHI::Viewport& viewport, float x, float
case '\n': case '\n':
{ {
charX = baseXY.x + offset.x; charX = baseXY.x + offset.x;
charY += size.y; charY += size.y * (1.f + ctx.GetLineSpacing());
continue; continue;
} }
break; break;
@ -1675,47 +1675,46 @@ static void SetCommonContextFlags(AZ::TextDrawContext& ctx, const AzFramework::T
} }
} }
void AZ::FFont::DrawScreenAlignedText2d( AZ::FFont::DrawParameters AZ::FFont::ExtractDrawParameters(const AzFramework::TextDrawParameters& params, AZStd::string_view text, bool forceCalculateSize)
const AzFramework::TextDrawParameters& params,
const AZStd::string_view& string)
{ {
DrawParameters internalParams;
if (params.m_drawViewportId == AzFramework::InvalidViewportId || if (params.m_drawViewportId == AzFramework::InvalidViewportId ||
string.empty()) text.empty())
{ {
return; return internalParams;
} }
//Code mostly duplicated from CRenderer::Draw2dTextWithDepth
float posX = params.m_position.GetX(); float posX = params.m_position.GetX();
float posY = params.m_position.GetY(); float posY = params.m_position.GetY();
AZ::RPI::ViewportContext* viewportContext = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get()->GetViewportContextById(params.m_drawViewportId).get(); internalParams.m_viewportContext = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get()->GetViewportContextById(params.m_drawViewportId);
const AZ::RHI::Viewport& viewport = viewportContext->GetWindowContext()->GetViewport(); const AZ::RHI::Viewport& viewport = internalParams.m_viewportContext->GetWindowContext()->GetViewport();
internalParams.m_viewport = &viewport;
if (params.m_virtual800x600ScreenSize) if (params.m_virtual800x600ScreenSize)
{ {
posX *= WindowScaleWidth / (viewport.m_maxX - viewport.m_minX); posX *= WindowScaleWidth / (viewport.m_maxX - viewport.m_minX);
posY *= WindowScaleHeight / (viewport.m_maxY - viewport.m_minY); posY *= WindowScaleHeight / (viewport.m_maxY - viewport.m_minY);
} }
TextDrawContext ctx; internalParams.m_ctx.SetBaseState(GS_NODEPTHTEST);
ctx.SetBaseState(GS_NODEPTHTEST); internalParams.m_ctx.SetColor(AZColorToLYColorF(params.m_color));
ctx.SetColor(AZColorToLYColorF(params.m_color)); internalParams.m_ctx.SetCharWidthScale((params.m_monospace || params.m_scaleWithWindow) ? 0.5f : 1.0f);
ctx.SetCharWidthScale((params.m_monospace || params.m_scaleWithWindow) ? 0.5f : 1.0f); internalParams.m_ctx.EnableFrame(false);
ctx.EnableFrame(false); internalParams.m_ctx.SetProportional(!params.m_monospace && params.m_scaleWithWindow);
ctx.SetProportional(!params.m_monospace && params.m_scaleWithWindow); internalParams.m_ctx.SetSizeIn800x600(params.m_scaleWithWindow && params.m_virtual800x600ScreenSize);
ctx.SetSizeIn800x600(params.m_scaleWithWindow && params.m_virtual800x600ScreenSize); internalParams.m_ctx.SetSize(AZVec2ToLYVec2(UiDraw_TextSizeFactor * params.m_scale));
ctx.SetSize(AZVec2ToLYVec2(UiDraw_TextSizeFactor * params.m_scale)); internalParams.m_ctx.SetLineSpacing(params.m_lineSpacing);
if (params.m_monospace || !params.m_scaleWithWindow) if (params.m_monospace || !params.m_scaleWithWindow)
{ {
ScaleCoord(viewport, posX, posY); ScaleCoord(viewport, posX, posY);
} }
if (params.m_hAlign != AzFramework::TextHorizontalAlignment::Left || if (params.m_hAlign != AzFramework::TextHorizontalAlignment::Left ||
params.m_vAlign != AzFramework::TextVerticalAlignment::Top) params.m_vAlign != AzFramework::TextVerticalAlignment::Top ||
forceCalculateSize)
{ {
Vec2 textSize = GetTextSizeUInternal(viewport, string.data(), params.m_multiline, ctx); Vec2 textSize = GetTextSizeUInternal(viewport, text.data(), params.m_multiline, internalParams.m_ctx);
// If we're using virtual 800x600 coordinates, convert the text size from // If we're using virtual 800x600 coordinates, convert the text size from
// pixels to that before using it as an offset. // pixels to that before using it as an offset.
if (ctx.m_sizeIn800x600) if (internalParams.m_ctx.m_sizeIn800x600)
{ {
float width = 1.0f; float width = 1.0f;
float height = 1.0f; float height = 1.0f;
@ -1741,33 +1740,46 @@ void AZ::FFont::DrawScreenAlignedText2d(
{ {
posY -= textSize.y; posY -= textSize.y;
} }
internalParams.m_size = AZ::Vector2{textSize.x, textSize.y};
}
SetCommonContextFlags(internalParams.m_ctx, params);
internalParams.m_ctx.m_drawTextFlags |= eDrawText_2D;
internalParams.m_position = AZ::Vector2{posX, posY};
return internalParams;
}
void AZ::FFont::DrawScreenAlignedText2d(
const AzFramework::TextDrawParameters& params,
AZStd::string_view text)
{
DrawParameters internalParams = ExtractDrawParameters(params, text, false);
if (!internalParams.m_viewportContext)
{
return;
} }
SetCommonContextFlags(ctx, params);
ctx.m_drawTextFlags |= eDrawText_2D;
DrawStringUInternal( DrawStringUInternal(
viewport, *internalParams.m_viewport,
viewportContext, internalParams.m_viewportContext,
posX, internalParams.m_position.GetX(),
posY, internalParams.m_position.GetY(),
params.m_position.GetZ(), // Z params.m_position.GetZ(), // Z
string.data(), text.data(),
params.m_multiline, params.m_multiline,
ctx internalParams.m_ctx
); );
} }
void AZ::FFont::DrawScreenAlignedText3d( void AZ::FFont::DrawScreenAlignedText3d(
const AzFramework::TextDrawParameters& params, const AzFramework::TextDrawParameters& params,
const AZStd::string_view& string) AZStd::string_view text)
{ {
if (params.m_drawViewportId == AzFramework::InvalidViewportId || DrawParameters internalParams = ExtractDrawParameters(params, text, false);
string.empty()) if (!internalParams.m_viewportContext)
{ {
return; return;
} }
AZ::RPI::ViewportContext* viewportContext = AZ::Interface<AZ::RPI::ViewportContextRequestsInterface>::Get()->GetViewportContextById(params.m_drawViewportId).get(); AZ::RPI::ViewPtr currentView = internalParams.m_viewportContext->GetDefaultView();
AZ::RPI::ViewPtr currentView = viewportContext->GetDefaultView();
if (!currentView) if (!currentView)
{ {
return; return;
@ -1779,7 +1791,23 @@ void AZ::FFont::DrawScreenAlignedText3d(
); );
AzFramework::TextDrawParameters param2d = params; AzFramework::TextDrawParameters param2d = params;
param2d.m_position = positionNDC; param2d.m_position = positionNDC;
DrawScreenAlignedText2d(param2d, string);
DrawStringUInternal(
*internalParams.m_viewport,
internalParams.m_viewportContext,
internalParams.m_position.GetX(),
internalParams.m_position.GetY(),
params.m_position.GetZ(), // Z
text.data(),
params.m_multiline,
internalParams.m_ctx
);
}
AZ::Vector2 AZ::FFont::GetTextSize(const AzFramework::TextDrawParameters& params, AZStd::string_view text)
{
DrawParameters sizeParams = ExtractDrawParameters(params, text, true);
return sizeParams.m_size;
} }
#endif //USE_NULLFONT_ALWAYS #endif //USE_NULLFONT_ALWAYS

@ -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,52 @@
#
# 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 AtomViewportDisplayInfo GEM_MODULE
NAMESPACE Gem
FILES_CMAKE
atomviewportdisplayinfo_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Source
PUBLIC
Include
BUILD_DEPENDENCIES
PRIVATE
AZ::AzCore
AZ::AtomCore
Legacy::CryCommon
Gem::Atom_RHI.Reflect
Gem::Atom_RPI.Public
)
################################################################################
# Tests
################################################################################
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
ly_add_target(
NAME AtomViewportDisplayInfo.Tests ${PAL_TRAIT_TEST_TARGET_TYPE}
NAMESPACE Gem
FILES_CMAKE
atomviewportdisplayinfo_test_files.cmake
INCLUDE_DIRECTORIES
PRIVATE
Include
Tests
BUILD_DEPENDENCIES
PRIVATE
AZ::AzTest
)
ly_add_googletest(
NAME Gem::AtomViewportDisplayInfo.Tests
)
endif()

@ -0,0 +1,61 @@
/*
* 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>
#include <AzCore/EBus/EBus.h>
namespace AZ
{
namespace AtomBridge
{
//! The level of information to display in the viewport info display overlay.
enum class ViewportInfoDisplayState : int
{
NoInfo = 0,
NormalInfo = 1,
FullInfo = 2,
CompactInfo = 3,
Invalid
};
//! This bus is used to request changes to the viewport info display overlay.
class AtomViewportInfoDisplayRequests
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single;
//! Gets the current viewport info overlay state.
virtual ViewportInfoDisplayState GetDisplayState() const = 0;
//! Sets the current viewport info overlay state.
//! The overlay will be drawn to the default viewport context every frame, if enabled.
virtual void SetDisplayState(ViewportInfoDisplayState state) = 0;
};
using AtomViewportInfoDisplayRequestBus = AZ::EBus<AtomViewportInfoDisplayRequests>;
//! This bus is used to listen for state changes in the viewport info display overlay.
class AtomViewportInfoDisplayNotifications
: public AZ::EBusTraits
{
public:
static const AZ::EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Multiple;
static const AZ::EBusAddressPolicy AddressPolicy = EBusAddressPolicy::Single;
//! Called when the ViewportInfoDisplayState (via the r_displayInfo CVar) has changed.
virtual void OnViewportInfoDisplayStateChanged([[maybe_unused]]ViewportInfoDisplayState state){}
};
using AtomViewportInfoDisplayNotificationBus = AZ::EBus<AtomViewportInfoDisplayNotifications>;
}
}

@ -0,0 +1,316 @@
/*
* 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 "AtomViewportDisplayInfoSystemComponent.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/EditContextConstants.inl>
#include <AzCore/Console/IConsole.h>
#include <AzCore/Interface/Interface.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <Atom/RPI.Public/ViewportContext.h>
#include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/Pass/ParentPass.h>
#include <Atom/RHI/Factory.h>
#include <CryCommon/ISystem.h>
#include <CryCommon/IConsole.h>
namespace AZ::Render
{
AZ_CVAR(int, r_displayInfo, 1, [](const int& newDisplayInfoVal)->void
{
// Forward this event to the system component so it can update accordingly.
// This callback only gets triggered by console commands, so this will not recurse.
AtomBridge::AtomViewportInfoDisplayRequestBus::Broadcast(
&AtomBridge::AtomViewportInfoDisplayRequestBus::Events::SetDisplayState,
aznumeric_cast<AtomBridge::ViewportInfoDisplayState>(newDisplayInfoVal)
);
}, AZ::ConsoleFunctorFlags::DontReplicate,
"Toggles debugging information display.\n"
"Usage: r_displayInfo [0=off/1=show/2=enhanced/3=compact]"
);
AZ_CVAR(float, r_fpsCalcInterval, 1.0f, nullptr, AZ::ConsoleFunctorFlags::DontReplicate,
"The time period over which to calculate the framerate for r_displayInfo."
);
void AtomViewportDisplayInfoSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<AtomViewportDisplayInfoSystemComponent, AZ::Component>()
->Version(0)
;
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<AtomViewportDisplayInfoSystemComponent>("Viewport Display Info", "Manages debug viewport information through r_displayInfo")
->ClassElement(Edit::ClassElements::EditorData, "")
->Attribute(Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
->Attribute(Edit::Attributes::AutoExpand, true)
;
}
}
}
void AtomViewportDisplayInfoSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("ViewportDisplayInfoService"));
}
void AtomViewportDisplayInfoSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC("ViewportDisplayInfoService"));
}
void AtomViewportDisplayInfoSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("RPISystem", 0xf2add773));
}
void AtomViewportDisplayInfoSystemComponent::GetDependentServices([[maybe_unused]] AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
}
void AtomViewportDisplayInfoSystemComponent::Activate()
{
AZ::Name apiName = AZ::RHI::Factory::Get().GetName();
if (!apiName.IsEmpty())
{
m_rendererDescription = AZStd::string::format("Atom using %s RHI", apiName.GetCStr());
}
AZ::RPI::ViewportContextNotificationBus::Handler::BusConnect(
AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContextName());
AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler::BusConnect();
}
void AtomViewportDisplayInfoSystemComponent::Deactivate()
{
AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler::BusDisconnect();
AZ::RPI::ViewportContextNotificationBus::Handler::BusDisconnect();
}
AZ::RPI::ViewportContextPtr AtomViewportDisplayInfoSystemComponent::GetViewportContext() const
{
return AZ::RPI::ViewportContextRequests::Get()->GetDefaultViewportContext();
}
void AtomViewportDisplayInfoSystemComponent::DrawLine(AZStd::string_view line, AZ::Color color)
{
m_drawParams.m_color = color;
AZ::Vector2 textSize = m_fontDrawInterface->GetTextSize(m_drawParams, line);
m_fontDrawInterface->DrawScreenAlignedText2d(m_drawParams, line);
m_drawParams.m_position.SetY(m_drawParams.m_position.GetY() + textSize.GetY() + m_lineSpacing);
}
void AtomViewportDisplayInfoSystemComponent::OnRenderTick()
{
if (!m_fontDrawInterface)
{
auto fontQueryInterface = AZ::Interface<AzFramework::FontQueryInterface>::Get();
if (!fontQueryInterface)
{
return;
}
m_fontDrawInterface =
fontQueryInterface->GetDefaultFontDrawInterface();
}
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
if (!m_fontDrawInterface || !viewportContext || !viewportContext->GetRenderScene())
{
return;
}
m_fpsInterval = AZStd::chrono::seconds(r_fpsCalcInterval);
UpdateFramerate();
const AtomBridge::ViewportInfoDisplayState displayLevel = GetDisplayState();
if (displayLevel == AtomBridge::ViewportInfoDisplayState::NoInfo)
{
return;
}
if (m_updateRootPassQuery)
{
if (auto rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass())
{
rootPass->SetPipelineStatisticsQueryEnabled(displayLevel != AtomBridge::ViewportInfoDisplayState::CompactInfo);
m_updateRootPassQuery = false;
}
}
m_drawParams.m_drawViewportId = viewportContext->GetId();
auto viewportSize = viewportContext->GetViewportSize();
m_drawParams.m_position = AZ::Vector3(viewportSize.m_width, 0.f, 1.f);
m_drawParams.m_color = AZ::Colors::White;
m_drawParams.m_scale = AZ::Vector2(0.7f);
m_drawParams.m_hAlign = AzFramework::TextHorizontalAlignment::Right;
m_drawParams.m_monospace = false;
m_drawParams.m_depthTest = false;
m_drawParams.m_virtual800x600ScreenSize = true;
m_drawParams.m_scaleWithWindow = false;
m_drawParams.m_multiline = true;
m_drawParams.m_lineSpacing = 0.5f;
// Calculate line spacing based on the font's actual line height
const float lineHeight = m_fontDrawInterface->GetTextSize(m_drawParams, " ").GetY();
m_lineSpacing = lineHeight * m_drawParams.m_lineSpacing;
DrawRendererInfo();
if (displayLevel == AtomBridge::ViewportInfoDisplayState::FullInfo)
{
DrawCameraInfo();
}
if (displayLevel != AtomBridge::ViewportInfoDisplayState::CompactInfo)
{
DrawPassInfo();
}
DrawFramerate();
}
AtomBridge::ViewportInfoDisplayState AtomViewportDisplayInfoSystemComponent::GetDisplayState() const
{
return aznumeric_cast<AtomBridge::ViewportInfoDisplayState>(r_displayInfo.operator int());
}
void AtomViewportDisplayInfoSystemComponent::SetDisplayState(AtomBridge::ViewportInfoDisplayState state)
{
r_displayInfo = aznumeric_cast<int>(state);
AtomBridge::AtomViewportInfoDisplayNotificationBus::Broadcast(
&AtomBridge::AtomViewportInfoDisplayNotificationBus::Events::OnViewportInfoDisplayStateChanged,
state);
m_updateRootPassQuery = true;
}
void AtomViewportDisplayInfoSystemComponent::DrawRendererInfo()
{
DrawLine(m_rendererDescription, AZ::Colors::Yellow);
}
void AtomViewportDisplayInfoSystemComponent::DrawCameraInfo()
{
AZ::RPI::ViewportContextPtr viewportContext = GetViewportContext();
AZ::RPI::ViewPtr currentView = viewportContext->GetDefaultView();
if (currentView == nullptr)
{
return;
}
auto viewportSize = viewportContext->GetViewportSize();
AzFramework::CameraState cameraState;
AzFramework::SetCameraClippingVolumeFromPerspectiveFovMatrixRH(cameraState, currentView->GetViewToClipMatrix());
const AZ::Transform transform = currentView->GetCameraTransform();
const AZ::Vector3 translation = transform.GetTranslation();
const AZ::Vector3 rotation = transform.GetEulerDegrees();
DrawLine(AZStd::string::format(
"CamPos=%.2f %.2f %.2f Angl=%3.0f %3.0f %4.0f ZN=%.2f ZF=%.0f",
translation.GetX(), translation.GetY(), translation.GetZ(),
rotation.GetX(), rotation.GetY(), rotation.GetZ(),
cameraState.m_nearClip, cameraState.m_farClip
));
}
void AtomViewportDisplayInfoSystemComponent::DrawPassInfo()
{
auto rootPass = AZ::RPI::PassSystemInterface::Get()->GetRootPass();
const RPI::PipelineStatisticsResult stats = rootPass->GetLatestPipelineStatisticsResult();
AZStd::function<int(const AZ::RPI::Ptr<AZ::RPI::Pass>)> containingPassCount = [&containingPassCount](const AZ::RPI::Ptr<AZ::RPI::Pass> pass)
{
int count = 1;
if (auto passAsParent = pass->AsParent())
{
for (const auto& child : passAsParent->GetChildren())
{
count += containingPassCount(child);
}
}
return count;
};
const int numPasses = containingPassCount(rootPass);
DrawLine(AZStd::string::format(
"Total Passes: %d Vertex Count: %lld Primitive Count: %lld",
numPasses,
aznumeric_cast<long long>(stats.m_vertexCount),
aznumeric_cast<long long>(stats.m_primitiveCount)
));
}
void AtomViewportDisplayInfoSystemComponent::UpdateFramerate()
{
if (!m_tickRequests)
{
m_tickRequests = AZ::TickRequestBus::FindFirstHandler();
if (!m_tickRequests)
{
return;
}
}
AZ::ScriptTimePoint currentTime = m_tickRequests->GetTimeAtCurrentTick();
// Only keep as much sampling data as is required by our FPS history.
while (!m_fpsHistory.empty() && (currentTime.Get() - m_fpsHistory.front().Get()) > m_fpsInterval)
{
m_fpsHistory.pop_front();
}
// Discard entries with a zero time-delta (can happen when we don't have window focus).
if (m_fpsHistory.empty() || (currentTime.Get() - m_fpsHistory.back().Get()) != AZStd::chrono::seconds(0))
{
m_fpsHistory.push_back(currentTime);
}
}
void AtomViewportDisplayInfoSystemComponent::DrawFramerate()
{
AZStd::chrono::duration<double> actualInterval = AZStd::chrono::seconds(0);
AZStd::optional<AZ::ScriptTimePoint> lastTime;
AZStd::optional<double> minFPS;
AZStd::optional<double> maxFPS;
for (const AZ::ScriptTimePoint& time : m_fpsHistory)
{
if (lastTime.has_value())
{
AZStd::chrono::duration<double> deltaTime = time.Get() - lastTime.value().Get();
double fps = AZStd::chrono::seconds(1) / deltaTime;
if (!minFPS.has_value())
{
minFPS = fps;
maxFPS = fps;
}
else
{
minFPS = AZStd::min(minFPS.value(), fps);
maxFPS = AZStd::max(maxFPS.value(), fps);
}
actualInterval += deltaTime;
}
lastTime = time;
}
const double averageFPS = aznumeric_cast<double>(m_fpsHistory.size()) / actualInterval.count();
const double frameIntervalSeconds = m_fpsInterval.count();
DrawLine(
AZStd::string::format(
"FPS %.1f [%.0f..%.0f], frame avg over %.1fs",
averageFPS,
minFPS.value_or(0.0),
maxFPS.value_or(0.0),
frameIntervalSeconds),
AZ::Colors::Yellow);
}
} // namespace AZ::Render

@ -0,0 +1,79 @@
/*
* 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/CrySystemBus.h>
#include <AzCore/Script/ScriptTimePoint.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzFramework/Font/FontInterface.h>
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/ViewportContextBus.h>
#include <AtomLyIntegration/AtomViewportDisplayInfo/AtomViewportInfoDisplayBus.h>
namespace AZ
{
class TickRequests;
namespace Render
{
class AtomViewportDisplayInfoSystemComponent
: public AZ::Component
, public AZ::RPI::ViewportContextNotificationBus::Handler
, public AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler
{
public:
AZ_COMPONENT(AtomViewportDisplayInfoSystemComponent, "{AC32F173-E7E2-4943-8E6C-7C3091978221}");
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 overrides...
void Activate() override;
void Deactivate() override;
// AZ::RPI::ViewportContextNotificationBus::Handler overrides...
void OnRenderTick() override;
// AZ::AtomBridge::AtomViewportInfoDisplayRequestBus::Handler overrides...
AtomBridge::ViewportInfoDisplayState GetDisplayState() const override;
void SetDisplayState(AtomBridge::ViewportInfoDisplayState state) override;
private:
AZ::RPI::ViewportContextPtr GetViewportContext() const;
void DrawLine(AZStd::string_view line, AZ::Color color = AZ::Colors::White);
void UpdateFramerate();
void DrawRendererInfo();
void DrawCameraInfo();
void DrawPassInfo();
void DrawFramerate();
AZStd::string m_rendererDescription;
AzFramework::TextDrawParameters m_drawParams;
AzFramework::FontDrawInterface* m_fontDrawInterface = nullptr;
float m_lineSpacing;
AZStd::chrono::duration<double> m_fpsInterval = AZStd::chrono::seconds(1);
AZStd::deque<AZ::ScriptTimePoint> m_fpsHistory;
AZStd::optional<AZStd::chrono::system_clock::time_point> m_lastMemoryUpdate;
AZ::TickRequests* m_tickRequests = nullptr;
bool m_updateRootPassQuery = true;
};
} // namespace Render
} // namespace AZ

@ -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 "AtomViewportDisplayInfoSystemComponent.h"
namespace AZ
{
namespace Render
{
class AtomViewportDisplayInfoModule
: public AZ::Module
{
public:
AZ_RTTI(AtomViewportDisplayInfoModule, "{B10C0E55-03A1-4A46-AE3E-D3615AEAA659}", AZ::Module);
AZ_CLASS_ALLOCATOR(AtomViewportDisplayInfoModule, AZ::SystemAllocator, 0);
AtomViewportDisplayInfoModule()
: AZ::Module()
{
m_descriptors.insert(m_descriptors.end(), {
AtomViewportDisplayInfoSystemComponent::CreateDescriptor(),
});
}
AZ::ComponentTypeList GetRequiredSystemComponents() const override
{
return AZ::ComponentTypeList{
azrtti_typeid<AtomViewportDisplayInfoSystemComponent>(),
};
}
};
} // 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_AtomViewportDisplayInfo, AZ::Render::AtomViewportDisplayInfoModule)

@ -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(AtomViewportDisplayInfoSanityTest, Sanity)
{
EXPECT_EQ(1, 1);
}

@ -0,0 +1,16 @@
#
# 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/AtomViewportDisplayInfoSystemComponent.cpp
Source/AtomViewportDisplayInfoSystemComponent.h
Source/Module.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
)

@ -0,0 +1,12 @@
{
"gem_name": "AtomLyIntegration_AtomViewportDisplayInfo",
"display_name": "Atom Viewport Display Info Overlay",
"summary": "Provides a diagnostic viewport overlay for the default O3DE Atom viewport.",
"canonical_tags": [
"Gem"
],
"user_tags": [
"AtomLyIntegration",
"AtomViewportDisplayInfo"
]
}

@ -16,3 +16,4 @@ add_subdirectory(EMotionFXAtom)
add_subdirectory(AtomFont) add_subdirectory(AtomFont)
add_subdirectory(TechnicalArt) add_subdirectory(TechnicalArt)
add_subdirectory(AtomBridge) add_subdirectory(AtomBridge)
add_subdirectory(AtomViewportDisplayInfo)

@ -160,6 +160,17 @@ namespace Camera
incompatible.push_back(AZ_CRC("CameraService", 0x1dd1caa4)); incompatible.push_back(AZ_CRC("CameraService", 0x1dd1caa4));
} }
void CameraComponentController::Init()
{
m_onViewMatrixChanged = AZ::Event<const AZ::Matrix4x4&>::Handler([this](const AZ::Matrix4x4&)
{
if (!m_updatingTransformFromEntity)
{
AZ::TransformBus::Event(m_entityId, &AZ::TransformInterface::SetWorldTM, m_atomCamera->GetCameraTransform());
}
});
}
void CameraComponentController::Activate(AZ::EntityId entityId) void CameraComponentController::Activate(AZ::EntityId entityId)
{ {
m_entityId = entityId; m_entityId = entityId;
@ -218,6 +229,8 @@ namespace Camera
} }
} }
AZ::RPI::ViewProviderBus::Handler::BusConnect(m_entityId); AZ::RPI::ViewProviderBus::Handler::BusConnect(m_entityId);
m_atomCamera->ConnectWorldToViewMatrixChangedHandler(m_onViewMatrixChanged);
} }
UpdateCamera(); UpdateCamera();
@ -258,6 +271,7 @@ namespace Camera
if (atomViewportRequests) if (atomViewportRequests)
{ {
AZ::RPI::ViewProviderBus::Handler::BusDisconnect(m_entityId); AZ::RPI::ViewProviderBus::Handler::BusDisconnect(m_entityId);
m_onViewMatrixChanged.Disconnect();
} }
DeactivateAtomView(); DeactivateAtomView();
@ -376,7 +390,9 @@ namespace Camera
if (m_atomCamera) if (m_atomCamera)
{ {
m_updatingTransformFromEntity = true;
m_atomCamera->SetCameraTransform(AZ::Matrix3x4::CreateFromTransform(world.GetOrthogonalized())); m_atomCamera->SetCameraTransform(AZ::Matrix3x4::CreateFromTransform(world.GetOrthogonalized()));
m_updatingTransformFromEntity = false;
} }
} }
@ -425,7 +441,9 @@ namespace Camera
m_config.m_nearClipDistance, m_config.m_nearClipDistance,
m_config.m_farClipDistance, m_config.m_farClipDistance,
true); true);
m_updatingTransformFromEntity = true;
m_atomCamera->SetViewToClipMatrix(viewToClipMatrix); m_atomCamera->SetViewToClipMatrix(viewToClipMatrix);
m_updatingTransformFromEntity = false;
} }
} }

@ -77,6 +77,7 @@ namespace Camera
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided); static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible); static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
void Init();
void Activate(AZ::EntityId entityId); void Activate(AZ::EntityId entityId);
void Deactivate(); void Deactivate();
void SetConfiguration(const CameraComponentConfig& config); void SetConfiguration(const CameraComponentConfig& config);
@ -121,6 +122,8 @@ namespace Camera
// Atom integration // Atom integration
AZ::RPI::ViewPtr m_atomCamera; AZ::RPI::ViewPtr m_atomCamera;
AZ::RPI::AuxGeomDrawPtr m_atomAuxGeom; AZ::RPI::AuxGeomDrawPtr m_atomAuxGeom;
AZ::Event<const AZ::Matrix4x4&>::Handler m_onViewMatrixChanged;
bool m_updatingTransformFromEntity = false;
// Cry view integration // Cry view integration
IView* m_view = nullptr; IView* m_view = nullptr;

Loading…
Cancel
Save