Translation gizmo transform functionality implemented

This commit is contained in:
parax0 2015-08-19 21:01:58 -04:00
parent 08dbdb337a
commit 63c8351dcf
23 changed files with 567 additions and 107 deletions

44
Common/CPlane.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "CPlane.h"
CPlane::CPlane()
{
mNormal = CVector3f::skUp;
mDist = 0.f;
}
CPlane::CPlane(const CVector3f& normal, float dist)
{
mNormal = normal;
mDist = dist;
}
CPlane::CPlane(const CVector3f& normal, const CVector3f& origin)
{
Redefine(normal, origin);
}
void CPlane::Redefine(const CVector3f& normal, const CVector3f& origin)
{
mNormal = normal;
mDist = -normal.Dot(origin);
}
CVector3f CPlane::Normal() const
{
return mNormal;
}
float CPlane::Dist() const
{
return mDist;
}
void CPlane::SetNormal(const CVector3f& normal)
{
mNormal = normal;
}
void CPlane::SetDist(float dist)
{
mDist = dist;
}

23
Common/CPlane.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef CPLANE_H
#define CPLANE_H
#include "CVector3f.h"
class CPlane
{
CVector3f mNormal;
float mDist;
public:
CPlane();
CPlane(const CVector3f& normal, float dist);
CPlane(const CVector3f& normal, const CVector3f& origin);
void Redefine(const CVector3f& normal, const CVector3f& origin);
CVector3f Normal() const;
float Dist() const;
void SetNormal(const CVector3f& normal);
void SetDist(float dist);
};
#endif // CPLANE_H

View File

@ -18,6 +18,47 @@ CQuaternion::CQuaternion(float _x, float _y, float _z, float _w)
w = _w; w = _w;
} }
CVector3f CQuaternion::XAxis()
{
return (*this * CVector3f::skUnitX);
}
CVector3f CQuaternion::YAxis()
{
return (*this * CVector3f::skUnitY);
}
CVector3f CQuaternion::ZAxis()
{
return (*this * CVector3f::skUnitZ);
}
CQuaternion CQuaternion::Inverse()
{
float fNorm = (w * w) + (x * x) + (y * y) + (z * z);
if (fNorm > 0.f)
{
float fInvNorm = 1.f / fNorm;
return CQuaternion(-x * fInvNorm, -y * fInvNorm, -z * fInvNorm, w * fInvNorm);
}
else
return CQuaternion::skZero;
}
// ************ OPERATORS ************
CVector3f CQuaternion::operator*(const CVector3f& vec) const
{
CVector3f uv, uuv;
CVector3f qvec(x, y, z);
uv = qvec.Cross(vec);
uuv = qvec.Cross(uv);
uv *= (2.0f * w);
uuv *= 2.0f;
return vec + uv + uuv;
}
CQuaternion CQuaternion::operator*(const CQuaternion& other) const CQuaternion CQuaternion::operator*(const CQuaternion& other) const
{ {
CQuaternion out; CQuaternion out;
@ -84,3 +125,4 @@ CQuaternion CQuaternion::FromAxisAngle(float angle, CVector3f axis)
} }
CQuaternion CQuaternion::skIdentity = CQuaternion(0.f, 0.f, 0.f, 1.f); CQuaternion CQuaternion::skIdentity = CQuaternion(0.f, 0.f, 0.f, 1.f);
CQuaternion CQuaternion::skZero = CQuaternion(0.f, 0.f, 0.f, 0.f);

View File

@ -11,7 +11,13 @@ public:
CQuaternion(); CQuaternion();
CQuaternion(float _x, float _y, float _z, float _w); CQuaternion(float _x, float _y, float _z, float _w);
CVector3f XAxis();
CVector3f YAxis();
CVector3f ZAxis();
CQuaternion Inverse();
// Operators // Operators
CVector3f operator*(const CVector3f& vec) const;
CQuaternion operator*(const CQuaternion& other) const; CQuaternion operator*(const CQuaternion& other) const;
void operator *= (const CQuaternion& other); void operator *= (const CQuaternion& other);
@ -20,6 +26,7 @@ public:
static CQuaternion FromAxisAngle(float angle, CVector3f axis); static CQuaternion FromAxisAngle(float angle, CVector3f axis);
static CQuaternion skIdentity; static CQuaternion skIdentity;
static CQuaternion skZero;
}; };
#endif // CQUATERNION_H #endif // CQUATERNION_H

View File

@ -279,12 +279,15 @@ const float& CVector3f::operator[](long index) const
const CVector3f CVector3f::skZero = CVector3f(0.f); const CVector3f CVector3f::skZero = CVector3f(0.f);
const CVector3f CVector3f::skOne = CVector3f(1.f); const CVector3f CVector3f::skOne = CVector3f(1.f);
const CVector3f CVector3f::skInfinite = CVector3f(FLT_MAX); const CVector3f CVector3f::skInfinite = CVector3f(FLT_MAX);
const CVector3f CVector3f::skForward = CVector3f(0.f, 1.f, 0.f); const CVector3f CVector3f::skUnitX = CVector3f(1.f, 0.f, 0.f);
const CVector3f CVector3f::skBack = CVector3f(0.f, -1.f, 0.f); const CVector3f CVector3f::skUnitY = CVector3f(0.f, 1.f, 0.f);
const CVector3f CVector3f::skRight = CVector3f( 1.f, 0.f, 0.f); const CVector3f CVector3f::skUnitZ = CVector3f(0.f, 0.f, 1.f);
const CVector3f CVector3f::skLeft = CVector3f(-1.f, 0.f, 0.f); const CVector3f CVector3f::skRight = CVector3f::skUnitX;
const CVector3f CVector3f::skUp = CVector3f(0.f, 0.f, 1.f); const CVector3f CVector3f::skLeft = -CVector3f::skUnitX;
const CVector3f CVector3f::skDown = CVector3f(0.f, 0.f, -1.f); const CVector3f CVector3f::skForward = CVector3f::skUnitY;
const CVector3f CVector3f::skBack = -CVector3f::skUnitY;
const CVector3f CVector3f::skUp = CVector3f::skUnitZ;
const CVector3f CVector3f::skDown = -CVector3f::skUnitZ;
// ************ OTHER ************ // ************ OTHER ************
std::ostream& operator<<(std::ostream& o, const CVector3f& Vector) std::ostream& operator<<(std::ostream& o, const CVector3f& Vector)

