Files
o3de/Gems/AtomLyIntegration/AtomBridge/Code/Source/AtomDebugDisplayViewportInterface.h
T
rgba16f d4bad61f9a DebugDraw gem fixes for Atom (#885)
* Work in progress on adapting the DebugDraw gem to use AzFramework::DebugDisplayRequests API

* Cleanup fixes for DebugDisplayRequestBus & DebugDraw gem.

Remove SandboxIntegration implementation of the DebugDisplayRequestBus
Add DrawWireCylinder & DrawWireCone to the DebugDisplayRequestBus interface
Remove SetFillMode & DrawTexture functions from the DebugDisplayRequestBus interface
Fixup uses of the SetFillMode api, replace with new Draw[Wire|Solid]X functions.
Fixes to the DebugDraw gem to get it compiling with new warnings settings.

* Changes to get the DebugDraw gem working with Atom/RHI/Code/Include/Atom/RHI

Add GetWidth, GetHeight, GetDepth utility accessors to RHI::Viewport
Start cleaning out unnecessary Cry includes from DebugDraw gem
Fixes for AtomFont FFont.cpp 3d screen aligned text drawing.
Clean out no longer supported code for 3d text to render multiple strings for the same entity location

* Cleanup some unused or commented code

* Update with PR feedback from Nick Van Sickle
2021-05-24 16:49:00 -05:00

374 lines
18 KiB
C++

/*
* 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>
#include <Atom/RPI.Public/ViewportContextBus.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
// separate tracking for Cry only state
bool m_drawInFront = false;
bool m_2dMode = false;
};
//! 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 Draw2d(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 = auxGeomDrawPtr->GetOrAdd2DViewProjOverride();
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 Draw2d(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::RPI::ViewportContextIdNotificationBus::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) 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 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 DrawWireOBB(const AZ::Vector3& center, const AZ::Vector3& axisX, const AZ::Vector3& axisY, const AZ::Vector3& axisZ, const AZ::Vector3& halfExtents) 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 DrawWireCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height) override;
void DrawSolidCone(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;
void SetLineWidth(float width) override;
bool IsVisible(const AZ::Aabb& bounds) 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;
void PushMatrix(const AZ::Transform& tm) override;
void PopMatrix() override;
private:
// ViewportContextIdNotificationBus handlers
void OnViewportDefaultViewChanged(AZ::RPI::ViewPtr view) override;
// internal helper functions
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); }
//! Convert positions to world space.
AZStd::vector<AZ::Vector3> ToWorldSpacePosition(const AZStd::vector<AZ::Vector3>& positions) const;
//! Convert directions to world space (translation is not considered)
AZStd::vector<AZ::Vector3> ToWorldSpaceVector(const AZStd::vector<AZ::Vector3>& vectors) const;
void CalcBasisVectors(const AZ::Vector3& n, AZ::Vector3& b1, AZ::Vector3& b2) const;
const AZ::Matrix3x4& GetCurrentTransform() const;
void UpdateAuxGeom(RPI::Scene* scene, AZ::RPI::View* view);
void InitInternal(RPI::Scene* scene, AZ::RPI::ViewportContextPtr viewportContextPtr);
AZ::RPI::ViewportContextPtr GetViewportContext() const;
uint32_t ConvertRenderStateToCry() const;
RenderState m_rendState;
AZ::RPI::AuxGeomDrawPtr m_auxGeomPtr;
// m_defaultInstance is true for the instance that multicasts the debug draws to all viewports
// (with an AuxGeom render pass) in the default scene.
bool m_defaultInstance = false;
AzFramework::ViewportId m_viewportId = AzFramework::InvalidViewportId; // Address this instance answers on.
AZ::RPI::ViewportContext::SceneChangedEvent::Handler m_sceneChangeHandler;
};
// 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