Gizmo raycasting implemented
This commit is contained in:
parent
44d0900125
commit
5977225aca
|
@ -34,7 +34,7 @@ CVector3f CAABox::Center() const
|
|||
return (mMax - ((mMax - mMin) * 0.5f));
|
||||
}
|
||||
|
||||
CVector3f CAABox::GetSize() const
|
||||
CVector3f CAABox::Size() const
|
||||
{
|
||||
return (mMax - mMin);
|
||||
}
|
||||
|
@ -49,14 +49,24 @@ CVector3f CAABox::Max() const
|
|||
return mMax;
|
||||
}
|
||||
|
||||
void CAABox::SetMin(const CVector3f& min)
|
||||
{
|
||||
mMin = min;
|
||||
}
|
||||
|
||||
void CAABox::SetMax(const CVector3f& max)
|
||||
{
|
||||
mMax = max;
|
||||
}
|
||||
|
||||
bool CAABox::IsNull() const
|
||||
{
|
||||
return (GetSize() == CVector3f::skZero);
|
||||
return (Size() == CVector3f::skZero);
|
||||
}
|
||||
|
||||
bool CAABox::IsInfinite() const
|
||||
{
|
||||
return (GetSize() == CVector3f::skInfinite);
|
||||
return (Size() == CVector3f::skInfinite);
|
||||
}
|
||||
|
||||
void CAABox::ExpandBounds(const CVector3f& vtx)
|
||||
|
@ -76,6 +86,13 @@ void CAABox::ExpandBounds(const CAABox& AABox)
|
|||
ExpandBounds(AABox.mMax);
|
||||
}
|
||||
|
||||
void CAABox::ExpandBy(const CVector3f& amount)
|
||||
{
|
||||
CVector3f halfAmount = amount / 2.f;
|
||||
mMin -= halfAmount;
|
||||
mMax += halfAmount;
|
||||
}
|
||||
|
||||
CAABox CAABox::Transformed(const CTransform4f& transform) const
|
||||
{
|
||||
CAABox AABox;
|
||||
|
|
|
@ -19,14 +19,17 @@ public:
|
|||
CAABox(CInputStream& input);
|
||||
void Write(COutputStream& Output);
|
||||
CVector3f Center() const;
|
||||
CVector3f GetSize() const;
|
||||
CVector3f Size() const;
|
||||
CVector3f Min() const;
|
||||
CVector3f Max() const;
|
||||
void SetMin(const CVector3f& min);
|
||||
void SetMax(const CVector3f& max);
|
||||
bool IsNull() const;
|
||||
bool IsInfinite() const;
|
||||
|
||||
void ExpandBounds(const CVector3f& vtx);
|
||||
void ExpandBounds(const CAABox& AABox);
|
||||
void ExpandBy(const CVector3f& amount);
|
||||
CAABox Transformed(const CTransform4f& transform) const;
|
||||
|
||||
bool IsPointInBox(const CVector3f& Point) const;
|
||||
|
|
|
@ -60,7 +60,7 @@ float CVector3f::Magnitude() const
|
|||
|
||||
float CVector3f::SquaredMagnitude() const
|
||||
{
|
||||
return (powf(x,2) + powf(y,2) + powf(z,2));
|
||||
return Dot(*this);
|
||||
}
|
||||
|
||||
CVector3f CVector3f::Normalized() const
|
||||
|
|
|
@ -144,6 +144,69 @@ std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box)
|
|||
return std::pair<bool,float>(Hit, lowt);
|
||||
}
|
||||
|
||||
std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA,
|
||||
const CVector3f& pointB, float threshold)
|
||||
{
|
||||
// http://geomalgorithms.com/a07-_distance.html
|
||||
// http://www.gamedev.net/topic/589705-rayline-intersection-in-3d/
|
||||
CVector3f u = ray.Direction();
|
||||
CVector3f v = pointB - pointA;
|
||||
CVector3f w = ray.Origin() - pointA;
|
||||
float a = u.Dot(u);
|
||||
float b = u.Dot(v);
|
||||
float c = v.Dot(v);
|
||||
float d = u.Dot(w);
|
||||
float e = v.Dot(w);
|
||||
float D = a * c - b * b;
|
||||
float sc, sN, sD = D;
|
||||
float tc, tN, tD = D;
|
||||
|
||||
if (D < FLT_EPSILON) {
|
||||
sN = 0.f;
|
||||
sD = 1.f;
|
||||
tN = e;
|
||||
tD = c;
|
||||
}
|
||||
else {
|
||||
sN = b * e - c * d;
|
||||
tN = a * e - b * d;
|
||||
|
||||
if (sN < 0.f) {
|
||||
sN = 0.f;
|
||||
tN = e;
|
||||
tD = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (tN < 0.f) {
|
||||
tN = 0.f;
|
||||
|
||||
if (-d < 0.f)
|
||||
sN = 0.f;
|
||||
else {
|
||||
sN = -d;
|
||||
sD = a;
|
||||
}
|
||||
}
|
||||
else if (tN > tD) {
|
||||
tN = tD;
|
||||
|
||||
if (-d + b < 0.f)
|
||||
sN = 0.f;
|
||||
else {
|
||||
sN = -d + b;
|
||||
sD = a;
|
||||
}
|
||||
}
|
||||
|
||||
sc = (fabs(sN) < FLT_EPSILON ? 0.f : sN / sD);
|
||||
tc = (fabs(tN) < FLT_EPSILON ? 0.f : tN / tD);
|
||||
|
||||
CVector3f dP = w + (u * sc) - (v * tc);
|
||||
bool hit = (dP.Magnitude() <= threshold);
|
||||
return std::pair<bool,float>(hit, sc);
|
||||
}
|
||||
|
||||
std::pair<bool,float> RayTriangleIntersection(const CRay& Ray,
|
||||
const CVector3f& vtxA, const CVector3f& vtxB,
|
||||
const CVector3f& vtxC, bool AllowBackfaces)
|
||||
|
|
|
@ -16,6 +16,9 @@ float Distance(const CVector3f& A, const CVector3f& B);
|
|||
|
||||
std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box);
|
||||
|
||||
std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA,
|
||||
const CVector3f& pointB, float threshold = 0.02f);
|
||||
|
||||
std::pair<bool,float> RayTriangleIntersection(const CRay& Ray, const CVector3f& PointA,
|
||||
const CVector3f& PointB, const CVector3f& PointC,
|
||||
bool AllowBackfaces = false);
|
||||
|
|
|
@ -151,7 +151,7 @@ void CDrawUtil::DrawWireCube(const CAABox& kAABox, const CColor& kColor)
|
|||
|
||||
// Calculate model matrix
|
||||
CTransform4f Transform;
|
||||
Transform.Scale(kAABox.GetSize());
|
||||
Transform.Scale(kAABox.Size());
|
||||
Transform.Translate(kAABox.Center());
|
||||
CGraphics::sMVPBlock.ModelMatrix = Transform.ToMatrix4f();
|
||||
CGraphics::UpdateMVPBlock();
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
#include <Common/Math.h>
|
||||
#include <Core/CDrawUtil.h>
|
||||
|
||||
std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4f& Transform)
|
||||
std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, float LineThreshold)
|
||||
{
|
||||
//CDrawUtil::DrawWireCube(AABox.Transformed(Transform), CColor::skRed);
|
||||
bool Hit = false;
|
||||
float HitDist;
|
||||
|
||||
|
@ -14,6 +13,7 @@ std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4
|
|||
SPrimitive *pPrim = &Primitives[iPrim];
|
||||
u32 NumVerts = pPrim->Vertices.size();
|
||||
|
||||
// Triangles
|
||||
if ((pPrim->Type == eGX_Triangles) || (pPrim->Type == eGX_TriangleFan) || (pPrim->Type == eGX_TriangleStrip))
|
||||
{
|
||||
u32 NumTris;
|
||||
|
@ -23,14 +23,6 @@ std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4
|
|||
else
|
||||
NumTris = NumVerts - 2;
|
||||
|
||||
CColor LineColor;
|
||||
if (pPrim->Type == eGX_Triangles)
|
||||
LineColor = CColor::skRed;
|
||||
else if (pPrim->Type == eGX_TriangleStrip)
|
||||
LineColor = CColor::skYellow;
|
||||
else if (pPrim->Type == eGX_TriangleFan)
|
||||
LineColor = CColor::skGreen;
|
||||
|
||||
for (u32 iTri = 0; iTri < NumTris; iTri++)
|
||||
{
|
||||
CVector3f vtxA, vtxB, vtxC;
|
||||
|
@ -82,7 +74,38 @@ std::pair<bool,float> SSurface::IntersectsRay(const CRay& Ray, const CTransform4
|
|||
}
|
||||
}
|
||||
|
||||
// todo: Intersection tests for line primitives
|
||||
// Lines
|
||||
if ((pPrim->Type == eGX_Lines) || (pPrim->Type == eGX_LineStrip))
|
||||
{
|
||||
u32 NumLines;
|
||||
|
||||
if (pPrim->Type == eGX_Lines)
|
||||
NumLines = NumVerts / 2;
|
||||
else
|
||||
NumLines = NumVerts - 1;
|
||||
|
||||
for (u32 iLine = 0; iLine < NumLines; iLine++)
|
||||
{
|
||||
CVector3f vtxA, vtxB;
|
||||
|
||||
// Get the two vertices that make up the current line
|
||||
u32 index = (pPrim->Type == eGX_Lines ? iLine * 2 : iLine);
|
||||
vtxA = pPrim->Vertices[index].Position;
|
||||
vtxB = pPrim->Vertices[index+1].Position;
|
||||
|
||||
// Intersection test
|
||||
std::pair<bool,float> result = Math::RayLineIntersection(Ray, vtxA, vtxB, LineThreshold);
|
||||
|
||||
if (result.first)
|
||||
{
|
||||
if ((!Hit) || (result.second < HitDist))
|
||||
{
|
||||
Hit = true;
|
||||
HitDist = result.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::pair<bool,float>(Hit, HitDist);
|
||||
|
|
|
@ -33,7 +33,7 @@ struct SSurface
|
|||
TriangleCount = 0;
|
||||
}
|
||||
|
||||
std::pair<bool,float> IntersectsRay(const CRay& Ray, const CTransform4f& Transform = CTransform4f::skIdentity);
|
||||
std::pair<bool,float> IntersectsRay(const CRay& Ray, float LineThreshold = 0.02f);
|
||||
};
|
||||
|
||||
#endif // SSURFACE_H
|
||||
|
|
|
@ -112,7 +112,7 @@ SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
|||
out.AssetIndex = AssetID;
|
||||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform());
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay);
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
|
|
|
@ -213,7 +213,7 @@ SRayIntersection CScriptNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
|||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
CModel *pModel = (mpActiveModel ? mpActiveModel : CDrawUtil::GetCubeModel());
|
||||
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform());
|
||||
std::pair<bool,float> Result = pModel->GetSurface(AssetID)->IntersectsRay(TransformedRay);
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
|
@ -267,8 +267,8 @@ void CScriptNode::GeneratePosition()
|
|||
CScriptNode *pNode = mpScene->ScriptNodeByID(link.ObjectID);
|
||||
pNode->GeneratePosition();
|
||||
mPosition = pNode->GetAbsolutePosition();
|
||||
mPosition.z += (pNode->AABox().GetSize().z / 2.f);
|
||||
mPosition.z += (AABox().GetSize().z / 2.f);
|
||||
mPosition.z += (pNode->AABox().Size().z / 2.f);
|
||||
mPosition.z += (AABox().Size().z / 2.f);
|
||||
mPosition.z += 2.f;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ SRayIntersection CStaticNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID)
|
|||
out.AssetIndex = AssetID;
|
||||
|
||||
CRay TransformedRay = Ray.Transformed(Transform().Inverse());
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay, Transform());
|
||||
std::pair<bool,float> Result = mpModel->GetSurface(AssetID)->IntersectsRay(TransformedRay);
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
|
|
191
UI/CGizmo.cpp
191
UI/CGizmo.cpp
|
@ -1,4 +1,5 @@
|
|||
#include "CGizmo.h"
|
||||
#include <Common/Math.h>
|
||||
#include <Core/CRenderer.h>
|
||||
#include <Core/CResCache.h>
|
||||
|
||||
|
@ -6,7 +7,7 @@ CGizmo::CGizmo()
|
|||
{
|
||||
LoadModels();
|
||||
|
||||
mMode = eRotate;
|
||||
SetMode(eTranslate);
|
||||
mSelectedAxes = eNone;
|
||||
mGizmoSize = 1.f;
|
||||
mCameraDist = 0.f;
|
||||
|
@ -31,29 +32,15 @@ void CGizmo::AddToRenderer(CRenderer *pRenderer)
|
|||
// Transform is updated every frame even if the user doesn't modify the gizmo
|
||||
// in order to account for scale changes based on camera distance
|
||||
UpdateTransform();
|
||||
|
||||
// Determine which SModelPart array to use
|
||||
SModelPart *pParts;
|
||||
u32 numParts;
|
||||
|
||||
if (mMode == eTranslate) {
|
||||
pParts = smTranslateModels;
|
||||
numParts = 6;
|
||||
} else if (mMode == eRotate) {
|
||||
pParts = smRotateModels;
|
||||
numParts = 4;
|
||||
} else if (mMode == eScale) {
|
||||
pParts = smScaleModels;
|
||||
numParts = 7;
|
||||
}
|
||||
SModelPart *pPart = mpCurrentParts;
|
||||
|
||||
// Add all parts to renderer
|
||||
for (u32 iPart = 0; iPart < numParts; iPart++)
|
||||
for (u32 iPart = 0; iPart < mNumCurrentParts; iPart++)
|
||||
{
|
||||
CModel *pModel = pParts->pModel;
|
||||
CModel *pModel = pPart->pModel;
|
||||
|
||||
// Determine whether to use the mat set for regular (0) or highlight (1)
|
||||
bool isHighlighted = (mSelectedAxes & pParts->modelAxes) == pParts->modelAxes;
|
||||
bool isHighlighted = (mSelectedAxes & pPart->modelAxes) == pPart->modelAxes;
|
||||
u32 setID = (isHighlighted ? 1 : 0);
|
||||
|
||||
// Add to renderer...
|
||||
|
@ -62,7 +49,7 @@ void CGizmo::AddToRenderer(CRenderer *pRenderer)
|
|||
else
|
||||
pRenderer->AddOpaqueMesh(this, iPart, pModel->AABox().Transformed(mTransform), eDrawAsset);
|
||||
|
||||
pParts++;
|
||||
pPart++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,26 +59,13 @@ void CGizmo::DrawAsset(ERenderOptions options, u32 asset)
|
|||
CGraphics::UpdateMVPBlock();
|
||||
|
||||
// Determine which SModelPart array to use
|
||||
SModelPart *pParts;
|
||||
u32 numParts;
|
||||
|
||||
if (mMode == eTranslate) {
|
||||
pParts = smTranslateModels;
|
||||
numParts = 6;
|
||||
} else if (mMode == eRotate) {
|
||||
pParts = smRotateModels;
|
||||
numParts = 4;
|
||||
} else if (mMode == eScale) {
|
||||
pParts = smScaleModels;
|
||||
numParts = 7;
|
||||
}
|
||||
|
||||
if (asset >= numParts) return;
|
||||
if (asset >= mNumCurrentParts) return;
|
||||
SModelPart *pPart = mpCurrentParts;
|
||||
|
||||
// Draw model
|
||||
bool isHighlighted = (mSelectedAxes & pParts[asset].modelAxes) == pParts[asset].modelAxes;
|
||||
bool isHighlighted = (mSelectedAxes & pPart[asset].modelAxes) == pPart[asset].modelAxes;
|
||||
u32 setID = (isHighlighted ? 1 : 0);
|
||||
pParts[asset].pModel->Draw((ERenderOptions) 0, setID);
|
||||
pPart[asset].pModel->Draw((ERenderOptions) 0, setID);
|
||||
}
|
||||
|
||||
void CGizmo::DrawRotationOutline()
|
||||
|
@ -135,6 +109,80 @@ void CGizmo::UpdateForCamera(const CCamera &camera)
|
|||
mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis);
|
||||
}
|
||||
|
||||
bool CGizmo::IntersectsRay(const CRay &ray)
|
||||
{
|
||||
// todo: fix raycasting for rotate gizmo; currently it can hit the invisible back side of the model
|
||||
CRay localRay = ray.Transformed(mTransform.Inverse());
|
||||
float threshold = 0.02f * mGizmoSize * mCameraDist;
|
||||
|
||||
// Do raycast on each model
|
||||
SModelPart *pPart = mpCurrentParts;
|
||||
|
||||
struct SResult {
|
||||
SModelPart *pPart;
|
||||
float dist;
|
||||
};
|
||||
std::list<SResult> results;
|
||||
|
||||
for (u32 iPart = 0; iPart < mNumCurrentParts; iPart++)
|
||||
{
|
||||
if (!pPart->enableRayCast) continue;
|
||||
CModel *pModel = pPart->pModel;
|
||||
|
||||
// Ray/Model AABox test - allow buffer room because lines are small
|
||||
CAABox AABox = pModel->AABox();
|
||||
AABox.ExpandBy(CVector3f::skOne);
|
||||
bool modelBoxCheck = Math::RayBoxIntersection(localRay, AABox).first;
|
||||
|
||||
if (modelBoxCheck)
|
||||
{
|
||||
bool hit = false;
|
||||
float dist;
|
||||
|
||||
for (u32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++)
|
||||
{
|
||||
// Skip surface/box check
|
||||
SSurface *pSurf = pModel->GetSurface(iSurf);
|
||||
std::pair<bool,float> surfCheck = pSurf->IntersectsRay(localRay, 0.05f);
|
||||
|
||||
if (surfCheck.first)
|
||||
{
|
||||
if ((!hit) || (surfCheck.second < dist))
|
||||
dist = surfCheck.second;
|
||||
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hit)
|
||||
{
|
||||
SResult result;
|
||||
result.pPart = pPart;
|
||||
result.dist = dist;
|
||||
results.push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
pPart++;
|
||||
}
|
||||
|
||||
// Results list empty = no hits
|
||||
if (results.empty())
|
||||
{
|
||||
mSelectedAxes = eNone;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise, we have at least one hit - sort results and set selected axes
|
||||
results.sort([](const SResult& a, SResult& b) -> bool
|
||||
{
|
||||
return (a.dist < b.dist);
|
||||
});
|
||||
|
||||
mSelectedAxes = results.front().pPart->modelAxes;
|
||||
return true;
|
||||
}
|
||||
|
||||
CGizmo::EGizmoMode CGizmo::Mode()
|
||||
{
|
||||
return mMode;
|
||||
|
@ -143,6 +191,24 @@ CGizmo::EGizmoMode CGizmo::Mode()
|
|||
void CGizmo::SetMode(EGizmoMode mode)
|
||||
{
|
||||
mMode = mode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case eTranslate:
|
||||
mpCurrentParts = smTranslateModels;
|
||||
mNumCurrentParts = 9;
|
||||
break;
|
||||
|
||||
case eRotate:
|
||||
mpCurrentParts = smRotateModels;
|
||||
mNumCurrentParts = 4;
|
||||
break;
|
||||
|
||||
case eScale:
|
||||
mpCurrentParts = smScaleModels;
|
||||
mNumCurrentParts = 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CGizmo::SetPosition(const CVector3f& position)
|
||||
|
@ -150,31 +216,42 @@ void CGizmo::SetPosition(const CVector3f& position)
|
|||
mPosition = position;
|
||||
}
|
||||
|
||||
void CGizmo::ResetSelectedAxes()
|
||||
{
|
||||
mSelectedAxes = eNone;
|
||||
}
|
||||
|
||||
// ************ PRIVATE STATIC ************
|
||||
void CGizmo::LoadModels()
|
||||
{
|
||||
if (!smModelsLoaded)
|
||||
{
|
||||
smTranslateModels[CGIZMO_TRANSLATE_X] = SModelPart(eX, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoX.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_Y] = SModelPart(eY, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoY.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_Z] = SModelPart(eZ, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoZ.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_XY] = SModelPart(eXY, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoXY.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_XZ] = SModelPart(eXZ, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoXZ.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_YZ] = SModelPart(eYZ, (CModel*) gResCache.GetResource("../resources/editor/TranslateGizmoYZ.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateX.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateY.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateZ.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_LINES_XY] = SModelPart(eXY, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXY.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_LINES_XZ] = SModelPart(eXZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesXZ.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_LINES_YZ] = SModelPart(eYZ, true, (CModel*) gResCache.GetResource("../resources/editor/TranslateLinesYZ.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_POLY_XY] = SModelPart(eXY, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXY.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_POLY_XZ] = SModelPart(eXZ, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyXZ.CMDL"));
|
||||
smTranslateModels[CGIZMO_TRANSLATE_POLY_YZ] = SModelPart(eYZ, false, (CModel*) gResCache.GetResource("../resources/editor/TranslatePolyYZ.CMDL"));
|
||||
|
||||
smRotateModels[CGIZMO_ROTATE_X] = SModelPart(eX, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoX.CMDL"));
|
||||
smRotateModels[CGIZMO_ROTATE_Y] = SModelPart(eY, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoY.CMDL"));
|
||||
smRotateModels[CGIZMO_ROTATE_Z] = SModelPart(eZ, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoZ.CMDL"));
|
||||
smRotateModels[CGIZMO_ROTATE_XYZ] = SModelPart(eXYZ, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoXYZ.CMDL"));
|
||||
smRotateClipOutline = SModelPart(eNone, (CModel*) gResCache.GetResource("../resources/editor/RotateGizmoClipOutline.CMDL"));
|
||||
smRotateModels[CGIZMO_ROTATE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/RotateX.CMDL"));
|
||||
smRotateModels[CGIZMO_ROTATE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/RotateY.CMDL"));
|
||||
smRotateModels[CGIZMO_ROTATE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/RotateZ.CMDL"));
|
||||
smRotateModels[CGIZMO_ROTATE_XYZ] = SModelPart(eXYZ, false, (CModel*) gResCache.GetResource("../resources/editor/RotateXYZ.CMDL"));
|
||||
smRotateClipOutline = SModelPart(eNone, false, (CModel*) gResCache.GetResource("../resources/editor/RotateClipOutline.CMDL"));
|
||||
|
||||
smScaleModels[CGIZMO_SCALE_X] = SModelPart(eX, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoX.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_Y] = SModelPart(eY, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoY.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_Z] = SModelPart(eZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_XY] = SModelPart(eXY, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoXY.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_XZ] = SModelPart(eXZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoXZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_YZ] = SModelPart(eYZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoYZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, (CModel*) gResCache.GetResource("../resources/editor/ScaleGizmoXYZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_X] = SModelPart(eX, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleX.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_Y] = SModelPart(eY, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleY.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_Z] = SModelPart(eZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_LINES_XY] = SModelPart(eXY, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXY.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_LINES_XZ] = SModelPart(eXZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesXZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_LINES_YZ] = SModelPart(eYZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleLinesYZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_POLY_XY] = SModelPart(eXY, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXY.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_POLY_XZ] = SModelPart(eXZ, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyXZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_POLY_YZ] = SModelPart(eYZ, false, (CModel*) gResCache.GetResource("../resources/editor/ScalePolyYZ.CMDL"));
|
||||
smScaleModels[CGIZMO_SCALE_XYZ] = SModelPart(eXYZ, true, (CModel*) gResCache.GetResource("../resources/editor/ScaleXYZ.CMDL"));
|
||||
|
||||
smModelsLoaded = true;
|
||||
}
|
||||
|
@ -215,7 +292,7 @@ void CGizmo::UpdateTransform()
|
|||
|
||||
// ************ STATIC MEMBER INITIALIZATION ************
|
||||
bool CGizmo::smModelsLoaded = false;
|
||||
CGizmo::SModelPart CGizmo::smTranslateModels[6];
|
||||
CGizmo::SModelPart CGizmo::smTranslateModels[9];
|
||||
CGizmo::SModelPart CGizmo::smRotateModels[4];
|
||||
CGizmo::SModelPart CGizmo::smScaleModels[7];
|
||||
CGizmo::SModelPart CGizmo::smScaleModels[10];
|
||||
CGizmo::SModelPart CGizmo::smRotateClipOutline;
|
||||
|
|
35
UI/CGizmo.h
35
UI/CGizmo.h
|
@ -12,9 +12,12 @@
|
|||
#define CGIZMO_TRANSLATE_X 0
|
||||
#define CGIZMO_TRANSLATE_Y 1
|
||||
#define CGIZMO_TRANSLATE_Z 2
|
||||
#define CGIZMO_TRANSLATE_XY 3
|
||||
#define CGIZMO_TRANSLATE_XZ 4
|
||||
#define CGIZMO_TRANSLATE_YZ 5
|
||||
#define CGIZMO_TRANSLATE_LINES_XY 3
|
||||
#define CGIZMO_TRANSLATE_LINES_XZ 4
|
||||
#define CGIZMO_TRANSLATE_LINES_YZ 5
|
||||
#define CGIZMO_TRANSLATE_POLY_XY 6
|
||||
#define CGIZMO_TRANSLATE_POLY_XZ 7
|
||||
#define CGIZMO_TRANSLATE_POLY_YZ 8
|
||||
#define CGIZMO_ROTATE_X 0
|
||||
#define CGIZMO_ROTATE_Y 1
|
||||
#define CGIZMO_ROTATE_Z 2
|
||||
|
@ -22,10 +25,13 @@
|
|||
#define CGIZMO_SCALE_X 0
|
||||
#define CGIZMO_SCALE_Y 1
|
||||
#define CGIZMO_SCALE_Z 2
|
||||
#define CGIZMO_SCALE_XY 3
|
||||
#define CGIZMO_SCALE_XZ 4
|
||||
#define CGIZMO_SCALE_YZ 5
|
||||
#define CGIZMO_SCALE_XYZ 6
|
||||
#define CGIZMO_SCALE_LINES_XY 3
|
||||
#define CGIZMO_SCALE_LINES_XZ 4
|
||||
#define CGIZMO_SCALE_LINES_YZ 5
|
||||
#define CGIZMO_SCALE_POLY_XY 6
|
||||
#define CGIZMO_SCALE_POLY_XZ 7
|
||||
#define CGIZMO_SCALE_POLY_YZ 8
|
||||
#define CGIZMO_SCALE_XYZ 9
|
||||
|
||||
class CGizmo : public IRenderable
|
||||
{
|
||||
|
@ -66,27 +72,31 @@ private:
|
|||
bool mFlipScaleY;
|
||||
bool mFlipScaleZ;
|
||||
|
||||
// Static
|
||||
struct SModelPart
|
||||
{
|
||||
EGizmoAxes modelAxes;
|
||||
bool enableRayCast;
|
||||
CModel *pModel;
|
||||
CToken modelToken;
|
||||
|
||||
SModelPart() {}
|
||||
SModelPart(EGizmoAxes axes, CModel *_pModel) :
|
||||
modelAxes(axes), pModel(_pModel), modelToken(_pModel) {}
|
||||
SModelPart(EGizmoAxes axes, bool rayCastOn, CModel *_pModel) :
|
||||
modelAxes(axes), enableRayCast(rayCastOn), pModel(_pModel), modelToken(_pModel) {}
|
||||
};
|
||||
SModelPart *mpCurrentParts;
|
||||
u32 mNumCurrentParts;
|
||||
|
||||
// Static
|
||||
static bool smModelsLoaded;
|
||||
static SModelPart smTranslateModels[6];
|
||||
static SModelPart smTranslateModels[9];
|
||||
static SModelPart smRotateModels[4];
|
||||
static SModelPart smScaleModels[7];
|
||||
static SModelPart smScaleModels[10];
|
||||
static SModelPart smRotateClipOutline;
|
||||
|
||||
public:
|
||||
CGizmo();
|
||||
~CGizmo();
|
||||
|
||||
void AddToRenderer(CRenderer *pRenderer);
|
||||
void DrawAsset(ERenderOptions options, u32 asset);
|
||||
void DrawRotationOutline();
|
||||
|
@ -99,6 +109,7 @@ public:
|
|||
EGizmoMode Mode();
|
||||
void SetMode(EGizmoMode mode);
|
||||
void SetPosition(const CVector3f& position);
|
||||
void ResetSelectedAxes();
|
||||
|
||||
// Protected
|
||||
protected:
|
||||
|
|
|
@ -135,6 +135,10 @@ void CWorldEditor::ViewportRayCast(CRay Ray)
|
|||
{
|
||||
if (!ui->MainViewport->IsMouseInputActive())
|
||||
{
|
||||
// Gizmo ray check
|
||||
mGizmoHovering = mGizmo.IntersectsRay(Ray);
|
||||
|
||||
// Scene ray check
|
||||
SRayIntersection Result = mpSceneManager->SceneRayCast(Ray);
|
||||
|
||||
if (Result.Hit)
|
||||
|
@ -151,7 +155,10 @@ void CWorldEditor::ViewportRayCast(CRay Ray)
|
|||
ResetHover();
|
||||
}
|
||||
else
|
||||
{
|
||||
mGizmo.ResetSelectedAxes();
|
||||
ResetHover();
|
||||
}
|
||||
}
|
||||
|
||||
CRenderer* CWorldEditor::Renderer()
|
||||
|
@ -347,7 +354,9 @@ void CWorldEditor::UpdateCursor()
|
|||
{
|
||||
if (ui->MainViewport->IsCursorVisible())
|
||||
{
|
||||
if ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode))
|
||||
if (mGizmoHovering)
|
||||
ui->MainViewport->SetCursorState(Qt::SizeAllCursor);
|
||||
else if ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode))
|
||||
ui->MainViewport->SetCursorState(Qt::PointingHandCursor);
|
||||
else
|
||||
ui->MainViewport->SetCursorState(Qt::ArrowCursor);
|
||||
|
@ -359,7 +368,7 @@ void CWorldEditor::UpdateStatusBar()
|
|||
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
|
||||
QString StatusText = "";
|
||||
|
||||
if (mpHoverNode)
|
||||
if (!mGizmoHovering && mpHoverNode)
|
||||
{
|
||||
if (mpHoverNode->NodeType() != eStaticNode)
|
||||
StatusText = QString::fromStdString(mpHoverNode->Name());
|
||||
|
|
|
@ -33,6 +33,7 @@ class CWorldEditor : public QMainWindow
|
|||
CTimer mFrameTimer;
|
||||
bool mDrawSky;
|
||||
bool mShowGizmo;
|
||||
bool mGizmoHovering;
|
||||
|
||||
CVector3f mHoverPoint;
|
||||
CSceneNode *mpHoverNode;
|
||||
|
|
Loading…
Reference in New Issue