View File

@ -75,10 +75,13 @@ public:
static const CVector3f skZero; static const CVector3f skZero;
static const CVector3f skOne; static const CVector3f skOne;
static const CVector3f skInfinite; static const CVector3f skInfinite;
static const CVector3f skForward; static const CVector3f skUnitX;
static const CVector3f skBack; static const CVector3f skUnitY;
static const CVector3f skUnitZ;
static const CVector3f skRight; static const CVector3f skRight;
static const CVector3f skLeft; static const CVector3f skLeft;
static const CVector3f skForward;
static const CVector3f skBack;
static const CVector3f skUp; static const CVector3f skUp;
static const CVector3f skDown; static const CVector3f skDown;

11
Common/ETransformSpace.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef ETRANSFORMSPACE
#define ETRANSFORMSPACE
enum ETransformSpace
{
eWorldTransform,
eLocalTransform
};
#endif // ETRANSFORMSPACE

View File

@ -3,6 +3,11 @@
namespace Math namespace Math
{ {
float Abs(float v)
{
return fabs(v);
}
float Pow(float Base, float Exponent) float Pow(float Base, float Exponent)
{ {
return pow(Base, Exponent); return pow(Base, Exponent);
@ -15,6 +20,23 @@ float Distance(const CVector3f& A, const CVector3f& B)
Pow(B.z - A.z, 2.f) ); Pow(B.z - A.z, 2.f) );
} }
std::pair<bool,float> RayPlaneIntersecton(const CRay& ray, const CPlane& plane)
{
// Code based on ray/plane intersect code from Ogre
// https://bitbucket.org/sinbad/ogre/src/197116fd2ac62c57cdeed1666f9866c3dddd4289/OgreMain/src/OgreMath.cpp?at=default#OgreMath.cpp-350
// Are ray and plane parallel?
float denom = plane.Normal().Dot(ray.Direction());
if (Abs(denom) < FLT_EPSILON)
return std::pair<bool,float>(false, 0.f);
// Not parallel
float nom = plane.Normal().Dot(ray.Origin()) + plane.Dist();
float t = -(nom / denom);
return std::pair<bool,float>(t >= 0.f, t);
}
std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box) std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box)
{ {
// Code slightly modified from Ogre // Code slightly modified from Ogre

View File

@ -3,6 +3,7 @@
#include "CAABox.h" #include "CAABox.h"
#include "CRay.h" #include "CRay.h"
#include "CPlane.h"
#include "CVector3f.h" #include "CVector3f.h"
#include "SRayIntersection.h" #include "SRayIntersection.h"
#include <utility> #include <utility>
@ -10,10 +11,14 @@
namespace Math namespace Math
{ {
float Abs(float v);
float Pow(float Base, float Exponent); float Pow(float Base, float Exponent);
float Distance(const CVector3f& A, const CVector3f& B); float Distance(const CVector3f& A, const CVector3f& B);
std::pair<bool,float> RayPlaneIntersecton(const CRay& ray, const CPlane& plane);
std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box); std::pair<bool,float> RayBoxIntersection(const CRay& Ray, const CAABox& Box);
std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA, std::pair<bool,float> RayLineIntersection(const CRay& ray, const CVector3f& pointA,

View File

@ -140,10 +140,6 @@ void CRenderer::RenderBuckets(CCamera& Camera)
mTransparentBucket.Sort(Camera); mTransparentBucket.Sort(Camera);
mTransparentBucket.Draw(mOptions); mTransparentBucket.Draw(mOptions);
mTransparentBucket.Clear(); mTransparentBucket.Clear();
// Clear depth buffer to enable more rendering passes
glDepthMask(GL_TRUE);
glClear(GL_DEPTH_BUFFER_BIT);
} }
void CRenderer::RenderBloom() void CRenderer::RenderBloom()
@ -331,6 +327,12 @@ void CRenderer::EndFrame()
gDrawCount = 0; gDrawCount = 0;
} }
void CRenderer::ClearDepthBuffer()
{
glDepthMask(GL_TRUE);
glClear(GL_DEPTH_BUFFER_BIT);
}
// ************ PRIVATE ************ // ************ PRIVATE ************
void CRenderer::InitFramebuffer() void CRenderer::InitFramebuffer()
{ {

View File

@ -72,6 +72,7 @@ public:
void AddTransparentMesh(IRenderable *pRenderable, u32 AssetID, CAABox& AABox, ERenderCommand Command); void AddTransparentMesh(IRenderable *pRenderable, u32 AssetID, CAABox& AABox, ERenderCommand Command);
void BeginFrame(); void BeginFrame();
void EndFrame(); void EndFrame();
void ClearDepthBuffer();
// Private // Private
private: private:

View File

@ -157,7 +157,6 @@ void CSceneManager::SetActiveArea(CGameArea* _area)
{ {
CScriptObject *pObj = pGenLayer->ObjectByIndex(o); CScriptObject *pObj = pGenLayer->ObjectByIndex(o);
CScriptNode *Node = AddScriptObject(pObj); CScriptNode *Node = AddScriptObject(pObj);
Node->BuildLightList(mpArea);
// Add to map // Add to map
mScriptNodeMap[pObj->InstanceID()] = Node; mScriptNodeMap[pObj->InstanceID()] = Node;
@ -165,9 +164,12 @@ void CSceneManager::SetActiveArea(CGameArea* _area)
} }
PickEnvironmentObjects(); PickEnvironmentObjects();
// Ensure script nodes have valid positions // Ensure script nodes have valid positions + build light lists
for (auto it = mScriptNodeMap.begin(); it != mScriptNodeMap.end(); it++) for (auto it = mScriptNodeMap.begin(); it != mScriptNodeMap.end(); it++)
{
it->second->GeneratePosition(); it->second->GeneratePosition();
it->second->BuildLightList(mpArea);
}
u32 NumLightLayers = mpArea->GetLightLayerCount(); u32 NumLightLayers = mpArea->GetLightLayerCount();
CGraphics::sAreaAmbientColor = CColor::skBlack; CGraphics::sAreaAmbientColor = CColor::skBlack;

View File

@ -134,7 +134,8 @@ SOURCES += \
UI/WScanPreviewPanel.cpp \ UI/WScanPreviewPanel.cpp \
UI/WIntegralSpinBox.cpp \ UI/WIntegralSpinBox.cpp \
UI/CAboutDialog.cpp \ UI/CAboutDialog.cpp \
UI/CGizmo.cpp UI/CGizmo.cpp \
Common/CPlane.cpp
HEADERS += \ HEADERS += \
Common/AnimUtil.h \ Common/AnimUtil.h \
@ -283,7 +284,9 @@ HEADERS += \
UI/CAboutDialog.h \ UI/CAboutDialog.h \
UI/CGizmo.h \ UI/CGizmo.h \
Core/IRenderable.h \ Core/IRenderable.h \
Core/SRenderablePtr.h Core/SRenderablePtr.h \
Common/ETransformSpace.h \
Common/CPlane.h
FORMS += \ FORMS += \
UI/CWorldEditorWindow.ui \ UI/CWorldEditorWindow.ui \

View File

@ -185,15 +185,29 @@ void CSceneNode::DrawBoundingBox()
} }
// ************ TRANSFORM ************ // ************ TRANSFORM ************
void CSceneNode::Translate(const CVector3f& Translation) void CSceneNode::Translate(const CVector3f& translation, ETransformSpace transformSpace)
{ {
mPosition += Translation; switch (transformSpace)
{
case eWorldTransform:
mPosition += translation;
break;
case eLocalTransform:
mPosition += mRotation * translation;
break;
}
MarkTransformChanged(); MarkTransformChanged();
} }
void CSceneNode::Scale(const CVector3f& Scale) void CSceneNode::Rotate(const CQuaternion& rotation, ETransformSpace transformSpace)
{ {
mScale *= Scale; mRotation *= rotation;
MarkTransformChanged();
}
void CSceneNode::Scale(const CVector3f& scale, ETransformSpace transformSpace)
{
mScale *= scale;
MarkTransformChanged(); MarkTransformChanged();
} }
@ -209,9 +223,9 @@ void CSceneNode::UpdateTransform()
void CSceneNode::ForceRecalculateTransform() void CSceneNode::ForceRecalculateTransform()
{ {
_mCachedTransform = CTransform4f::skIdentity; _mCachedTransform = CTransform4f::skIdentity;
_mCachedTransform.Scale(GetAbsoluteScale()); _mCachedTransform.Scale(AbsoluteScale());
_mCachedTransform.Rotate(GetAbsoluteRotation()); _mCachedTransform.Rotate(AbsoluteRotation());
_mCachedTransform.Translate(GetAbsolutePosition()); _mCachedTransform.Translate(AbsolutePosition());
_mCachedAABox = mLocalAABox.Transformed(_mCachedTransform); _mCachedAABox = mLocalAABox.Transformed(_mCachedTransform);
// Sync with children - only needed if caller hasn't marked transform changed already // Sync with children - only needed if caller hasn't marked transform changed already
@ -259,47 +273,47 @@ CSceneManager* CSceneNode::Scene()
return mpScene; return mpScene;
} }
CVector3f CSceneNode::GetPosition() const CVector3f CSceneNode::LocalPosition() const
{ {
return mPosition; return mPosition;
} }
CVector3f CSceneNode::GetAbsolutePosition() const CVector3f CSceneNode::AbsolutePosition() const
{ {
CVector3f ret = mPosition; CVector3f ret = mPosition;
if ((mpParent) && (InheritsPosition())) if ((mpParent) && (InheritsPosition()))
ret += mpParent->GetAbsolutePosition(); ret += mpParent->AbsolutePosition();
return ret; return ret;
} }
CQuaternion CSceneNode::GetRotation() const CQuaternion CSceneNode::LocalRotation() const
{ {
return mRotation; return mRotation;
} }
CQuaternion CSceneNode::GetAbsoluteRotation() const CQuaternion CSceneNode::AbsoluteRotation() const
{ {
CQuaternion ret = mRotation; CQuaternion ret = mRotation;
if ((mpParent) && (InheritsRotation())) if ((mpParent) && (InheritsRotation()))
ret *= mpParent->GetAbsoluteRotation(); ret *= mpParent->AbsoluteRotation();
return ret; return ret;
} }
CVector3f CSceneNode::GetScale() const CVector3f CSceneNode::LocalScale() const
{ {
return mScale; return mScale;
} }
CVector3f CSceneNode::GetAbsoluteScale() const CVector3f CSceneNode::AbsoluteScale() const
{ {
CVector3f ret = mScale; CVector3f ret = mScale;
if ((mpParent) && (InheritsScale())) if ((mpParent) && (InheritsScale()))
ret *= mpParent->GetAbsoluteScale(); ret *= mpParent->AbsoluteScale();
return ret; return ret;
} }

