Gizmo raycasting implemented

This commit is contained in:
parax0 2015-08-17 14:10:42 -04:00
parent 44d0900125
commit 5977225aca
15 changed files with 301 additions and 94 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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:

View File

@ -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());

View File

@ -33,6 +33,7 @@ class CWorldEditor : public QMainWindow
CTimer mFrameTimer;
bool mDrawSky;
bool mShowGizmo;
bool mGizmoHovering;
CVector3f mHoverPoint;
CSceneNode *mpHoverNode;