56904d1799
* Generic Cleanup Removals: * Unused cvars,member variables and defines * Windows media center edition support routines * CSystem - removed debug_GetCallStackRaw/GetRootWindowMessageHandler/ UnloadDLL/ShutdownModuleLibraries Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix CryMessageBox return values in Windows build Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove named selection group and a few smaller unused functionalities Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove ObjectManager export functionality + 2 deprecated functions Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove object legacy freeze/hide support from ObjectManager Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove ObjectManager duplicate name dection, as well as object renaming Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove ObjectManager serialization and selection callbacks Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * ObjectManager - remove MoveObjects/HitTestObject/EndEditParams and related members/functions Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove a bunch of unused clone related functionality + misc Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * ObjectManager - misc removals Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * ObjectManager - more removals Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove unused object selection/retrieval in ObjectManager and LoadObjects in ObjectLoader Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * CBaseObject - remove unused material layers mask support Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * More CBaseObject cleanups. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * CBaseObject - remove SubObj functions and IMouseCreateCallback Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove unused procedural floor management, helper scale and tags. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * CBaseObject - remove more unused methods. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Removals in multiple places. CBaseObject - unused `OBJTYPE_DUMMY` flag removed, member `IsSameClass` CObjectArchive removed unused methods/members CObjectManager removed unused `Update` method Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * More removals IDisplayViewport - HitTestLine/GetGridStep/setHitcontext/ GetConstructionPlane Unused Cry_Matrix44 template specializations. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * O3DE.exe Project-Centric "Open Editor" fix (#5852) * The O3DE.exe Open Editor button now attempts to open the Editor in the build directory of the project being opened. If their is no Editor within the build directory of the Project, it uses the Editor.exe in the current O3DE.exe executable directory if it exists Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Engine .gitignore now ignores the build directory if placed in the AutomatedTesting project Previously it was just ignoring a `[Bb]uild` directory if it was directly within the engine root. This change matches the behavior of the project templates. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Renamed the ProjectUtils GetEditorDirectory function to GetEditorExecutablePath Added a platform specific implementation for retrieving the path to the Editor executable in the GetEditorExectuablePath function. It first attempts to locate the Editor via checking the project build directory for an Editor executable before falling back to checking the binary directory of the currently running O3DE executable. Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> * Correct the MacOS GetEditorExecutablePath to return the Editor path Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Adding missing C++20 std::erase implementations (#5735) There were already implementations for std::erase_if. This adds the counterpart AZStd::erase versions resolves #5734 Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com> Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * More removals and refactors `ShowMessage` and `CryMessageBox` return void now Simplify code in `CSystem::WarningV` Remove unused `CryGetTicksPerSec` Remove unused WinBase functionality Replace `nanosleep` call in WinBase with `std::this_thread::sleep_for` Remove unused Win32Wrapper routines Remove unused IFunctorBase.h and IEntityObjectListener.h Fix VectorAndArray.cpp compilation Use QMessageBox instead of CryMessageBox in the editor. Remove empty ArchiveVars platform specific files Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Fix test code. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove an unused function Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * CBaseObject and undo description removals. Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * A bunch of removals * Remove IRenderNode * Remove editor's KDTree * Remove StatObjBus, InstanceStatObjEventBus::ReleaseData is redundant ( same functionality in the only available handler is triggered by `OnCryEditorCloseScene`) * Remove CExportManager::AddStatObj/AddMeshes/AddMesh, IExportManager::ExportSingleStatObj * Remove CIconManager/IIconManager::GetObject * Remove CBaseObject::IntersectRayMesh * Remove IIndexedMesh and related structs. * Unused IUndoObject::GetDescription and all derived implementations. * Unused CUndoBaseLibrary/CUndoBaseLibraryManager * Unused Matrix34_tpl typedefs * Legacy Xml classes cleanup Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * Remove unused `Vec3ToVector3D` helper Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> * fix - remove unused static variable Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com> Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
1339 lines
46 KiB
C++
1339 lines
46 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
|
|
#include <Cry_Geo.h>
|
|
#include "DisplayContext.h"
|
|
#include "IRenderAuxGeom.h"
|
|
#include "IEditor.h"
|
|
#include "Include/IIconManager.h"
|
|
#include "Include/IDisplayViewport.h"
|
|
#include <Editor/Util/EditorUtils.h>
|
|
|
|
#include <QDateTime>
|
|
#include <QPoint>
|
|
|
|
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
|
|
|
|
#define FREEZE_COLOR QColor(100, 100, 100)
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
DisplayContext::DisplayContext()
|
|
{
|
|
view = 0;
|
|
flags = 0;
|
|
settings = 0;
|
|
pIconManager = 0;
|
|
m_renderState = 0;
|
|
|
|
m_currentMatrix = 0;
|
|
m_matrixStack[m_currentMatrix].SetIdentity();
|
|
pRenderAuxGeom = nullptr; // ToDo: Remove DisplayContext or update to work with Atom: LYN-3670
|
|
m_thickness = 0;
|
|
|
|
m_width = 0;
|
|
m_height = 0;
|
|
|
|
m_textureLabels.reserve(100);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::SetView(IDisplayViewport* pView)
|
|
{
|
|
view = pView;
|
|
int width, height;
|
|
view->GetDimensions(&width, &height);
|
|
m_width = static_cast<float>(width);
|
|
m_height = static_cast<float>(height);
|
|
m_textureLabels.resize(0);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::InternalDrawLine(const Vec3& v0, const ColorB& colV0, const Vec3& v1, const ColorB& colV1)
|
|
{
|
|
pRenderAuxGeom->DrawLine(v0, colV0, v1, colV1, m_thickness);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawPoint(const Vec3& p, int nSize)
|
|
{
|
|
pRenderAuxGeom->DrawPoint(ToWorldSpacePosition(p), m_color4b, static_cast<uint8>(nSize));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawTri(const Vec3& p1, const Vec3& p2, const Vec3& p3)
|
|
{
|
|
pRenderAuxGeom->DrawTriangle(ToWorldSpacePosition(p1), m_color4b, ToWorldSpacePosition(p2), m_color4b, ToWorldSpacePosition(p3), m_color4b);
|
|
}
|
|
|
|
void DisplayContext::DrawTriangles(const AZStd::vector<Vec3>& vertices, const ColorB& color)
|
|
{
|
|
pRenderAuxGeom->DrawTriangles(vertices.begin(), static_cast<uint32>(vertices.size()), color);
|
|
}
|
|
|
|
void DisplayContext::DrawTrianglesIndexed(const AZStd::vector<Vec3>& vertices, const AZStd::vector<vtx_idx>& indices, const ColorB& color)
|
|
{
|
|
pRenderAuxGeom->DrawTriangles(vertices.begin(), static_cast<uint32>(vertices.size()), indices.begin(), static_cast<uint32_t>(indices.size()), color);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawQuad(const Vec3& p1, const Vec3& p2, const Vec3& p3, const Vec3& p4)
|
|
{
|
|
Vec3 p[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) };
|
|
pRenderAuxGeom->DrawTriangle(p[0], m_color4b, p[1], m_color4b, p[2], m_color4b);
|
|
pRenderAuxGeom->DrawTriangle(p[2], m_color4b, p[3], m_color4b, p[0], m_color4b);
|
|
}
|
|
|
|
void DisplayContext::DrawQuad(float width, float height)
|
|
{
|
|
pRenderAuxGeom->DrawQuad(width, height, m_matrixStack[m_currentMatrix], m_color4b);
|
|
}
|
|
|
|
void DisplayContext::DrawWireQuad(const Vec3& p1, const Vec3& p2, const Vec3& p3, const Vec3& p4)
|
|
{
|
|
Vec3 p[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) };
|
|
pRenderAuxGeom->DrawPolyline(p, 4, true, m_color4b);
|
|
}
|
|
|
|
void DisplayContext::DrawWireQuad(float width, float height)
|
|
{
|
|
const float halfWidth = width * 0.5f;
|
|
const float halfHeight = height * 0.5f;
|
|
|
|
const Vec3 p[4] =
|
|
{
|
|
ToWorldSpacePosition(Vec3(-halfWidth, 0.0f, halfHeight)),
|
|
ToWorldSpacePosition(Vec3( halfWidth, 0.0f, halfHeight)),
|
|
ToWorldSpacePosition(Vec3( halfWidth, 0.0f, -halfHeight)),
|
|
ToWorldSpacePosition(Vec3(-halfWidth, 0.0f, -halfHeight)),
|
|
};
|
|
pRenderAuxGeom->DrawPolyline(p, 4, true, m_color4b);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawCylinder(const Vec3& p1, const Vec3& p2, float radius, float height)
|
|
{
|
|
Vec3 p[2] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2) };
|
|
Vec3 dir = p[1] - p[0];
|
|
pRenderAuxGeom->DrawCylinder(p[0], dir, radius, height, m_color4b);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawCone(const Vec3& pos, const Vec3& dir, float radius, float height, bool drawShaded /*= true*/)
|
|
{
|
|
const Vec3 worldPos = ToWorldSpacePosition(pos);
|
|
const Vec3 worldDir = ToWorldSpaceVector(dir);
|
|
pRenderAuxGeom->DrawCone(worldPos, worldDir, radius, height, m_color4b, drawShaded);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawWireCylinder(const Vec3& center, const Vec3& axis, float radius, float height)
|
|
{
|
|
if (radius > FLT_EPSILON && height > FLT_EPSILON && axis.GetLengthSquared() > FLT_EPSILON)
|
|
{
|
|
Vec3 axisNormalized = axis.GetNormalized();
|
|
|
|
// Draw circles at bottom & top of cylinder
|
|
Vec3 centerToTop = axisNormalized * height * 0.5f;
|
|
Vec3 circle1Center = center - centerToTop;
|
|
Vec3 circle2Center = center + centerToTop;
|
|
// DrawArc() takes local coordinates
|
|
DrawArc(circle1Center, radius, 0.0f, 360.0f, 22.5f, axisNormalized);
|
|
DrawArc(circle2Center, radius, 0.0f, 360.0f, 22.5f, axisNormalized);
|
|
|
|
// Draw 4 lines up side of cylinder
|
|
Vec3 rightDirNormalized, frontDirNormalized;
|
|
GetBasisVectors(axisNormalized, rightDirNormalized, frontDirNormalized);
|
|
Vec3 centerToRightEdge = rightDirNormalized * radius;
|
|
Vec3 centerToFrontEdge = frontDirNormalized * radius;
|
|
// InternalDrawLine() takes world coordinates
|
|
InternalDrawLine(ToWorldSpacePosition(circle1Center + centerToRightEdge), m_color4b,
|
|
ToWorldSpacePosition(circle2Center + centerToRightEdge), m_color4b);
|
|
InternalDrawLine(ToWorldSpacePosition(circle1Center - centerToRightEdge), m_color4b,
|
|
ToWorldSpacePosition(circle2Center - centerToRightEdge), m_color4b);
|
|
InternalDrawLine(ToWorldSpacePosition(circle1Center + centerToFrontEdge), m_color4b,
|
|
ToWorldSpacePosition(circle2Center + centerToFrontEdge), m_color4b);
|
|
InternalDrawLine(ToWorldSpacePosition(circle1Center - centerToFrontEdge), m_color4b,
|
|
ToWorldSpacePosition(circle2Center - centerToFrontEdge), m_color4b);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawSolidCylinder(const Vec3& center, const Vec3& axis, float radius, float height, bool drawShaded)
|
|
{
|
|
if (radius > FLT_EPSILON && height > FLT_EPSILON && axis.GetLengthSquared() > FLT_EPSILON)
|
|
{
|
|
// transform everything to world space
|
|
Vec3 wsCenter = ToWorldSpacePosition(center);
|
|
|
|
// determine scale in dir direction, apply to height
|
|
Vec3 axisNormalized = axis.GetNormalized();
|
|
Vec3 wsAxis = ToWorldSpaceVector(axisNormalized);
|
|
float wsAxisLength = wsAxis.GetLength();
|
|
float wsHeight = height * wsAxisLength;
|
|
|
|
// determine scale in orthogonal direction, apply to radius
|
|
Vec3 radiusDirNormalized = axisNormalized.GetOrthogonal();
|
|
radiusDirNormalized.Normalize();
|
|
Vec3 wsRadiusDir = ToWorldSpaceVector(radiusDirNormalized);
|
|
float wsRadiusDirLen = wsRadiusDir.GetLength();
|
|
float wsRadius = radius * wsRadiusDirLen;
|
|
|
|
pRenderAuxGeom->DrawCylinder(wsCenter, wsAxis, wsRadius, wsHeight, m_color4b, drawShaded);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void DisplayContext::DrawWireCapsule(const Vec3& center, const Vec3& axis, float radius, float heightStraightSection)
|
|
{
|
|
if (radius > FLT_EPSILON && axis.GetLengthSquared() > FLT_EPSILON)
|
|
{
|
|
Vec3 axisNormalized = axis.GetNormalizedFast();
|
|
|
|
// Draw cylinder part (or just a circle around the middle)
|
|
if (heightStraightSection > FLT_EPSILON)
|
|
{
|
|
DrawWireCylinder(center, axis, radius, heightStraightSection);
|
|
}
|
|
else
|
|
{
|
|
DrawArc(center, radius, 0.0f, 360.0f, 22.5f, axisNormalized);
|
|
}
|
|
|
|
// Draw top cap as two criss-crossing 180deg arcs
|
|
Vec3 ortho1Normalized, ortho2Normalized;
|
|
GetBasisVectors(axisNormalized, ortho1Normalized, ortho2Normalized);
|
|
Vec3 centerToTopCircleCenter = axisNormalized * heightStraightSection * 0.5f;
|
|
DrawArc(center + centerToTopCircleCenter, radius, 90.0f, 180.0f, 22.5f, ortho1Normalized);
|
|
DrawArc(center + centerToTopCircleCenter, radius, 180.0f, 180.0f, 22.5f, ortho2Normalized);
|
|
|
|
// Draw bottom cap
|
|
DrawArc(center - centerToTopCircleCenter, radius, -90.0f, 180.0f, 22.5f, ortho1Normalized);
|
|
DrawArc(center - centerToTopCircleCenter, radius, 0.0f, 180.0f, 22.5f, ortho2Normalized);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawWireBox(const Vec3& min, const Vec3& max)
|
|
{
|
|
pRenderAuxGeom->DrawAABB(AABB(min, max), m_matrixStack[m_currentMatrix], false, m_color4b, eBBD_Faceted);
|
|
}
|
|
|
|
void DisplayContext::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max)
|
|
{
|
|
pRenderAuxGeom->DrawAABB(
|
|
AABB(Vec3(min.GetX(), min.GetY(), min.GetZ()), Vec3(max.GetX(), max.GetY(), max.GetZ())),
|
|
m_matrixStack[m_currentMatrix], false, m_color4b, eBBD_Faceted);
|
|
}
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawSolidBox(const Vec3& min, const Vec3& max)
|
|
{
|
|
pRenderAuxGeom->DrawAABB(AABB(min, max), m_matrixStack[m_currentMatrix], true, m_color4b, eBBD_Faceted);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawSolidOBB(const Vec3& center, const Vec3& axisX, const Vec3& axisY, const Vec3& axisZ, const Vec3& halfExtents)
|
|
{
|
|
OBB obb;
|
|
obb.m33 = Matrix33::CreateFromVectors(axisX, axisY, axisZ);
|
|
obb.c = Vec3(0, 0, 0);
|
|
obb.h = halfExtents;
|
|
pRenderAuxGeom->DrawOBB(obb, center, true, m_color4b, eBBD_Faceted);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawLine(const Vec3& p1, const Vec3& p2)
|
|
{
|
|
InternalDrawLine(ToWorldSpacePosition(p1), m_color4b, ToWorldSpacePosition(p2), m_color4b);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawPolyLine(const Vec3* pnts, int numPoints, bool cycled)
|
|
{
|
|
MAKE_SURE(numPoints >= 2, return );
|
|
MAKE_SURE(pnts != 0, return );
|
|
|
|
int numSegments = cycled ? numPoints : (numPoints - 1);
|
|
Vec3 p1 = ToWorldSpacePosition(pnts[0]);
|
|
Vec3 p2;
|
|
for (int i = 0; i < numSegments; i++)
|
|
{
|
|
int j = (i + 1) % numPoints;
|
|
p2 = ToWorldSpacePosition(pnts[j]);
|
|
InternalDrawLine(p1, m_color4b, p2, m_color4b);
|
|
p1 = p2;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawTerrainCircle(const Vec3& worldPos, float radius, float height)
|
|
{
|
|
auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
|
|
// Draw circle with default radius.
|
|
Vec3 p0, p1;
|
|
p0.x = worldPos.x + radius * sin(0.0f);
|
|
p0.y = worldPos.y + radius * cos(0.0f);
|
|
const float defaultTerrainElevation = AzFramework::Terrain::TerrainDataRequests::GetDefaultTerrainHeight();
|
|
float terrainElevation = terrain ? terrain->GetHeightFromFloats(p0.x, p0.y) : defaultTerrainElevation;
|
|
p0.z = terrainElevation + height;
|
|
|
|
float step = 20.0f / 180 * gf_PI;
|
|
for (float angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = worldPos.x + radius * sin(angle);
|
|
p1.y = worldPos.y + radius * cos(angle);
|
|
terrainElevation = terrain ? terrain->GetHeightFromFloats(p1.x, p1.y) : defaultTerrainElevation;
|
|
p1.z = terrainElevation + height;
|
|
|
|
InternalDrawLine(ToWorldSpacePosition(p0), m_color4b, ToWorldSpacePosition(p1), m_color4b);
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawTerrainCircle(const Vec3& worldPos, float radius, float angle1, float angle2, float height)
|
|
{
|
|
auto terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
|
|
// Draw circle with default radius.
|
|
Vec3 p0, p1;
|
|
p0.x = worldPos.x + radius * sin(angle1);
|
|
p0.y = worldPos.y + radius * cos(angle1);
|
|
float terrainElevation = terrain ? terrain->GetHeightFromFloats(p0.x, p0.y) : 0.0f;
|
|
p0.z = terrainElevation + height;
|
|
|
|
float step = 20.0f / 180 * gf_PI;
|
|
for (float angle = step + angle1; angle < angle2; angle += step)
|
|
{
|
|
p1.x = worldPos.x + radius * sin(angle);
|
|
p1.y = worldPos.y + radius * cos(angle);
|
|
terrainElevation = terrain ? terrain->GetHeightFromFloats(p1.x, p1.y) : 0.0f;
|
|
p1.z = terrainElevation + height;
|
|
|
|
InternalDrawLine(ToWorldSpacePosition(p0), m_color4b, ToWorldSpacePosition(p1), m_color4b);
|
|
p0 = p1;
|
|
}
|
|
|
|
p1.x = worldPos.x + radius * sin(angle2);
|
|
p1.y = worldPos.y + radius * cos(angle2);
|
|
terrainElevation = terrain ? terrain->GetHeightFromFloats(p1.x, p1.y) : 0.0f;
|
|
p1.z = terrainElevation + height;
|
|
|
|
InternalDrawLine(ToWorldSpacePosition(p0), m_color4b, ToWorldSpacePosition(p1), m_color4b);
|
|
}
|
|
|
|
|
|
void DisplayContext::DrawArc(const Vec3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, int referenceAxis)
|
|
{
|
|
// angularStepDegrees cannot be zero as it is used to divide sweepAngleDegrees
|
|
if (fabs(angularStepDegrees) < FLT_EPSILON)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float startAngleRadians = DEG2RAD(startAngleDegrees);
|
|
float sweepAngleRadians = DEG2RAD(sweepAngleDegrees);
|
|
|
|
float angle = startAngleRadians;
|
|
|
|
const uint referenceAxis0 = referenceAxis % 3;
|
|
const uint referenceAxis1 = (referenceAxis + 1) % 3;
|
|
const uint referenceAxis2 = (referenceAxis + 2) % 3;
|
|
|
|
Vec3 p0;
|
|
p0[referenceAxis0] = pos[referenceAxis0];
|
|
p0[referenceAxis1] = pos[referenceAxis1] + radius * sin(angle);
|
|
p0[referenceAxis2] = pos[referenceAxis2] + radius * cos(angle);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
|
|
float step = DEG2RAD(angularStepDegrees);
|
|
int numSteps = std::abs(static_cast<int>(std::ceil(sweepAngleRadians / step)));
|
|
|
|
Vec3 p1;
|
|
for (int i = 0; i < numSteps; ++i)
|
|
{
|
|
angle += std::min(step, sweepAngleRadians); // Don't go past sweepAngleRadians when stepping or the arc will be too long.
|
|
sweepAngleRadians -= step;
|
|
|
|
p1[referenceAxis0] = pos[referenceAxis0];
|
|
p1[referenceAxis1] = pos[referenceAxis1] + radius * sin(angle);
|
|
p1[referenceAxis2] = pos[referenceAxis2] + radius * cos(angle);
|
|
p1 = ToWorldSpacePosition(p1);
|
|
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
void DisplayContext::DrawArc(const Vec3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, const Vec3& fixedAxis)
|
|
{
|
|
// angularStepDegrees cannot be zero as it is used to divide sweepAngleDegrees
|
|
if (fabs(angularStepDegrees) < FLT_EPSILON)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float startAngleRadians = DEG2RAD(startAngleDegrees);
|
|
float sweepAngleRadians = DEG2RAD(sweepAngleDegrees);
|
|
|
|
Vec3 a;
|
|
Vec3 b;
|
|
GetBasisVectors(fixedAxis, a, b);
|
|
|
|
float angle = startAngleRadians;
|
|
|
|
float cosAngle = cos(angle) * radius;
|
|
float sinAngle = sin(angle) * radius;
|
|
|
|
Vec3 p0;
|
|
p0.x = pos.x + cosAngle * a.x + sinAngle * b.x;
|
|
p0.y = pos.y + cosAngle * a.y + sinAngle * b.y;
|
|
p0.z = pos.z + cosAngle * a.z + sinAngle * b.z;
|
|
p0 = ToWorldSpacePosition(p0);
|
|
|
|
float step = DEG2RAD(angularStepDegrees);
|
|
int numSteps = std::abs(static_cast<int>(std::ceil(sweepAngleRadians / step)));
|
|
|
|
Vec3 p1;
|
|
for (int i = 0; i < numSteps; ++i)
|
|
{
|
|
angle += std::min(step, sweepAngleRadians); // Don't go past sweepAngleRadians when stepping or the arc will be too long.
|
|
sweepAngleRadians -= step;
|
|
|
|
float cosAngle2 = cos(angle) * radius;
|
|
float sinAngle2 = sin(angle) * radius;
|
|
|
|
p1.x = pos.x + cosAngle2 * a.x + sinAngle2 * b.x;
|
|
p1.y = pos.y + cosAngle2 * a.y + sinAngle2 * b.y;
|
|
p1.z = pos.z + cosAngle2 * a.z + sinAngle2 * b.z;
|
|
p1 = ToWorldSpacePosition(p1);
|
|
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Vera, Confetti
|
|
void DisplayContext::DrawArcWithArrow(const Vec3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, const Vec3& fixedAxis)
|
|
{
|
|
// angularStepDegrees cannot be zero as it is used to divide sweepAngleDegrees
|
|
// Grab the code from draw arc to get the final p0 and p1;
|
|
if (fabs(angularStepDegrees) < FLT_EPSILON)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float startAngleRadians = DEG2RAD(startAngleDegrees);
|
|
float sweepAngleRadians = DEG2RAD(sweepAngleDegrees);
|
|
|
|
Vec3 a;
|
|
Vec3 b;
|
|
GetBasisVectors(fixedAxis, a, b);
|
|
|
|
float angle = startAngleRadians;
|
|
|
|
float cosAngle = cos(angle) * radius;
|
|
float sinAngle = sin(angle) * radius;
|
|
|
|
Vec3 p0;
|
|
p0.x = pos.x + cosAngle * a.x + sinAngle * b.x;
|
|
p0.y = pos.y + cosAngle * a.y + sinAngle * b.y;
|
|
p0.z = pos.z + cosAngle * a.z + sinAngle * b.z;
|
|
p0 = ToWorldSpacePosition(p0);
|
|
|
|
float step = DEG2RAD(angularStepDegrees);
|
|
int numSteps = std::abs(static_cast<int>(std::ceil(sweepAngleRadians / step)));
|
|
|
|
Vec3 p1;
|
|
for (int i = 0; i < numSteps; ++i)
|
|
{
|
|
angle += step;
|
|
float cosAngle2 = cos(angle) * radius;
|
|
float sinAngle2 = sin(angle) * radius;
|
|
|
|
p1.x = pos.x + cosAngle2 * a.x + sinAngle2 * b.x;
|
|
p1.y = pos.y + cosAngle2 * a.y + sinAngle2 * b.y;
|
|
p1.z = pos.z + cosAngle2 * a.z + sinAngle2 * b.z;
|
|
p1 = ToWorldSpacePosition(p1);
|
|
|
|
if (i + 1 >= numSteps) // For last step, draw an arrow
|
|
{
|
|
// p0 and p1 are global position. We could like to map it to local
|
|
Matrix34 inverseMat = m_matrixStack[m_currentMatrix].GetInverted();
|
|
Vec3 localP0 = inverseMat.TransformPoint(p0);
|
|
Vec3 localP1 = inverseMat.TransformPoint(p1);
|
|
DrawArrow(localP0, localP1, m_thickness);
|
|
}
|
|
else
|
|
{
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
}
|
|
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawCircle(const Vec3& pos, float radius, int nUnchangedAxis)
|
|
{
|
|
// Draw circle with default radius.
|
|
Vec3 p0, p1;
|
|
p0[nUnchangedAxis] = pos[nUnchangedAxis];
|
|
p0[(nUnchangedAxis + 1) % 3] = pos[(nUnchangedAxis + 1) % 3] + radius * sin(0.0f);
|
|
p0[(nUnchangedAxis + 2) % 3] = pos[(nUnchangedAxis + 2) % 3] + radius * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
const float step = 10.0f / 180.0f * gf_PI;
|
|
for (float angle = step; angle < 360.0f / 180.0f * gf_PI + step; angle += step)
|
|
{
|
|
p1[nUnchangedAxis] = pos[nUnchangedAxis];
|
|
p1[(nUnchangedAxis + 1) % 3] = pos[(nUnchangedAxis + 1) % 3] + radius * sin(angle);
|
|
p1[(nUnchangedAxis + 2) % 3] = pos[(nUnchangedAxis + 2) % 3] + radius * cos(angle);
|
|
p1 = ToWorldSpacePosition(p1);
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
void DisplayContext::DrawHalfDottedCircle(const Vec3& pos, float radius, const Vec3& viewPos, int nUnchangedAxis)
|
|
{
|
|
// Draw circle with default radius
|
|
Vec3 p0, p1;
|
|
p0[nUnchangedAxis] = pos[nUnchangedAxis];
|
|
p0[(nUnchangedAxis + 1) % 3] = pos[(nUnchangedAxis + 1) % 3] + radius * sin(0.0f);
|
|
p0[(nUnchangedAxis + 2) % 3] = pos[(nUnchangedAxis + 2) % 3] + radius * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
const Vec3 worldPos = ToWorldSpacePosition(pos);
|
|
const Vec3 worldView = ToWorldSpacePosition(viewPos);
|
|
const float step = 10.0f / 180.0f * gf_PI;
|
|
size_t count = 0;
|
|
for (float angle = step; angle < 360.0f / 180.0f * gf_PI + step; angle += step)
|
|
{
|
|
p1[nUnchangedAxis] = pos[nUnchangedAxis];
|
|
p1[(nUnchangedAxis + 1) % 3] = pos[(nUnchangedAxis + 1) % 3] + radius * sin(angle);
|
|
p1[(nUnchangedAxis + 2) % 3] = pos[(nUnchangedAxis + 2) % 3] + radius * cos(angle);
|
|
p1 = ToWorldSpacePosition(p1);
|
|
// is circle edge facing away from us or not
|
|
const float dot = (p0 - worldPos).Dot(worldView - worldPos);
|
|
const bool facing = dot > 0.0f;
|
|
// if so skip every other line to produce a dotted effect
|
|
if (facing || count % 2 == 0)
|
|
{
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
}
|
|
count++;
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Vera, Confetti
|
|
void DisplayContext::DrawDottedCircle(const Vec3& pos, float radius, const Vec3& nUnchangedAxis, int numberOfArrows /*=0*/, float stepDegree /*= 1*/)
|
|
{
|
|
float startAngleRadians = 0;
|
|
|
|
Vec3 a;
|
|
Vec3 b;
|
|
GetBasisVectors(nUnchangedAxis, a, b);
|
|
|
|
float angle = startAngleRadians;
|
|
|
|
float cosAngle = cos(angle) * radius;
|
|
float sinAngle = sin(angle) * radius;
|
|
|
|
Vec3 p0;
|
|
p0.x = pos.x + cosAngle * a.x + sinAngle * b.x;
|
|
p0.y = pos.y + cosAngle * a.y + sinAngle * b.y;
|
|
p0.z = pos.z + cosAngle * a.z + sinAngle * b.z;
|
|
p0 = ToWorldSpacePosition(p0);
|
|
|
|
float step = DEG2RAD(stepDegree); // one degree each step
|
|
int numSteps = aznumeric_cast<int>(2.0f * gf_PI / step);
|
|
|
|
// Prepare for drawing arrow
|
|
float arrowStep = 0;
|
|
float arrowAngle = 0;
|
|
if (numberOfArrows > 0)
|
|
{
|
|
arrowStep = 2 * gf_PI / numberOfArrows;
|
|
arrowAngle = arrowStep;
|
|
}
|
|
|
|
Vec3 p1;
|
|
for (int i = 0; i < numSteps; ++i)
|
|
{
|
|
angle += step;
|
|
float cosAngle2 = cos(angle) * radius;
|
|
float sinAngle2 = sin(angle) * radius;
|
|
|
|
p1.x = pos.x + cosAngle2 * a.x + sinAngle2 * b.x;
|
|
p1.y = pos.y + cosAngle2 * a.y + sinAngle2 * b.y;
|
|
p1.z = pos.z + cosAngle2 * a.z + sinAngle2 * b.z;
|
|
p1 = ToWorldSpacePosition(p1);
|
|
|
|
|
|
if (arrowStep > 0) // If user want to draw arrow on circle
|
|
{
|
|
// if the arraw should be drawn between current angel and next angel
|
|
if (angle <= arrowAngle && angle + step * 2 > arrowAngle)
|
|
{
|
|
// Get local position from global position
|
|
Matrix34 inverseMat = m_matrixStack[m_currentMatrix].GetInverted();
|
|
Vec3 localP0 = inverseMat.TransformPoint(p0);
|
|
Vec3 localP1 = inverseMat.TransformPoint(p1);
|
|
DrawArrow(localP0, localP1, m_thickness);
|
|
arrowAngle += arrowStep;
|
|
if (arrowAngle > 2 * gf_PI) // if the next arrow angle is greater than 2PI. Stop adding arrow.
|
|
{
|
|
arrowStep = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
|
|
// Skip a step
|
|
angle += step;
|
|
cosAngle2 = cos(angle) * radius;
|
|
sinAngle2 = sin(angle) * radius;
|
|
|
|
p1.x = pos.x + cosAngle2 * a.x + sinAngle2 * b.x;
|
|
p1.y = pos.y + cosAngle2 * a.y + sinAngle2 * b.y;
|
|
p1.z = pos.z + cosAngle2 * a.z + sinAngle2 * b.z;
|
|
p1 = ToWorldSpacePosition(p1);
|
|
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawWireCircle2d(const QPoint& center, float radius, float z)
|
|
{
|
|
Vec3 p0, p1, pos;
|
|
pos.x = static_cast<float>(center.x());
|
|
pos.y = static_cast<float>(center.y());
|
|
pos.z = z;
|
|
p0.x = pos.x + radius * sin(0.0f);
|
|
p0.y = pos.y + radius * cos(0.0f);
|
|
p0.z = z;
|
|
float step = 10.0f / 180 * gf_PI;
|
|
|
|
int prevState = GetState();
|
|
//SetState( (prevState|e_Mode2D) & (~e_Mode3D) );
|
|
for (float angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = pos.x + radius * sin(angle);
|
|
p1.y = pos.y + radius * cos(angle);
|
|
p1.z = z;
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
SetState(prevState);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawWireSphere(const Vec3& pos, float radius)
|
|
{
|
|
Vec3 p0, p1;
|
|
float step = 10.0f / 180 * gf_PI;
|
|
float angle;
|
|
|
|
// Z Axis
|
|
p0 = pos;
|
|
p1 = pos;
|
|
p0.x += radius * sin(0.0f);
|
|
p0.y += radius * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
for (angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = pos.x + radius * sin(angle);
|
|
p1.y = pos.y + radius * cos(angle);
|
|
p1.z = pos.z;
|
|
p1 = ToWorldSpacePosition(p1);
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
|
|
// X Axis
|
|
p0 = pos;
|
|
p1 = pos;
|
|
p0.y += radius * sin(0.0f);
|
|
p0.z += radius * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
for (angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = pos.x;
|
|
p1.y = pos.y + radius * sin(angle);
|
|
p1.z = pos.z + radius * cos(angle);
|
|
p1 = ToWorldSpacePosition(p1);
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
|
|
// Y Axis
|
|
p0 = pos;
|
|
p1 = pos;
|
|
p0.x += radius * sin(0.0f);
|
|
p0.z += radius * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
for (angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = pos.x + radius * sin(angle);
|
|
p1.y = pos.y;
|
|
p1.z = pos.z + radius * cos(angle);
|
|
p1 = ToWorldSpacePosition(p1);
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawWireSphere(const Vec3& pos, const Vec3 radius)
|
|
{
|
|
Vec3 p0, p1;
|
|
float step = 10.0f / 180 * gf_PI;
|
|
float angle;
|
|
|
|
// Z Axis
|
|
p0 = pos;
|
|
p1 = pos;
|
|
p0.x += radius.x * sin(0.0f);
|
|
p0.y += radius.y * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
for (angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = pos.x + radius.x * sin(angle);
|
|
p1.y = pos.y + radius.y * cos(angle);
|
|
p1.z = pos.z;
|
|
p1 = ToWorldSpacePosition(p1);
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
|
|
// X Axis
|
|
p0 = pos;
|
|
p1 = pos;
|
|
p0.y += radius.y * sin(0.0f);
|
|
p0.z += radius.z * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
for (angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = pos.x;
|
|
p1.y = pos.y + radius.y * sin(angle);
|
|
p1.z = pos.z + radius.z * cos(angle);
|
|
p1 = ToWorldSpacePosition(p1);
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
|
|
// Y Axis
|
|
p0 = pos;
|
|
p1 = pos;
|
|
p0.x += radius.x * sin(0.0f);
|
|
p0.z += radius.z * cos(0.0f);
|
|
p0 = ToWorldSpacePosition(p0);
|
|
for (angle = step; angle < 360.0f / 180 * gf_PI + step; angle += step)
|
|
{
|
|
p1.x = pos.x + radius.x * sin(angle);
|
|
p1.y = pos.y;
|
|
p1.z = pos.z + radius.z * cos(angle);
|
|
p1 = ToWorldSpacePosition(p1);
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
p0 = p1;
|
|
}
|
|
}
|
|
|
|
void DisplayContext::DrawWireDisk(const Vec3& pos, const Vec3& dir, float radius)
|
|
{
|
|
// Draw circle
|
|
DrawArc(pos, radius, 0.0f, 360.0f, 11.25f, dir);
|
|
|
|
// Draw disk direction normal from center.
|
|
DrawLine(pos, pos + dir * radius * 0.2f);
|
|
}
|
|
|
|
void DisplayContext::DrawWireQuad2d(const QPoint& pmin, const QPoint& pmax, float z)
|
|
{
|
|
int prevState = GetState();
|
|
SetState((prevState | e_Mode2D) & (~e_Mode3D));
|
|
float minX = static_cast<float>(pmin.x());
|
|
float minY = static_cast<float>(pmin.y());
|
|
float maxX = static_cast<float>(pmax.x());
|
|
float maxY = static_cast<float>(pmax.y());
|
|
InternalDrawLine(Vec3(minX, minY, z), m_color4b, Vec3(maxX, minY, z), m_color4b);
|
|
InternalDrawLine(Vec3(maxX, minY, z), m_color4b, Vec3(maxX, maxY, z), m_color4b);
|
|
InternalDrawLine(Vec3(maxX, maxY, z), m_color4b, Vec3(minX, maxY, z), m_color4b);
|
|
InternalDrawLine(Vec3(minX, maxY, z), m_color4b, Vec3(minX, minY, z), m_color4b);
|
|
SetState(prevState);
|
|
}
|
|
|
|
void DisplayContext::DrawLine2d(const QPoint& p1, const QPoint& p2, float z)
|
|
{
|
|
int prevState = GetState();
|
|
|
|
SetState((prevState | e_Mode2D) & (~e_Mode3D));
|
|
|
|
// If we don't have correct information, we try to get it, but while we
|
|
// don't, we skip rendering this frame.
|
|
if (m_width == 0 || m_height == 0)
|
|
{
|
|
if (view)
|
|
{
|
|
// We tell the window to update itself, as it might be needed to
|
|
// get correct information.
|
|
view->Update();
|
|
int width, height;
|
|
view->GetDimensions(&width, &height);
|
|
m_width = static_cast<float>(width);
|
|
m_height = static_cast<float>(height);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
InternalDrawLine(Vec3(p1.x() / m_width, p1.y() / m_height, z), m_color4b, Vec3(p2.x() / m_width, p2.y() / m_height, z), m_color4b);
|
|
}
|
|
|
|
SetState(prevState);
|
|
}
|
|
|
|
void DisplayContext::DrawLine2dGradient(const QPoint& p1, const QPoint& p2, float z, ColorB firstColor, ColorB secondColor)
|
|
{
|
|
int prevState = GetState();
|
|
|
|
SetState((prevState | e_Mode2D) & (~e_Mode3D));
|
|
InternalDrawLine(Vec3(p1.x() / m_width, p1.y() / m_height, z), firstColor, Vec3(p2.x() / m_width, p2.y() / m_height, z), secondColor);
|
|
SetState(prevState);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawQuadGradient(const Vec3& p1, const Vec3& p2, const Vec3& p3, const Vec3& p4, ColorB firstColor, ColorB secondColor)
|
|
{
|
|
Vec3 p[4] = { ToWorldSpacePosition(p1), ToWorldSpacePosition(p2), ToWorldSpacePosition(p3), ToWorldSpacePosition(p4) };
|
|
pRenderAuxGeom->DrawTriangle(p[0], firstColor, p[1], firstColor, p[2], secondColor);
|
|
pRenderAuxGeom->DrawTriangle(p[2], secondColor, p[3], secondColor, p[0], firstColor);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QColor DisplayContext::GetSelectedColor()
|
|
{
|
|
float t = aznumeric_cast<float>(QDateTime::currentMSecsSinceEpoch() / 1000);
|
|
float r1 = fabs(sin(t * 8.0f));
|
|
if (r1 > 255)
|
|
{
|
|
r1 = 255;
|
|
}
|
|
return QColor(255, 0, aznumeric_cast<int>(r1 * 255));
|
|
// float r2 = cos(t*3);
|
|
//dc.renderer->SetMaterialColor( 1,0,r1,0.5f );
|
|
}
|
|
|
|
QColor DisplayContext::GetFreezeColor()
|
|
{
|
|
return FREEZE_COLOR;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::SetSelectedColor(float fAlpha)
|
|
{
|
|
SetColor(GetSelectedColor(), fAlpha);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::SetFreezeColor()
|
|
{
|
|
SetColor(FREEZE_COLOR, 0.5f);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawLine(const Vec3& p1, const Vec3& p2, const ColorF& col1, const ColorF& col2)
|
|
{
|
|
InternalDrawLine(ToWorldSpacePosition(p1), ColorB(col1), ToWorldSpacePosition(p2), ColorB(col2));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawLine(const Vec3& p1, const Vec3& p2, const QColor& rgb1, const QColor& rgb2)
|
|
{
|
|
InternalDrawLine(ToWorldSpacePosition(p1),
|
|
ColorB(static_cast<uint8>(rgb1.red()), static_cast<uint8>(rgb1.green()), static_cast<uint8>(rgb1.blue()), 255),
|
|
ToWorldSpacePosition(p2),
|
|
ColorB(static_cast<uint8>(rgb2.red()), static_cast<uint8>(rgb2.green()), static_cast<uint8>(rgb2.blue()), 255));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawLines(const AZStd::vector<Vec3>& points, const ColorF& color)
|
|
{
|
|
pRenderAuxGeom->DrawLines(points.begin(), static_cast<uint32>(points.size()), color, m_thickness);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Vera, Confetti
|
|
void DisplayContext::DrawDottedLine(const Vec3& p1, const Vec3& p2, [[maybe_unused]] const ColorF& col1, [[maybe_unused]] const ColorF& col2, const float numOfSteps)
|
|
{
|
|
Vec3 direction = Vec3(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
|
|
//We only draw half of a step and leave the other half empty to make it a dotted line.
|
|
Vec3 halfstep = (direction / numOfSteps) * 0.5f;
|
|
Vec3 startPoint = p1;
|
|
|
|
for (int stepCount = 0; stepCount < numOfSteps; stepCount++)
|
|
{
|
|
InternalDrawLine(ToWorldSpacePosition(startPoint), m_color4b, ToWorldSpacePosition(startPoint + halfstep), m_color4b);
|
|
startPoint += 2 * halfstep; //skip a half step to make it dotted
|
|
}
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::PushMatrix(const Matrix34& tm)
|
|
{
|
|
assert(m_currentMatrix < 31);
|
|
if (m_currentMatrix < 31)
|
|
{
|
|
m_currentMatrix++;
|
|
m_matrixStack[m_currentMatrix] = m_matrixStack[m_currentMatrix - 1] * tm;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::PopMatrix()
|
|
{
|
|
assert(m_currentMatrix > 0);
|
|
if (m_currentMatrix > 0)
|
|
{
|
|
m_currentMatrix--;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
const Matrix34& DisplayContext::GetMatrix()
|
|
{
|
|
return m_matrixStack[m_currentMatrix];
|
|
}
|
|
|
|
float DisplayContext::ToWorldSpaceMaxScale(float value)
|
|
{
|
|
// get the max scaled value in case the transform on the stack is scaled non-uniformly
|
|
const float transformedValueX = ToWorldSpaceVector(Vec3(value, 0.0f, 0.0f)).GetLength();
|
|
const float transformedValueY = ToWorldSpaceVector(Vec3(0.0f, value, 0.0f)).GetLength();
|
|
const float transformedValueZ = ToWorldSpaceVector(Vec3(0.0f, 0.0f, value)).GetLength();
|
|
return AZ::GetMax(transformedValueX, AZ::GetMax(transformedValueY, transformedValueZ));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawBall(const Vec3& pos, float radius, bool drawShaded)
|
|
{
|
|
pRenderAuxGeom->DrawSphere(
|
|
ToWorldSpacePosition(pos), ToWorldSpaceMaxScale(radius), m_color4b, drawShaded);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawDisk(const Vec3& pos, const Vec3& dir, float radius)
|
|
{
|
|
pRenderAuxGeom->DrawDisk(
|
|
ToWorldSpacePosition(pos), ToWorldSpaceVector(dir), ToWorldSpaceMaxScale(radius), m_color4b);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawArrow(const Vec3& src, const Vec3& trg, float fHeadScale, bool b2SidedArrow)
|
|
{
|
|
float f2dScale = 1.0f;
|
|
float arrowLen = 0.4f * fHeadScale;
|
|
float arrowRadius = 0.1f * fHeadScale;
|
|
if (flags & DISPLAY_2D)
|
|
{
|
|
f2dScale = 1.2f * ToWorldSpaceVector(Vec3(1, 0, 0)).GetLength();
|
|
}
|
|
Vec3 dir = trg - src;
|
|
dir = ToWorldSpaceVector(dir.GetNormalized());
|
|
Vec3 p0 = ToWorldSpacePosition(src);
|
|
Vec3 p1 = ToWorldSpacePosition(trg);
|
|
if (!b2SidedArrow)
|
|
{
|
|
p1 = p1 - dir * arrowLen;
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
pRenderAuxGeom->DrawCone(p1, dir, arrowRadius * f2dScale, arrowLen * f2dScale, m_color4b);
|
|
}
|
|
else
|
|
{
|
|
p0 = p0 + dir * arrowLen;
|
|
p1 = p1 - dir * arrowLen;
|
|
InternalDrawLine(p0, m_color4b, p1, m_color4b);
|
|
pRenderAuxGeom->DrawCone(p0, -dir, arrowRadius * f2dScale, arrowLen * f2dScale, m_color4b);
|
|
pRenderAuxGeom->DrawCone(p1, dir, arrowRadius * f2dScale, arrowLen * f2dScale, m_color4b);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::RenderObject(int objectType, const Vec3& pos, float scale)
|
|
{
|
|
Matrix34 tm;
|
|
tm.SetIdentity();
|
|
|
|
tm = Matrix33::CreateScale(Vec3(scale, scale, scale)) * tm;
|
|
|
|
tm.SetTranslation(pos);
|
|
RenderObject(objectType, tm);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::RenderObject(int, const Matrix34&)
|
|
{
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawTerrainRect(float x1, float y1, float x2, float y2, float height)
|
|
{
|
|
AzFramework::Terrain::TerrainDataRequests* terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
|
|
if (terrain == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Vec3 p1, p2;
|
|
float x, y;
|
|
|
|
float step = MAX(y2 - y1, x2 - x1);
|
|
if (step < 0.1)
|
|
{
|
|
return;
|
|
}
|
|
step = step / 100.0f;
|
|
if (step > 10)
|
|
{
|
|
step /= 10;
|
|
}
|
|
|
|
for (y = y1; y < y2; y += step)
|
|
{
|
|
float ye = min(y + step, y2);
|
|
|
|
p1.x = x1;
|
|
p1.y = y;
|
|
p1.z = terrain->GetHeightFromFloats(p1.x, p1.y) + height;
|
|
|
|
p2.x = x1;
|
|
p2.y = ye;
|
|
p2.z = terrain->GetHeightFromFloats(p2.x, p2.y) + height;
|
|
DrawLine(p1, p2);
|
|
|
|
p1.x = x2;
|
|
p1.y = y;
|
|
p1.z = terrain->GetHeightFromFloats(p1.x, p1.y) + height;
|
|
|
|
p2.x = x2;
|
|
p2.y = ye;
|
|
p2.z = terrain->GetHeightFromFloats(p2.x, p2.y) + height;
|
|
DrawLine(p1, p2);
|
|
}
|
|
for (x = x1; x < x2; x += step)
|
|
{
|
|
float xe = min(x + step, x2);
|
|
|
|
p1.x = x;
|
|
p1.y = y1;
|
|
p1.z = terrain->GetHeightFromFloats(p1.x, p1.y) + height;
|
|
|
|
p2.x = xe;
|
|
p2.y = y1;
|
|
p2.z = terrain->GetHeightFromFloats(p2.x, p2.y) + height;
|
|
DrawLine(p1, p2);
|
|
|
|
p1.x = x;
|
|
p1.y = y2;
|
|
p1.z = terrain->GetHeightFromFloats(p1.x, p1.y) + height;
|
|
|
|
p2.x = xe;
|
|
p2.y = y2;
|
|
p2.z = terrain->GetHeightFromFloats(p2.x, p2.y) + height;
|
|
DrawLine(p1, p2);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawTerrainLine(Vec3 worldPos1, Vec3 worldPos2)
|
|
{
|
|
worldPos1.z = worldPos2.z = 0;
|
|
|
|
int steps = static_cast<int>((worldPos2 - worldPos1).GetLength() / 4);
|
|
if (steps == 0)
|
|
{
|
|
steps = 1;
|
|
}
|
|
|
|
Vec3 step = (worldPos2 - worldPos1) / static_cast<float>(steps);
|
|
|
|
AzFramework::Terrain::TerrainDataRequests* terrain = AzFramework::Terrain::TerrainDataRequestBus::FindFirstHandler();
|
|
AZ_Assert(terrain != nullptr, "If there's no terrain, %s shouldn't be called", __FUNCTION__);
|
|
|
|
Vec3 p1 = worldPos1;
|
|
p1.z = terrain->GetHeightFromFloats(worldPos1.x, worldPos1.y);
|
|
for (int i = 0; i < steps; ++i)
|
|
{
|
|
Vec3 p2 = p1 + step;
|
|
p2.z = 0.1f + terrain->GetHeightFromFloats(p2.x, p2.y);
|
|
|
|
DrawLine(p1, p2);
|
|
|
|
p1 = p2;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawTextLabel(const Vec3& pos, float size, const char* text, const bool bCenter, [[maybe_unused]] int srcOffsetX, [[maybe_unused]] int scrOffsetY)
|
|
{
|
|
AZ_ErrorOnce(nullptr, false, "DisplayContext::DrawTextLabel needs to be removed/ported to use Atom");
|
|
|
|
#if 0
|
|
ColorF col(m_color4b.r * (1.0f / 255.0f), m_color4b.g * (1.0f / 255.0f), m_color4b.b * (1.0f / 255.0f), m_color4b.a * (1.0f / 255.0f));
|
|
|
|
float fCol[4] = { col.r, col.g, col.b, col.a };
|
|
if (flags & DISPLAY_2D)
|
|
{
|
|
//We need to pass Screen coordinates to Draw2dLabel Function
|
|
Vec3 screenPos = GetView()->GetScreenTM().TransformPoint(pos);
|
|
renderer->Draw2dLabel(screenPos.x, screenPos.y, size, fCol, bCenter, "%s", text);
|
|
}
|
|
else
|
|
{
|
|
renderer->DrawLabelEx(pos, size, fCol, true, true, text);
|
|
}
|
|
#else
|
|
AZ_UNUSED(pos);
|
|
AZ_UNUSED(size);
|
|
AZ_UNUSED(text);
|
|
AZ_UNUSED(bCenter);
|
|
#endif
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter)
|
|
{
|
|
AZ_ErrorOnce(nullptr, false, "DisplayContext::Draw2dTextLabel needs to be removed/ported to use Atom");
|
|
#if 0
|
|
float col[4] = { m_color4b.r * (1.0f / 255.0f), m_color4b.g * (1.0f / 255.0f), m_color4b.b * (1.0f / 255.0f), m_color4b.a * (1.0f / 255.0f) };
|
|
renderer->Draw2dLabel(x, y, size, col, bCenter, "%s", text);
|
|
#else
|
|
AZ_UNUSED(x);
|
|
AZ_UNUSED(y);
|
|
AZ_UNUSED(size);
|
|
AZ_UNUSED(text);
|
|
AZ_UNUSED(bCenter);
|
|
#endif
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::SetLineWidth(float width)
|
|
{
|
|
m_thickness = width;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool DisplayContext::IsVisible(const AABB& bounds)
|
|
{
|
|
if (flags & DISPLAY_2D)
|
|
{
|
|
if (box.IsIntersectBox(bounds))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 DisplayContext::GetState() const
|
|
{
|
|
return m_renderState;
|
|
}
|
|
|
|
//! Set a new render state flags.
|
|
//! @param returns previous render state.
|
|
uint32 DisplayContext::SetState(uint32 state)
|
|
{
|
|
uint32 old = m_renderState;
|
|
m_renderState = state;
|
|
pRenderAuxGeom->SetRenderFlags(m_renderState);
|
|
return old;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DepthTestOff()
|
|
{
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
pRenderAuxGeom->SetRenderFlags((m_renderState | e_DepthTestOff) & (~e_DepthTestOn));
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DepthTestOn()
|
|
{
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
pRenderAuxGeom->SetRenderFlags((m_renderState | e_DepthTestOn) & (~e_DepthTestOff));
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DepthWriteOff()
|
|
{
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
pRenderAuxGeom->SetRenderFlags((m_renderState | e_DepthWriteOff) & (~e_DepthWriteOn));
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DepthWriteOn()
|
|
{
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
pRenderAuxGeom->SetRenderFlags((m_renderState | e_DepthWriteOn) & (~e_DepthWriteOff));
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::CullOff()
|
|
{
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
pRenderAuxGeom->SetRenderFlags((m_renderState | e_CullModeNone) & (~(e_CullModeBack | e_CullModeFront)));
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::CullOn()
|
|
{
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
pRenderAuxGeom->SetRenderFlags((m_renderState | e_CullModeBack) & (~(e_CullModeNone | e_CullModeFront)));
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool DisplayContext::SetDrawInFrontMode(bool bOn)
|
|
{
|
|
int prevState = m_renderState;
|
|
SAuxGeomRenderFlags renderFlags = m_renderState;
|
|
renderFlags.SetDrawInFrontMode((bOn) ? e_DrawInFrontOn : e_DrawInFrontOff);
|
|
pRenderAuxGeom->SetRenderFlags(renderFlags);
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
return (prevState & e_DrawInFrontOn) != 0;
|
|
}
|
|
|
|
int DisplayContext::SetFillMode(int nFillMode)
|
|
{
|
|
int prevState = m_renderState;
|
|
SAuxGeomRenderFlags renderFlags = m_renderState;
|
|
renderFlags.SetFillMode((EAuxGeomPublicRenderflags_FillMode)nFillMode);
|
|
pRenderAuxGeom->SetRenderFlags(renderFlags);
|
|
m_renderState = pRenderAuxGeom->GetRenderFlags().m_renderFlags;
|
|
return prevState;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::DrawTextureLabel(const Vec3& pos, int nWidth, int nHeight, int nTexId, int nTexIconFlags, int srcOffsetX, int srcOffsetY, bool bDistanceScaleIcons, float fDistanceScale)
|
|
{
|
|
const float fLabelDepthPrecision = 0.05f;
|
|
Vec3 scrpos = view->WorldToView3D(pos);
|
|
|
|
float fWidth = (float)nWidth;
|
|
float fHeight = (float)nHeight;
|
|
|
|
if (bDistanceScaleIcons)
|
|
{
|
|
float fScreenScale = view->GetScreenScaleFactor(pos);
|
|
|
|
fWidth *= fDistanceScale / fScreenScale;
|
|
fHeight *= fDistanceScale / fScreenScale;
|
|
}
|
|
|
|
STextureLabel tl;
|
|
tl.x = scrpos.x + srcOffsetX;
|
|
tl.y = scrpos.y + srcOffsetY;
|
|
if (nTexIconFlags & TEXICON_ALIGN_BOTTOM)
|
|
{
|
|
tl.y -= fHeight / 2;
|
|
}
|
|
else if (nTexIconFlags & TEXICON_ALIGN_TOP)
|
|
{
|
|
tl.y += fHeight / 2;
|
|
}
|
|
tl.z = scrpos.z - (1.0f - scrpos.z) * fLabelDepthPrecision;
|
|
tl.w = fWidth;
|
|
tl.h = fHeight;
|
|
tl.nTexId = nTexId;
|
|
tl.flags = nTexIconFlags;
|
|
tl.color[0] = m_color4b.r * (1.0f / 255.0f);
|
|
tl.color[1] = m_color4b.g * (1.0f / 255.0f);
|
|
tl.color[2] = m_color4b.b * (1.0f / 255.0f);
|
|
tl.color[3] = m_color4b.a * (1.0f / 255.0f);
|
|
|
|
// Try to not overflood memory with labels.
|
|
if (m_textureLabels.size() < 100000)
|
|
{
|
|
m_textureLabels.push_back(tl);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void DisplayContext::Flush2D()
|
|
{
|
|
if (m_textureLabels.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
int rcw, rch;
|
|
view->GetDimensions(&rcw, &rch);
|
|
|
|
AZ_ErrorOnce(nullptr, false, "DisplayContext::Flush2D needs to be removed/ported to use Atom");
|
|
#if 0
|
|
|
|
TransformationMatrices backupSceneMatrices;
|
|
|
|
renderer->Set2DMode(rcw, rch, backupSceneMatrices, 0.0f, 1.0f);
|
|
|
|
renderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
|
|
//renderer->SetCullMode( R_CULL_NONE );
|
|
|
|
float uvs[4], uvt[4];
|
|
uvs[0] = 0;
|
|
uvt[0] = 1;
|
|
uvs[1] = 1;
|
|
uvt[1] = 1;
|
|
uvs[2] = 1;
|
|
uvt[2] = 0;
|
|
uvs[3] = 0;
|
|
uvt[3] = 0;
|
|
|
|
const size_t nLabels = m_textureLabels.size();
|
|
for (size_t i = 0; i < nLabels; i++)
|
|
{
|
|
STextureLabel& t = m_textureLabels[i];
|
|
float w2 = t.w * 0.5f;
|
|
float h2 = t.h * 0.5f;
|
|
if (t.flags & TEXICON_ADDITIVE)
|
|
{
|
|
renderer->SetState(GS_BLSRC_ONE | GS_BLDST_ONE);
|
|
}
|
|
else if (t.flags & TEXICON_ON_TOP)
|
|
{
|
|
renderer->SetState(GS_NODEPTHTEST | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
|
|
}
|
|
|
|
renderer->DrawImageWithUV(t.x - w2, t.y + h2, t.z, t.w, -t.h, t.nTexId, uvs, uvt, t.color[0], t.color[1], t.color[2], t.color[3]);
|
|
|
|
if (t.flags & (TEXICON_ADDITIVE | TEXICON_ON_TOP)) // Restore state.
|
|
{
|
|
renderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);
|
|
}
|
|
}
|
|
|
|
renderer->Unset2DMode(backupSceneMatrices);
|
|
#endif
|
|
|
|
m_textureLabels.clear();
|
|
}
|