View File

@ -3,13 +3,14 @@
#include <Core/IRenderable.h> #include <Core/IRenderable.h>
#include "ENodeType.h" #include "ENodeType.h"
#include <Common/CVector3f.h>
#include <Common/CQuaternion.h>
#include <Common/CAABox.h> #include <Common/CAABox.h>
#include <Common/CQuaternion.h>
#include <Common/CRay.h> #include <Common/CRay.h>
#include <Common/CRayCollisionTester.h> #include <Common/CRayCollisionTester.h>
#include <Common/types.h>
#include <Common/CTransform4f.h> #include <Common/CTransform4f.h>
#include <Common/CVector3f.h>
#include <Common/ETransformSpace.h>
#include <Common/types.h>
#include <Core/ERenderOptions.h> #include <Core/ERenderOptions.h>
#include <Resource/CLight.h> #include <Resource/CLight.h>
#include <Resource/CGameArea.h> #include <Resource/CGameArea.h>
@ -68,8 +69,9 @@ public:
void DrawBoundingBox(); void DrawBoundingBox();
// Transform // Transform
void Translate(const CVector3f& Translation); void Translate(const CVector3f& translation, ETransformSpace transformSpace);
void Scale(const CVector3f& Scale); void Rotate(const CQuaternion& rotation, ETransformSpace transformSpace);
void Scale(const CVector3f& scale, ETransformSpace transformSpace);
void UpdateTransform(); void UpdateTransform();
void ForceRecalculateTransform(); void ForceRecalculateTransform();
void MarkTransformChanged(); void MarkTransformChanged();
@ -79,12 +81,12 @@ public:
std::string Name() const; std::string Name() const;
CSceneNode* Parent() const; CSceneNode* Parent() const;
CSceneManager* Scene(); CSceneManager* Scene();
CVector3f GetPosition() const; CVector3f LocalPosition() const;
CVector3f GetAbsolutePosition() const; CVector3f AbsolutePosition() const;
CQuaternion GetRotation() const; CQuaternion LocalRotation() const;
CQuaternion GetAbsoluteRotation() const; CQuaternion AbsoluteRotation() const;
CVector3f GetScale() const; CVector3f LocalScale() const;
CVector3f GetAbsoluteScale() const; CVector3f AbsoluteScale() const;
CAABox AABox(); CAABox AABox();
CVector3f CenterPoint(); CVector3f CenterPoint();
bool MarkedVisible() const; bool MarkedVisible() const;

View File

@ -45,7 +45,7 @@ CScriptNode::CScriptNode(CSceneManager *pScene, CSceneNode *pParent, CScriptObje
{ {
mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel); mpVolumePreviewNode = new CModelNode(pScene, this, pVolumeModel);
mpVolumePreviewNode->SetInheritance(true, (VolumeShape == 1), false); mpVolumePreviewNode->SetInheritance(true, (VolumeShape == 1), false);
mpVolumePreviewNode->Scale(mpInstance->GetVolume()); mpVolumePreviewNode->Scale(mpInstance->GetVolume(), eWorldTransform);
mpVolumePreviewNode->ForceAlphaEnabled(true); mpVolumePreviewNode->ForceAlphaEnabled(true);
} }
} }
@ -266,7 +266,7 @@ void CScriptNode::GeneratePosition()
const SLink& link = (mpInstance->NumInLinks() > 0 ? mpInstance->InLink(0) : mpInstance->OutLink(0)); const SLink& link = (mpInstance->NumInLinks() > 0 ? mpInstance->InLink(0) : mpInstance->OutLink(0));
CScriptNode *pNode = mpScene->ScriptNodeByID(link.ObjectID); CScriptNode *pNode = mpScene->ScriptNodeByID(link.ObjectID);
pNode->GeneratePosition(); pNode->GeneratePosition();
mPosition = pNode->GetAbsolutePosition(); mPosition = pNode->AbsolutePosition();
mPosition.z += (pNode->AABox().Size().z / 2.f); mPosition.z += (pNode->AABox().Size().z / 2.f);
mPosition.z += (AABox().Size().z / 2.f); mPosition.z += (AABox().Size().z / 2.f);
mPosition.z += 2.f; mPosition.z += 2.f;

View File

@ -105,24 +105,31 @@ void CEditorGLWidget::mousePressEvent(QMouseEvent *pEvent)
// Left click only activates if mouse input is inactive to prevent the user from // Left click only activates if mouse input is inactive to prevent the user from
// clicking on things and creating selection rectangles while the cursor is hidden // clicking on things and creating selection rectangles while the cursor is hidden
else if (pEvent->button() == Qt::LeftButton) else
mButtonsPressed |= eLeftButton; {
if (pEvent->button() == Qt::LeftButton)
mButtonsPressed |= eLeftButton;
emit MouseClick(pEvent);
}
mLastMousePos = pEvent->globalPos(); mLastMousePos = pEvent->globalPos();
} }
void CEditorGLWidget::mouseReleaseEvent(QMouseEvent *pEvent) void CEditorGLWidget::mouseReleaseEvent(QMouseEvent *pEvent)
{ {
bool fromMouseInput = IsMouseInputActive();
if (pEvent->button() == Qt::LeftButton) mButtonsPressed &= ~eLeftButton; if (pEvent->button() == Qt::LeftButton) mButtonsPressed &= ~eLeftButton;
if (pEvent->button() == Qt::MidButton) mButtonsPressed &= ~eMiddleButton; if (pEvent->button() == Qt::MidButton) mButtonsPressed &= ~eMiddleButton;
if (pEvent->button() == Qt::RightButton) mButtonsPressed &= ~eRightButton; if (pEvent->button() == Qt::RightButton) mButtonsPressed &= ~eRightButton;
// Make cursor visible and emit mouse click event if middle/right mouse buttons are both released // Make cursor visible if needed
if (!IsMouseInputActive()) if (!IsMouseInputActive())
{
SetCursorVisible(true); SetCursorVisible(true);
emit MouseClick(pEvent);
} // Emit mouse release event if we didn't just exit mouse input (or regardless on left click)
if (!fromMouseInput || (pEvent->button() == Qt::LeftButton))
emit MouseRelease(pEvent);
} }
void CEditorGLWidget::keyPressEvent(QKeyEvent *pEvent) void CEditorGLWidget::keyPressEvent(QKeyEvent *pEvent)

View File

@ -54,6 +54,7 @@ signals:
void Render(CCamera& Camera); void Render(CCamera& Camera);
void PostRender(); void PostRender();
void MouseClick(QMouseEvent *pEvent); void MouseClick(QMouseEvent *pEvent);
void MouseRelease(QMouseEvent *pEvent);
void MouseDrag(QMouseEvent *pEvent); void MouseDrag(QMouseEvent *pEvent);
private: private:

View File

@ -2,6 +2,8 @@
#include <Common/Math.h> #include <Common/Math.h>
#include <Core/CRenderer.h> #include <Core/CRenderer.h>
#include <Core/CResCache.h> #include <Core/CResCache.h>
#include <Core/CDrawUtil.h>
#include <iostream>
CGizmo::CGizmo() CGizmo::CGizmo()
{ {
@ -15,9 +17,10 @@ CGizmo::CGizmo()
mPosition = CVector3f::skZero; mPosition = CVector3f::skZero;
mRotation = CQuaternion::skIdentity; mRotation = CQuaternion::skIdentity;
mScale = CVector3f::skOne; mScale = CVector3f::skOne;
mDeltaPosition = CVector3f::skZero; mDeltaTranslation = CVector3f::skZero;
mDeltaRotation = CQuaternion::skIdentity; mDeltaRotation = CQuaternion::skIdentity;
mDeltaScale = CVector3f::skOne; mDeltaScale = CVector3f::skOne;
mSetOffset = false;
mFlipScaleX = false; mFlipScaleX = false;
mFlipScaleY = false; mFlipScaleY = false;
mFlipScaleZ = false; mFlipScaleZ = false;
@ -109,11 +112,10 @@ void CGizmo::UpdateForCamera(const CCamera &camera)
mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis); mBillboardRotation = CQuaternion::FromAxisAngle(angle, axis);
} }
bool CGizmo::IntersectsRay(const CRay &ray) bool CGizmo::CheckSelectedAxes(const CRay &ray)
{ {
// todo: fix raycasting for rotate gizmo; currently it can hit the invisible back side of the model // todo: fix raycasting for rotate gizmo; currently it can hit the invisible back side of the model
CRay localRay = ray.Transformed(mTransform.Inverse()); CRay localRay = ray.Transformed(mTransform.Inverse());
float threshold = 0.02f * mGizmoSize * mCameraDist;
// Do raycast on each model // Do raycast on each model
SModelPart *pPart = mpCurrentParts; SModelPart *pPart = mpCurrentParts;
@ -126,7 +128,12 @@ bool CGizmo::IntersectsRay(const CRay &ray)
for (u32 iPart = 0; iPart < mNumCurrentParts; iPart++) for (u32 iPart = 0; iPart < mNumCurrentParts; iPart++)
{ {
if (!pPart->enableRayCast) continue; if (!pPart->enableRayCast)
{
pPart++;
continue;
}
CModel *pModel = pPart->pModel; CModel *pModel = pPart->pModel;
// Ray/Model AABox test - allow buffer room because lines are small // Ray/Model AABox test - allow buffer room because lines are small
@ -141,7 +148,7 @@ bool CGizmo::IntersectsRay(const CRay &ray)
for (u32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++) for (u32 iSurf = 0; iSurf < pModel->GetSurfaceCount(); iSurf++)
{ {
// Skip surface/box check // Skip surface/box check - since we use lines the boxes might be too small
SSurface *pSurf = pModel->GetSurface(iSurf); SSurface *pSurf = pModel->GetSurface(iSurf);
std::pair<bool,float> surfCheck = pSurf->IntersectsRay(localRay, 0.05f); std::pair<bool,float> surfCheck = pSurf->IntersectsRay(localRay, 0.05f);
@ -183,11 +190,129 @@ bool CGizmo::IntersectsRay(const CRay &ray)
return true; return true;
} }
u32 CGizmo::NumSelectedAxes()
{
u32 out = 0;
for (u32 iAxis = 1; iAxis < 8; iAxis <<= 1)
if (mSelectedAxes & (EGizmoAxes) iAxis) out++;
return out;
}
void CGizmo::ResetSelectedAxes()
{
mSelectedAxes = eNone;
}
void CGizmo::StartTransform()
{
mSetOffset = false;
mTotalTranslation = CVector3f::skZero;
mTotalRotation = CQuaternion::skIdentity;
mTotalScale = CVector3f::skOne;
}
bool CGizmo::TransformFromInput(const CRay& ray, const CCamera& camera)
{
if (mMode == eTranslate)
{
// Create translate plane
CVector3f axisA, axisB;
u32 numAxes = NumSelectedAxes();
if (numAxes == 1)
{
if (mSelectedAxes & eX) axisB = mRotation.XAxis();
else if (mSelectedAxes & eY) axisB = mRotation.YAxis();
else axisB = mRotation.ZAxis();
CVector3f gizmoToCamera = (mPosition - camera.Position()).Normalized();
axisA = axisB.Cross(gizmoToCamera);
}
else if (numAxes == 2)
{
axisA = (mSelectedAxes & eX ? mRotation.XAxis() : mRotation.YAxis());
axisB = (mSelectedAxes & eZ ? mRotation.ZAxis() : mRotation.YAxis());
}
CVector3f planeNormal = axisA.Cross(axisB);
mTranslatePlane.Redefine(planeNormal, mPosition);
// Do translate
std::pair<bool,float> result = Math::RayPlaneIntersecton(ray, mTranslatePlane);
if (result.first)
{
CVector3f hit = ray.PointOnRay(result.second);
CVector3f localDelta = mRotation.Inverse() * (hit - mPosition);
// Calculate new position
CVector3f newPos = mPosition;
if (mSelectedAxes & eX) newPos += mRotation.XAxis() * localDelta.x;
if (mSelectedAxes & eY) newPos += mRotation.YAxis() * localDelta.y;
if (mSelectedAxes & eZ) newPos += mRotation.ZAxis() * localDelta.z;
// Check relativity of new pos to camera to reduce issue where the gizmo might
// go flying off into the distance if newPosToCamera is parallel to the plane
CVector3f newPosToCamera = (newPos - camera.Position()).Normalized();
float dot = Math::Abs(planeNormal.Dot(newPosToCamera));
if (dot < 0.02f) return false;
// Set offset
if (!mSetOffset)
{
mTranslateOffset = mPosition - newPos;
mDeltaTranslation = CVector3f::skZero;
mSetOffset = true;
return false;
}
// Apply translation
else
{
mDeltaTranslation = mRotation.Inverse() * (newPos - mPosition + mTranslateOffset);
mTotalTranslation += mDeltaTranslation;
mPosition = newPos + mTranslateOffset;
return true;
}
}
else
{
mDeltaTranslation = CVector3f::skZero;
return false;
}
}
return false;
}
void CGizmo::EndTransform()
{
}
CGizmo::EGizmoMode CGizmo::Mode() CGizmo::EGizmoMode CGizmo::Mode()
{ {
return mMode; return mMode;
} }
CVector3f CGizmo::Position()
{
return mPosition;
}
CVector3f CGizmo::DeltaTranslation()
{
return mDeltaTranslation;
}
CVector3f CGizmo::TotalTranslation()
{
return mTotalTranslation;
}
void CGizmo::SetMode(EGizmoMode mode) void CGizmo::SetMode(EGizmoMode mode)
{ {
mMode = mode; mMode = mode;
@ -197,16 +322,22 @@ void CGizmo::SetMode(EGizmoMode mode)
case eTranslate: case eTranslate:
mpCurrentParts = smTranslateModels; mpCurrentParts = smTranslateModels;
mNumCurrentParts = 9; mNumCurrentParts = 9;
mDeltaRotation = CQuaternion::skIdentity;
mDeltaScale = CVector3f::skOne;
break; break;
case eRotate: case eRotate:
mpCurrentParts = smRotateModels; mpCurrentParts = smRotateModels;
mNumCurrentParts = 4; mNumCurrentParts = 4;
mDeltaTranslation = CVector3f::skZero;
mDeltaScale = CVector3f::skOne;
break; break;
case eScale: case eScale:
mpCurrentParts = smScaleModels; mpCurrentParts = smScaleModels;
mNumCurrentParts = 10; mNumCurrentParts = 10;
mDeltaTranslation = CVector3f::skZero;
mDeltaRotation = CQuaternion::skIdentity;
break; break;
} }
} }
@ -216,9 +347,9 @@ void CGizmo::SetPosition(const CVector3f& position)
mPosition = position; mPosition = position;
} }
void CGizmo::ResetSelectedAxes() void CGizmo::SetOrientation(const CQuaternion& orientation)
{ {
mSelectedAxes = eNone; mRotation = orientation;
} }
// ************ PRIVATE STATIC ************ // ************ PRIVATE STATIC ************

View File

@ -1,8 +1,9 @@
#ifndef CGIZMO_H #ifndef CGIZMO_H
#define CGIZMO_H #define CGIZMO_H
#include <Common/CVector3f.h> #include <Common/CPlane.h>
#include <Common/CQuaternion.h> #include <Common/CQuaternion.h>
#include <Common/CVector3f.h>
#include <Common/EnumUtil.h> #include <Common/EnumUtil.h>
#include <Core/CCamera.h> #include <Core/CCamera.h>
#include <Core/CToken.h> #include <Core/CToken.h>
@ -63,15 +64,24 @@ private:
CTransform4f mTransform; CTransform4f mTransform;
CVector3f mPosition; CVector3f mPosition;
CVector3f mDeltaTranslation;
CVector3f mTotalTranslation;
CQuaternion mRotation; CQuaternion mRotation;
CVector3f mScale;
CVector3f mDeltaPosition;
CQuaternion mDeltaRotation; CQuaternion mDeltaRotation;
CQuaternion mTotalRotation;
CVector3f mScale;
CVector3f mDeltaScale; CVector3f mDeltaScale;
CVector3f mTotalScale;
bool mFlipScaleX; bool mFlipScaleX;
bool mFlipScaleY; bool mFlipScaleY;
bool mFlipScaleZ; bool mFlipScaleZ;
CPlane mTranslatePlane;
CVector3f mLastTranslatePosition;
CVector3f mTranslateOffset;
bool mSetOffset;
struct SModelPart struct SModelPart
{ {
EGizmoAxes modelAxes; EGizmoAxes modelAxes;
@ -104,12 +114,20 @@ public:
void IncrementSize(); void IncrementSize();
void DecrementSize(); void DecrementSize();
void UpdateForCamera(const CCamera& camera); void UpdateForCamera(const CCamera& camera);
bool IntersectsRay(const CRay& ray); bool CheckSelectedAxes(const CRay& ray);
u32 NumSelectedAxes();
void ResetSelectedAxes();
void StartTransform();
bool TransformFromInput(const CRay& ray, const CCamera& camera);
void EndTransform();
EGizmoMode Mode(); EGizmoMode Mode();
CVector3f Position();
CVector3f DeltaTranslation();
CVector3f TotalTranslation();
void SetMode(EGizmoMode mode); void SetMode(EGizmoMode mode);
void SetPosition(const CVector3f& position); void SetPosition(const CVector3f& position);
void ResetSelectedAxes(); void SetOrientation(const CQuaternion& orientation);
// Protected // Protected
protected: protected:

View File

@ -6,6 +6,7 @@
#include <iostream> #include <iostream>
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QFontMetrics> #include <QFontMetrics>
#include <QComboBox>
#include <Core/Log.h> #include <Core/Log.h>
#include "WDraggableSpinBox.h" #include "WDraggableSpinBox.h"
@ -32,6 +33,9 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
mpHoverNode = nullptr; mpHoverNode = nullptr;
mDrawSky = true; mDrawSky = true;
mShowGizmo = false; mShowGizmo = false;
mGizmoHovering = false;
mGizmoTransforming = false;
mUpdateUILater = false;
mFrameCount = 0; mFrameCount = 0;
mFPSTimer.Start(); mFPSTimer.Start();
@ -47,7 +51,6 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
delete pOldTitleBar; delete pOldTitleBar;
// Initialize UI stuff // Initialize UI stuff
ui->ModifyTabContents->SetEditor(this); ui->ModifyTabContents->SetEditor(this);
ui->InstancesTabContents->SetEditor(this, mpSceneManager); ui->InstancesTabContents->SetEditor(this, mpSceneManager);
@ -55,17 +58,27 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
ui->CamSpeedSpinBox->SetDefaultValue(1.0); ui->CamSpeedSpinBox->SetDefaultValue(1.0);
ResetHover(); ResetHover();
mTransformSpace = eWorldTransform;
QComboBox *pTransformCombo = new QComboBox(this);
pTransformCombo->setMinimumWidth(75);
pTransformCombo->addItem("World");
pTransformCombo->addItem("Local");
ui->MainToolBar->insertWidget(0, pTransformCombo);
// Initialize offscreen actions // Initialize offscreen actions
addAction(ui->ActionIncrementGizmo); addAction(ui->ActionIncrementGizmo);
addAction(ui->ActionDecrementGizmo); addAction(ui->ActionDecrementGizmo);
// Connect signals and slots // Connect signals and slots
connect(pTransformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(SetTransformSpace(int)));
connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double))); connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double)));
connect(ui->MainViewport, SIGNAL(PreRender()), this, SLOT(ViewportPreRender())); connect(ui->MainViewport, SIGNAL(PreRender()), this, SLOT(ViewportPreRender()));
connect(ui->MainViewport, SIGNAL(Render(CCamera&)), this, SLOT(ViewportRender(CCamera&))); connect(ui->MainViewport, SIGNAL(Render(CCamera&)), this, SLOT(ViewportRender(CCamera&)));
connect(ui->MainViewport, SIGNAL(ViewportResized(int,int)), this, SLOT(SetViewportSize(int,int))); connect(ui->MainViewport, SIGNAL(ViewportResized(int,int)), this, SLOT(SetViewportSize(int,int)));
connect(ui->MainViewport, SIGNAL(frameSwapped()), this, SLOT(ViewportPostRender())); connect(ui->MainViewport, SIGNAL(frameSwapped()), this, SLOT(ViewportPostRender()));
connect(ui->MainViewport, SIGNAL(MouseClick(QMouseEvent*)), this, SLOT(ViewportMouseClick(QMouseEvent*))); connect(ui->MainViewport, SIGNAL(MouseClick(QMouseEvent*)), this, SLOT(ViewportMouseClick(QMouseEvent*)));
connect(ui->MainViewport, SIGNAL(MouseRelease(QMouseEvent*)), this, SLOT(ViewportMouseRelease(QMouseEvent*)));
} }
CWorldEditor::~CWorldEditor() CWorldEditor::~CWorldEditor()
@ -135,28 +148,58 @@ void CWorldEditor::ViewportRayCast(CRay Ray)
{ {
if (!ui->MainViewport->IsMouseInputActive()) if (!ui->MainViewport->IsMouseInputActive())
{ {
// Gizmo ray check if (!mGizmoTransforming)
mGizmoHovering = mGizmo.IntersectsRay(Ray);
// Scene ray check
SRayIntersection Result = mpSceneManager->SceneRayCast(Ray);
if (Result.Hit)
{ {
if (mpHoverNode) // Gizmo hover check
mpHoverNode->SetMouseHovering(false); if (mShowGizmo && !mSelectedNodes.empty())
mGizmoHovering = mGizmo.CheckSelectedAxes(Ray);
else
{
mGizmoHovering = false;
mGizmo.ResetSelectedAxes();
}
mpHoverNode = Result.pNode; // Scene ray check
mpHoverNode->SetMouseHovering(true); SRayIntersection Result = mpSceneManager->SceneRayCast(Ray);
mHoverPoint = Ray.PointOnRay(Result.Distance); if (Result.Hit)
{
if (mpHoverNode)
mpHoverNode->SetMouseHovering(false);
mpHoverNode = Result.pNode;
mpHoverNode->SetMouseHovering(true);
mHoverPoint = Ray.PointOnRay(Result.Distance);
}
else
ResetHover();
} }
else else
ResetHover(); {
bool moved = mGizmo.TransformFromInput(Ray, ui->MainViewport->Camera());
if (moved)
{
CVector3f delta = mGizmo.DeltaTranslation();
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
{
(*it)->Translate(delta, mTransformSpace);
(*it)->BuildLightList(this->mpArea);
}
RecalculateSelectionBounds();
mUpdateUILater = true;
}
}
} }
else else
{ {
mGizmo.ResetSelectedAxes(); if (!mGizmoTransforming)
{
mGizmoHovering = false;
mGizmo.ResetSelectedAxes();
}
ResetHover(); ResetHover();
} }
} }
@ -229,44 +272,73 @@ void CWorldEditor::ClearSelection()
// ************ SLOTS ************ // ************ SLOTS ************
void CWorldEditor::ViewportMouseDrag(QMouseEvent *pEvent) void CWorldEditor::ViewportMouseDrag(QMouseEvent *pEvent)
{ {
// todo: gizmo translate/rotate/scale implementation
} }
void CWorldEditor::ViewportMouseClick(QMouseEvent *pEvent) void CWorldEditor::ViewportMouseClick(QMouseEvent *pEvent)
{ {
// Process left click (button press) bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
if (mGizmoHovering && !AltPressed && !CtrlPressed)
{
mGizmoTransforming = true;
mGizmo.StartTransform();
}
}
void CWorldEditor::ViewportMouseRelease(QMouseEvent *pEvent)
{
if (pEvent->button() == Qt::LeftButton) if (pEvent->button() == Qt::LeftButton)
{ {
bool ValidNode = ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode)); // Gizmo transform stop
bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0); if (mGizmoTransforming)
bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
// Alt pressed - deselect object
if (AltPressed)
{ {
// No valid node selected - do nothing mGizmoTransforming = false;
if (!ValidNode)
return;
DeselectNode(mpHoverNode);
} }
// Other - select object // Object selection/deselection
else else if (!ui->MainViewport->IsMouseInputActive())
{ {
// Control not pressed - clear existing selection bool ValidNode = ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode));
if (!CtrlPressed) bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
ClearSelection(); bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
// Add hover node to selection // Alt pressed - deselect object
if (ValidNode) if (AltPressed)
SelectNode(mpHoverNode); {
// No valid node selected - do nothing
if (!ValidNode)
return;
DeselectNode(mpHoverNode);
}
// Ctrl pressed - add object to selection
else if (CtrlPressed)
{
// Add hover node to selection
if (ValidNode)
SelectNode(mpHoverNode);
}
// Neither pressed
else
{
// If the gizmo isn't under the mouse, clear existing selection + select object (if applicable)
if (!mGizmoHovering)
{
ClearSelection();
if (ValidNode)
SelectNode(mpHoverNode);
}
}
UpdateSelectionUI();
} }
UpdateSelectionUI();
} }
// Later, possibly expand to context menu creation for right-click // todo: context menu creation on right-click goes here
} }
// ************ SLOTS ************ // ************ SLOTS ************
@ -298,8 +370,10 @@ void CWorldEditor::ViewportRender(CCamera& Camera)
if (mShowGizmo && (mSelectedNodes.size() > 0)) if (mShowGizmo && (mSelectedNodes.size() > 0))
{ {
mpRenderer->ClearDepthBuffer();
Camera.LoadMatrices(); Camera.LoadMatrices();
mGizmo.UpdateForCamera(Camera); if (!mGizmoTransforming) mGizmo.UpdateForCamera(Camera);
mGizmo.AddToRenderer(mpRenderer); mGizmo.AddToRenderer(mpRenderer);
if (mGizmo.Mode() == CGizmo::eRotate) if (mGizmo.Mode() == CGizmo::eRotate)
@ -318,6 +392,12 @@ void CWorldEditor::ViewportPostRender()
// Update UI with raycast results // Update UI with raycast results
UpdateCursor(); UpdateCursor();
UpdateStatusBar(); UpdateStatusBar();
if (mUpdateUILater)
{
UpdateSelectionUI();
mUpdateUILater = false;
}
} }
void CWorldEditor::SetViewportSize(int Width, int Height) void CWorldEditor::SetViewportSize(int Width, int Height)
@ -325,6 +405,22 @@ void CWorldEditor::SetViewportSize(int Width, int Height)
mpRenderer->SetViewportSize(Width, Height); mpRenderer->SetViewportSize(Width, Height);
} }
void CWorldEditor::SetTransformSpace(int space)
{
switch (space)
{
case 0:
mTransformSpace = eWorldTransform;
mGizmo.SetOrientation(CQuaternion::skIdentity);
break;
case 1:
mTransformSpace = eLocalTransform;
if (!mSelectedNodes.empty())
mGizmo.SetOrientation(mSelectedNodes.front()->AbsoluteRotation());
break;
}
}
// ************ PRIVATE ************ // ************ PRIVATE ************
void CWorldEditor::RecalculateSelectionBounds() void CWorldEditor::RecalculateSelectionBounds()
{ {
@ -396,13 +492,21 @@ void CWorldEditor::UpdateSelectionUI()
ui->SelectionInfoLabel->setText(SelectionText); ui->SelectionInfoLabel->setText(SelectionText);
// Update transform // Update transform
CVector3f pos = (!mSelectedNodes.empty() ? mSelectedNodes.front()->GetAbsolutePosition() : CVector3f::skZero); CVector3f pos = (!mSelectedNodes.empty() ? mSelectedNodes.front()->AbsolutePosition() : CVector3f::skZero);
ui->XSpinBox->setValue(pos.x); ui->XSpinBox->setValue(pos.x);
ui->YSpinBox->setValue(pos.y); ui->YSpinBox->setValue(pos.y);
ui->ZSpinBox->setValue(pos.z); ui->ZSpinBox->setValue(pos.z);
// Update gizmo // Update gizmo
mGizmo.SetPosition(pos); if (!mGizmoTransforming)
{
mGizmo.SetPosition(pos);
if ((mTransformSpace == eLocalTransform) && !mSelectedNodes.empty())
mGizmo.SetOrientation(mSelectedNodes.front()->AbsoluteRotation());
else
mGizmo.SetOrientation(CQuaternion::skIdentity);
}
} }
// ************ ACTIONS ************ // ************ ACTIONS ************

View File

@ -9,6 +9,7 @@
#include <Common/CTimer.h> #include <Common/CTimer.h>
#include <Common/EKeyInputs.h> #include <Common/EKeyInputs.h>
#include <Common/SRayIntersection.h> #include <Common/SRayIntersection.h>
#include <Common/ETransformSpace.h>
#include <Core/CRenderer.h> #include <Core/CRenderer.h>
#include <Core/CSceneManager.h> #include <Core/CSceneManager.h>
#include <Core/CToken.h> #include <Core/CToken.h>
@ -25,6 +26,7 @@ class CWorldEditor : public QMainWindow
CRenderer *mpRenderer; CRenderer *mpRenderer;
CSceneManager *mpSceneManager; CSceneManager *mpSceneManager;
CGizmo mGizmo; CGizmo mGizmo;
ETransformSpace mTransformSpace;
CCamera mCamera; CCamera mCamera;
CGameArea *mpArea; CGameArea *mpArea;
CWorld *mpWorld; CWorld *mpWorld;
@ -34,6 +36,8 @@ class CWorldEditor : public QMainWindow
bool mDrawSky; bool mDrawSky;
bool mShowGizmo; bool mShowGizmo;
bool mGizmoHovering; bool mGizmoHovering;
bool mGizmoTransforming;
bool mUpdateUILater;
CVector3f mHoverPoint; CVector3f mHoverPoint;
CSceneNode *mpHoverNode; CSceneNode *mpHoverNode;
@ -64,7 +68,9 @@ public slots:
void ViewportPostRender(); void ViewportPostRender();
void ViewportMouseDrag(QMouseEvent *pEvent); void ViewportMouseDrag(QMouseEvent *pEvent);
void ViewportMouseClick(QMouseEvent *pEvent); void ViewportMouseClick(QMouseEvent *pEvent);
void ViewportMouseRelease(QMouseEvent *pEvent);
void SetViewportSize(int Width, int Height); void SetViewportSize(int Width, int Height);
void SetTransformSpace(int space);
private: private:
Ui::CWorldEditor *ui; Ui::CWorldEditor *ui;

View File

@ -440,13 +440,16 @@
<addaction name="menuWindow"/> <addaction name="menuWindow"/>
</widget> </widget>
<widget class="QStatusBar" name="statusbar"/> <widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="Toolbar"> <widget class="QToolBar" name="FileToolBar">
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum> <enum>Qt::NoContextMenu</enum>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>toolBar_2</string> <string>toolBar_2</string>
</property> </property>
<property name="movable">
<bool>false</bool>
</property>
<attribute name="toolBarArea"> <attribute name="toolBarArea">
<enum>TopToolBarArea</enum> <enum>TopToolBarArea</enum>
</attribute> </attribute>
@ -593,13 +596,19 @@
</layout> </layout>
</widget> </widget>
</widget> </widget>
<widget class="QToolBar" name="toolBar"> <widget class="QToolBar" name="MainToolBar">
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum> <enum>Qt::NoContextMenu</enum>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>toolBar</string> <string>toolBar</string>
</property> </property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<attribute name="toolBarArea"> <attribute name="toolBarArea">
<enum>TopToolBarArea</enum> <enum>TopToolBarArea</enum>
</attribute> </attribute>