|
@@ -1,1961 +0,0 @@
|
|
|
-/*
|
|
|
- * 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
|
|
|
- *
|
|
|
- */
|
|
|
-
|
|
|
-
|
|
|
-// Description : CBaseObject implementation.
|
|
|
-
|
|
|
-
|
|
|
-#include "EditorDefs.h"
|
|
|
-
|
|
|
-#include "BaseObject.h"
|
|
|
-
|
|
|
-// Azframework
|
|
|
-#include <AzFramework/Terrain/TerrainDataRequestBus.h> // for AzFramework::Terrain::TerrainDataRequests
|
|
|
-
|
|
|
-// AzToolsFramework
|
|
|
-#include <AzToolsFramework/API/ComponentEntityObjectBus.h> // for ComponentEntityObjectRequestBus
|
|
|
-
|
|
|
-// Editor
|
|
|
-#include "Settings.h"
|
|
|
-#include "Viewport.h"
|
|
|
-#include "DisplaySettings.h"
|
|
|
-#include "Undo/Undo.h"
|
|
|
-#include "UsedResources.h"
|
|
|
-#include "Objects/ObjectManager.h"
|
|
|
-#include "ViewManager.h"
|
|
|
-#include "IEditorImpl.h"
|
|
|
-#include "GameEngine.h"
|
|
|
-// To use the Andrew's algorithm in order to make convex hull from the points, this header is needed.
|
|
|
-#include "Util/GeometryUtil.h"
|
|
|
-
|
|
|
-extern CObjectManager* g_pObjectManager;
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//! Undo object for CBaseObject.
|
|
|
-class CUndoBaseObject
|
|
|
- : public IUndoObject
|
|
|
-{
|
|
|
-public:
|
|
|
- CUndoBaseObject(CBaseObject* pObj);
|
|
|
-
|
|
|
-protected:
|
|
|
- int GetSize() override { return sizeof(*this); }
|
|
|
- QString GetObjectName() override;
|
|
|
-
|
|
|
- void Undo(bool bUndo) override;
|
|
|
- void Redo() override;
|
|
|
-
|
|
|
-protected:
|
|
|
- GUID m_guid;
|
|
|
- XmlNodeRef m_undo;
|
|
|
- XmlNodeRef m_redo;
|
|
|
-};
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//! Undo object for CBaseObject that only stores its transform, color, area
|
|
|
-class CUndoBaseObjectMinimal
|
|
|
- : public IUndoObject
|
|
|
-{
|
|
|
-public:
|
|
|
- CUndoBaseObjectMinimal(CBaseObject* obj, int flags);
|
|
|
-
|
|
|
-protected:
|
|
|
- int GetSize() override { return sizeof(*this); }
|
|
|
- QString GetObjectName() override;
|
|
|
-
|
|
|
- void Undo(bool bUndo) override;
|
|
|
- void Redo() override;
|
|
|
-
|
|
|
-private:
|
|
|
- struct StateStruct
|
|
|
- {
|
|
|
- Vec3 pos;
|
|
|
- Quat rotate;
|
|
|
- Vec3 scale;
|
|
|
- QColor color;
|
|
|
- float area;
|
|
|
- };
|
|
|
-
|
|
|
- void SetTransformsFromState(CBaseObject* pObject, const StateStruct& state, bool bUndo);
|
|
|
-
|
|
|
- GUID m_guid;
|
|
|
- StateStruct m_undoState;
|
|
|
- StateStruct m_redoState;
|
|
|
-};
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//! Undo object for attach/detach changes
|
|
|
-class CUndoAttachBaseObject
|
|
|
- : public IUndoObject
|
|
|
-{
|
|
|
-public:
|
|
|
- CUndoAttachBaseObject(CBaseObject* pAttachedObject, bool bKeepPos, bool bAttach)
|
|
|
- : m_attachedObjectGUID(pAttachedObject->GetId())
|
|
|
- , m_parentObjectGUID(pAttachedObject->GetParent()->GetId())
|
|
|
- , m_bKeepPos(bKeepPos)
|
|
|
- , m_bAttach(bAttach) {}
|
|
|
-
|
|
|
- void Undo([[maybe_unused]] bool bUndo) override
|
|
|
- {
|
|
|
- if (m_bAttach)
|
|
|
- {
|
|
|
- Detach();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- Attach();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void Redo() override
|
|
|
- {
|
|
|
- if (m_bAttach)
|
|
|
- {
|
|
|
- Attach();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- Detach();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-private:
|
|
|
- void Attach()
|
|
|
- {
|
|
|
- CObjectManager* pObjectManager = static_cast<CObjectManager*>(GetIEditor()->GetObjectManager());
|
|
|
- CBaseObject* pObject = pObjectManager->FindObject(m_attachedObjectGUID);
|
|
|
- CBaseObject* pParentObject = pObjectManager->FindObject(m_parentObjectGUID);
|
|
|
-
|
|
|
- if (pObject && pParentObject)
|
|
|
- {
|
|
|
- pParentObject->AttachChild(pObject, m_bKeepPos);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void Detach()
|
|
|
- {
|
|
|
- CObjectManager* pObjectManager = static_cast<CObjectManager*>(GetIEditor()->GetObjectManager());
|
|
|
- CBaseObject* pObject = pObjectManager->FindObject(m_attachedObjectGUID);
|
|
|
-
|
|
|
- if (pObject)
|
|
|
- {
|
|
|
- pObject->DetachThis(m_bKeepPos);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- int GetSize() override { return sizeof(CUndoAttachBaseObject); }
|
|
|
-
|
|
|
- GUID m_attachedObjectGUID;
|
|
|
- GUID m_parentObjectGUID;
|
|
|
- bool m_bKeepPos;
|
|
|
- bool m_bAttach;
|
|
|
-};
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-CUndoBaseObject::CUndoBaseObject(CBaseObject* obj)
|
|
|
-{
|
|
|
- // Stores the current state of this object.
|
|
|
- assert(obj != 0);
|
|
|
- m_guid = obj->GetId();
|
|
|
-
|
|
|
- m_redo = nullptr;
|
|
|
- m_undo = XmlHelpers::CreateXmlNode("Undo");
|
|
|
- CObjectArchive ar(GetIEditor()->GetObjectManager(), m_undo, false);
|
|
|
- ar.bUndo = true;
|
|
|
- obj->Serialize(ar);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-QString CUndoBaseObject::GetObjectName()
|
|
|
-{
|
|
|
- if (CBaseObject* obj = GetIEditor()->GetObjectManager()->FindObject(m_guid))
|
|
|
- {
|
|
|
- return obj->GetName();
|
|
|
- }
|
|
|
- return QString();
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CUndoBaseObject::Undo(bool bUndo)
|
|
|
-{
|
|
|
- CBaseObject* pObject = GetIEditor()->GetObjectManager()->FindObject(m_guid);
|
|
|
- if (!pObject)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- GetIEditor()->SuspendUndo();
|
|
|
-
|
|
|
- if (bUndo)
|
|
|
- {
|
|
|
- m_redo = XmlHelpers::CreateXmlNode("Redo");
|
|
|
- // Save current object state.
|
|
|
- CObjectArchive ar(GetIEditor()->GetObjectManager(), m_redo, false);
|
|
|
- ar.bUndo = true;
|
|
|
- pObject->Serialize(ar);
|
|
|
- }
|
|
|
-
|
|
|
- // Undo object state.
|
|
|
- CObjectArchive ar(GetIEditor()->GetObjectManager(), m_undo, true);
|
|
|
- ar.bUndo = true;
|
|
|
- pObject->Serialize(ar);
|
|
|
-
|
|
|
- GetIEditor()->ResumeUndo();
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CUndoBaseObject::Redo()
|
|
|
-{
|
|
|
- CBaseObject* pObject = GetIEditor()->GetObjectManager()->FindObject(m_guid);
|
|
|
- if (!pObject)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- GetIEditor()->SuspendUndo();
|
|
|
-
|
|
|
- CObjectArchive ar(GetIEditor()->GetObjectManager(), m_redo, true);
|
|
|
- ar.bUndo = true;
|
|
|
-
|
|
|
- pObject->Serialize(ar);
|
|
|
-
|
|
|
- GetIEditor()->ResumeUndo();
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-CUndoBaseObjectMinimal::CUndoBaseObjectMinimal(CBaseObject* pObj, [[maybe_unused]] int flags)
|
|
|
-{
|
|
|
- // Stores the current state of this object.
|
|
|
- assert(pObj != nullptr);
|
|
|
- m_guid = pObj->GetId();
|
|
|
-
|
|
|
- ZeroStruct(m_redoState);
|
|
|
-
|
|
|
- m_undoState.pos = pObj->GetPos();
|
|
|
- m_undoState.rotate = pObj->GetRotation();
|
|
|
- m_undoState.scale = pObj->GetScale();
|
|
|
- m_undoState.color = pObj->GetColor();
|
|
|
- m_undoState.area = pObj->GetArea();
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-QString CUndoBaseObjectMinimal::GetObjectName()
|
|
|
-{
|
|
|
- CBaseObject* pObject = GetIEditor()->GetObjectManager()->FindObject(m_guid);
|
|
|
- if (!pObject)
|
|
|
- {
|
|
|
- return QString();
|
|
|
- }
|
|
|
-
|
|
|
- return pObject->GetName();
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CUndoBaseObjectMinimal::Undo(bool bUndo)
|
|
|
-{
|
|
|
- CBaseObject* pObject = GetIEditor()->GetObjectManager()->FindObject(m_guid);
|
|
|
- if (!pObject)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (bUndo)
|
|
|
- {
|
|
|
- m_redoState.pos = pObject->GetPos();
|
|
|
- m_redoState.scale = pObject->GetScale();
|
|
|
- m_redoState.rotate = pObject->GetRotation();
|
|
|
- m_redoState.color = pObject->GetColor();
|
|
|
- m_redoState.area = pObject->GetArea();
|
|
|
- }
|
|
|
-
|
|
|
- SetTransformsFromState(pObject, m_undoState, bUndo);
|
|
|
-
|
|
|
- pObject->ChangeColor(m_undoState.color);
|
|
|
- pObject->SetArea(m_undoState.area);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CUndoBaseObjectMinimal::Redo()
|
|
|
-{
|
|
|
- CBaseObject* pObject = GetIEditor()->GetObjectManager()->FindObject(m_guid);
|
|
|
- if (!pObject)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- SetTransformsFromState(pObject, m_redoState, true);
|
|
|
-
|
|
|
- pObject->ChangeColor(m_redoState.color);
|
|
|
- pObject->SetArea(m_redoState.area);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CUndoBaseObjectMinimal::SetTransformsFromState(CBaseObject* pObject, const StateStruct& state, bool bUndo)
|
|
|
-{
|
|
|
- uint32 flags = eObjectUpdateFlags_Undo;
|
|
|
- if (!bUndo)
|
|
|
- {
|
|
|
- flags |= eObjectUpdateFlags_UserInputUndo;
|
|
|
- }
|
|
|
-
|
|
|
- pObject->SetPos(state.pos, flags);
|
|
|
- pObject->SetScale(state.scale, flags);
|
|
|
- pObject->SetRotation(state.rotate, flags);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CObjectCloneContext::AddClone(CBaseObject* pFromObject, CBaseObject* pToObject)
|
|
|
-{
|
|
|
- m_objectsMap[pFromObject] = pToObject;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-CBaseObject* CObjectCloneContext::FindClone(CBaseObject* pFromObject)
|
|
|
-{
|
|
|
- CBaseObject* pTarget = stl::find_in_map(m_objectsMap, pFromObject, (CBaseObject*) nullptr);
|
|
|
- return pTarget;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-GUID CObjectCloneContext::ResolveClonedID(REFGUID guid)
|
|
|
-{
|
|
|
- CBaseObject* pObject = GetIEditor()->GetObjectManager()->FindObject(guid);
|
|
|
- CBaseObject* pClonedTarget = FindClone(pObject);
|
|
|
- if (!pClonedTarget)
|
|
|
- {
|
|
|
- pClonedTarget = pObject; // If target not cloned, link to original target.
|
|
|
- }
|
|
|
- if (pClonedTarget)
|
|
|
- {
|
|
|
- return pClonedTarget->GetId();
|
|
|
- }
|
|
|
- return GUID_NULL;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-// CBaseObject implementation.
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-CBaseObject::CBaseObject()
|
|
|
- : m_pos(0, 0, 0)
|
|
|
- , m_rotate(IDENTITY)
|
|
|
- , m_scale(1, 1, 1)
|
|
|
- , m_guid(GUID_NULL)
|
|
|
- , m_flags(0)
|
|
|
- , m_nTextureIcon(0)
|
|
|
- , m_color(QColor(255, 255, 255))
|
|
|
- , m_worldTM(IDENTITY)
|
|
|
- , m_lookat(nullptr)
|
|
|
- , m_lookatSource(nullptr)
|
|
|
- , m_flattenArea(0.f)
|
|
|
- , m_classDesc(nullptr)
|
|
|
- , m_numRefs(0)
|
|
|
- , m_parent(nullptr)
|
|
|
- , m_bInSelectionBox(false)
|
|
|
- , m_pTransformDelegate(nullptr)
|
|
|
- , m_bMatrixInWorldSpace(false)
|
|
|
- , m_bMatrixValid(false)
|
|
|
- , m_bWorldBoxValid(false)
|
|
|
- , m_vDrawIconPos(0, 0, 0)
|
|
|
- , m_nIconFlags(0)
|
|
|
-{
|
|
|
- m_worldBounds.min.Set(0, 0, 0);
|
|
|
- m_worldBounds.max.Set(0, 0, 0);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-IObjectManager* CBaseObject::GetObjectManager() const
|
|
|
-{
|
|
|
- return g_pObjectManager;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-void CBaseObject::SetClassDesc(CObjectClassDesc* classDesc)
|
|
|
-{
|
|
|
- m_classDesc = classDesc;
|
|
|
-}
|
|
|
-
|
|
|
-//! Initialize Object.
|
|
|
-bool CBaseObject::Init([[maybe_unused]] IEditor* ie, CBaseObject* prev, [[maybe_unused]] const QString& file)
|
|
|
-{
|
|
|
- SetFlags(m_flags & (~OBJFLAG_DELETED));
|
|
|
-
|
|
|
- if (prev != nullptr)
|
|
|
- {
|
|
|
- SetUniqueName(prev->GetName());
|
|
|
- SetLocalTM(prev->GetPos(), prev->GetRotation(), prev->GetScale());
|
|
|
- SetArea(prev->GetArea());
|
|
|
- SetColor(prev->GetColor());
|
|
|
-
|
|
|
- // Copy all basic variables.
|
|
|
- EnableUpdateCallbacks(false);
|
|
|
- CopyVariableValues(prev);
|
|
|
- EnableUpdateCallbacks(true);
|
|
|
- OnSetValues();
|
|
|
- }
|
|
|
-
|
|
|
- if (m_classDesc->RenderTextureOnTop())
|
|
|
- {
|
|
|
- SetFlags(OBJFLAG_SHOW_ICONONTOP);
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-CBaseObject::~CBaseObject()
|
|
|
-{
|
|
|
- for (Childs::iterator c = m_childs.begin(); c != m_childs.end(); c++)
|
|
|
- {
|
|
|
- CBaseObject* child = *c;
|
|
|
- child->m_parent = nullptr;
|
|
|
- }
|
|
|
- m_childs.clear();
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::Done()
|
|
|
-{
|
|
|
- DetachThis();
|
|
|
-
|
|
|
- // From children
|
|
|
- DetachAll();
|
|
|
-
|
|
|
- SetLookAt(nullptr);
|
|
|
- if (m_lookatSource)
|
|
|
- {
|
|
|
- m_lookatSource->SetLookAt(nullptr);
|
|
|
- }
|
|
|
- SetFlags(m_flags | OBJFLAG_DELETED);
|
|
|
-
|
|
|
- NotifyListeners(CBaseObject::ON_DELETE);
|
|
|
- m_eventListeners.clear();
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetName(const QString& name)
|
|
|
-{
|
|
|
- if (name == m_name)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- StoreUndo();
|
|
|
-
|
|
|
- // Notification is expensive and not required if this is during construction.
|
|
|
- bool notify = (!m_name.isEmpty());
|
|
|
-
|
|
|
- m_name = name;
|
|
|
- GetObjectManager()->RegisterObjectName(name);
|
|
|
- SetModified(false);
|
|
|
-
|
|
|
- if (notify)
|
|
|
- {
|
|
|
- NotifyListeners(ON_RENAME);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetUniqueName(const QString& name)
|
|
|
-{
|
|
|
- SetName(GetObjectManager()->GenerateUniqueObjectName(name));
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::GenerateUniqueName()
|
|
|
-{
|
|
|
- if (m_classDesc)
|
|
|
- {
|
|
|
- SetUniqueName(m_classDesc->ClassName());
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- SetUniqueName("Object");
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-const QString& CBaseObject::GetName() const
|
|
|
-{
|
|
|
- return m_name;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::SetPos(const Vec3& pos, int flags)
|
|
|
-{
|
|
|
- const Vec3 currentPos = GetPos();
|
|
|
-
|
|
|
- bool equal = false;
|
|
|
- if (flags & eObjectUpdateFlags_MoveTool) // very sensitive in case of the move tool
|
|
|
- {
|
|
|
- equal = IsVectorsEqual(currentPos, pos, 0.0f);
|
|
|
- }
|
|
|
- else // less sensitive for others
|
|
|
- {
|
|
|
- equal = IsVectorsEqual(currentPos, pos);
|
|
|
- }
|
|
|
-
|
|
|
- if (equal)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- // Check if position is bad.
|
|
|
- if (fabs(pos.x) > AZ::Constants::MaxFloatBeforePrecisionLoss ||
|
|
|
- fabs(pos.y) > AZ::Constants::MaxFloatBeforePrecisionLoss ||
|
|
|
- fabs(pos.z) > AZ::Constants::MaxFloatBeforePrecisionLoss ||
|
|
|
- !_finite(pos.x) || !_finite(pos.y) || !_finite(pos.z))
|
|
|
- {
|
|
|
- CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING,
|
|
|
- "Object %s, SetPos called with invalid position: (%f,%f,%f)",
|
|
|
- GetName().toUtf8().data(), pos.x, pos.y, pos.z);
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- OnBeforeAreaChange();
|
|
|
-
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- const bool bPositionDelegated = m_pTransformDelegate && m_pTransformDelegate->IsPositionDelegated();
|
|
|
- if (m_pTransformDelegate && (flags & eObjectUpdateFlags_Animated) == 0)
|
|
|
- {
|
|
|
- m_pTransformDelegate->SetTransformDelegatePos(pos);
|
|
|
- }
|
|
|
-
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- if (!bPositionDelegated && (flags & eObjectUpdateFlags_RestoreUndo) == 0 && (flags & eObjectUpdateFlags_Animated) == 0)
|
|
|
- {
|
|
|
- StoreUndo(true, flags);
|
|
|
- }
|
|
|
-
|
|
|
- if (!bPositionDelegated)
|
|
|
- {
|
|
|
- m_pos = pos;
|
|
|
- }
|
|
|
-
|
|
|
- if (!(flags & eObjectUpdateFlags_DoNotInvalidate))
|
|
|
- {
|
|
|
- InvalidateTM(flags | eObjectUpdateFlags_PositionChanged);
|
|
|
- }
|
|
|
-
|
|
|
- SetModified(true);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::SetRotation(const Quat& rotate, int flags)
|
|
|
-{
|
|
|
- const Quat currentRotate = GetRotation();
|
|
|
-
|
|
|
- if (currentRotate.w == rotate.w && currentRotate.v.x == rotate.v.x
|
|
|
- && currentRotate.v.y == rotate.v.y && currentRotate.v.z == rotate.v.z)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (flags & eObjectUpdateFlags_ScaleTool)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- OnBeforeAreaChange();
|
|
|
-
|
|
|
- const bool bRotationDelegated = m_pTransformDelegate && m_pTransformDelegate->IsRotationDelegated();
|
|
|
- if (m_pTransformDelegate && (flags & eObjectUpdateFlags_Animated) == 0)
|
|
|
- {
|
|
|
- m_pTransformDelegate->SetTransformDelegateRotation(rotate);
|
|
|
- }
|
|
|
-
|
|
|
- if (!bRotationDelegated && (flags & eObjectUpdateFlags_RestoreUndo) == 0 && (flags & eObjectUpdateFlags_Animated) == 0)
|
|
|
- {
|
|
|
- StoreUndo(true, flags);
|
|
|
- }
|
|
|
-
|
|
|
- if (!bRotationDelegated)
|
|
|
- {
|
|
|
- m_rotate = rotate;
|
|
|
- }
|
|
|
-
|
|
|
- if (m_bMatrixValid && !(flags & eObjectUpdateFlags_DoNotInvalidate))
|
|
|
- {
|
|
|
- InvalidateTM(flags | eObjectUpdateFlags_RotationChanged);
|
|
|
- }
|
|
|
-
|
|
|
- SetModified(true);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::SetScale(const Vec3& scale, int flags)
|
|
|
-{
|
|
|
- if (IsVectorsEqual(GetScale(), scale))
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- // Check if scale is bad.
|
|
|
- if (scale.x < 0.01f || scale.y < 0.01f || scale.z < 0.01f)
|
|
|
- {
|
|
|
- CryWarning(VALIDATOR_MODULE_EDITOR, VALIDATOR_WARNING, "Object %s, SetScale called with invalid scale: (%f,%f,%f)", GetName().toUtf8().data(), scale.x, scale.y, scale.z);
|
|
|
- return false;
|
|
|
- }
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
- OnBeforeAreaChange();
|
|
|
-
|
|
|
- const bool bScaleDelegated = m_pTransformDelegate && m_pTransformDelegate->IsScaleDelegated();
|
|
|
- if (m_pTransformDelegate && (flags & eObjectUpdateFlags_Animated) == 0)
|
|
|
- {
|
|
|
- m_pTransformDelegate->SetTransformDelegateScale(scale);
|
|
|
- }
|
|
|
-
|
|
|
- if (!bScaleDelegated && (flags & eObjectUpdateFlags_RestoreUndo) == 0 && (flags & eObjectUpdateFlags_Animated) == 0)
|
|
|
- {
|
|
|
- StoreUndo(true, flags);
|
|
|
- }
|
|
|
-
|
|
|
- if (!bScaleDelegated)
|
|
|
- {
|
|
|
- m_scale = scale;
|
|
|
- }
|
|
|
-
|
|
|
- if (m_bMatrixValid && !(flags & eObjectUpdateFlags_DoNotInvalidate))
|
|
|
- {
|
|
|
- InvalidateTM(flags | eObjectUpdateFlags_ScaleChanged);
|
|
|
- }
|
|
|
-
|
|
|
- SetModified(true);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-const Vec3 CBaseObject::GetPos() const
|
|
|
-{
|
|
|
- if (!m_pTransformDelegate)
|
|
|
- {
|
|
|
- return m_pos;
|
|
|
- }
|
|
|
-
|
|
|
- return m_pTransformDelegate->GetTransformDelegatePos(m_pos);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-const Quat CBaseObject::GetRotation() const
|
|
|
-{
|
|
|
- if (!m_pTransformDelegate)
|
|
|
- {
|
|
|
- return m_rotate;
|
|
|
- }
|
|
|
-
|
|
|
- return m_pTransformDelegate->GetTransformDelegateRotation(m_rotate);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-const Vec3 CBaseObject::GetScale() const
|
|
|
-{
|
|
|
- if (!m_pTransformDelegate)
|
|
|
- {
|
|
|
- return m_scale;
|
|
|
- }
|
|
|
-
|
|
|
- return m_pTransformDelegate->GetTransformDelegateScale(m_scale);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::ChangeColor(const QColor& color)
|
|
|
-{
|
|
|
- if (color == m_color)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- StoreUndo(true);
|
|
|
-
|
|
|
- SetColor(color);
|
|
|
- SetModified(false);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetColor(const QColor& color)
|
|
|
-{
|
|
|
- m_color = color;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetArea(float area)
|
|
|
-{
|
|
|
- if (m_flattenArea == area)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- StoreUndo(true);
|
|
|
-
|
|
|
- m_flattenArea = area;
|
|
|
- SetModified(false);
|
|
|
-};
|
|
|
-
|
|
|
-//! Get bounding box of object in world coordinate space.
|
|
|
-void CBaseObject::GetBoundBox(AABB& box)
|
|
|
-{
|
|
|
- if (!m_bWorldBoxValid)
|
|
|
- {
|
|
|
- GetLocalBounds(m_worldBounds);
|
|
|
- if (!m_worldBounds.IsReset() && !m_worldBounds.IsEmpty())
|
|
|
- {
|
|
|
- m_worldBounds.SetTransformedAABB(GetWorldTM(), m_worldBounds);
|
|
|
- m_bWorldBoxValid = true;
|
|
|
- }
|
|
|
- }
|
|
|
- box = m_worldBounds;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::GetLocalBounds(AABB& box)
|
|
|
-{
|
|
|
- box.min.Set(0, 0, 0);
|
|
|
- box.max.Set(0, 0, 0);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetModified(bool)
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::OnEvent(ObjectEvent event)
|
|
|
-{
|
|
|
- switch (event)
|
|
|
- {
|
|
|
- case EVENT_CONFIG_SPEC_CHANGE:
|
|
|
- UpdateVisibility(!IsHidden());
|
|
|
- break;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetHidden(bool bHidden, bool bAnimated)
|
|
|
-{
|
|
|
- if (CheckFlags(OBJFLAG_HIDDEN) != bHidden)
|
|
|
- {
|
|
|
- if (!bAnimated)
|
|
|
- {
|
|
|
- StoreUndo();
|
|
|
- }
|
|
|
-
|
|
|
- if (bHidden)
|
|
|
- {
|
|
|
- SetFlags(OBJFLAG_HIDDEN);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ClearFlags(OBJFLAG_HIDDEN);
|
|
|
- }
|
|
|
-
|
|
|
- UpdateVisibility(!IsHidden());
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetFrozen(bool bFrozen)
|
|
|
-{
|
|
|
- if (CheckFlags(OBJFLAG_FROZEN) != bFrozen)
|
|
|
- {
|
|
|
- StoreUndo();
|
|
|
- if (bFrozen)
|
|
|
- {
|
|
|
- SetFlags(OBJFLAG_FROZEN);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ClearFlags(OBJFLAG_FROZEN);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetHighlight(bool bHighlight)
|
|
|
-{
|
|
|
- if (bHighlight)
|
|
|
- {
|
|
|
- SetFlags(OBJFLAG_HIGHLIGHT);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ClearFlags(OBJFLAG_HIGHLIGHT);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetSelected(bool bSelect)
|
|
|
-{
|
|
|
- if (bSelect)
|
|
|
- {
|
|
|
- SetFlags(OBJFLAG_SELECTED);
|
|
|
- NotifyListeners(ON_SELECT);
|
|
|
-
|
|
|
- //CLogFile::FormatLine( "Selected: %s, ID=%u",(const char*)m_name,m_id );
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- ClearFlags(OBJFLAG_SELECTED);
|
|
|
- NotifyListeners(ON_UNSELECT);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//! Returns true if object hidden.
|
|
|
-bool CBaseObject::IsHidden() const
|
|
|
-{
|
|
|
- return (CheckFlags(OBJFLAG_HIDDEN)) ||
|
|
|
- (m_classDesc && (gSettings.objectHideMask & GetType()));
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//! Returns true if object frozen.
|
|
|
-bool CBaseObject::IsFrozen() const
|
|
|
-{
|
|
|
- return CheckFlags(OBJFLAG_FROZEN);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::IsSelectable() const
|
|
|
-{
|
|
|
- // Not selectable if frozen.
|
|
|
- return IsFrozen() ? false : true;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::Serialize(CObjectArchive& ar)
|
|
|
-{
|
|
|
- XmlNodeRef xmlNode = ar.node;
|
|
|
-
|
|
|
- ITransformDelegate* pTransformDelegate = m_pTransformDelegate;
|
|
|
- m_pTransformDelegate = nullptr;
|
|
|
-
|
|
|
- if (ar.bLoading)
|
|
|
- {
|
|
|
- // Loading.
|
|
|
- int flags = 0;
|
|
|
- int oldFlags = m_flags;
|
|
|
-
|
|
|
- QString name = m_name;
|
|
|
- QString mtlName;
|
|
|
-
|
|
|
- Vec3 pos = m_pos;
|
|
|
- Vec3 scale = m_scale;
|
|
|
- Quat quat = m_rotate;
|
|
|
- Ang3 angles(0, 0, 0);
|
|
|
-
|
|
|
- QColor color = m_color;
|
|
|
- float flattenArea = m_flattenArea;
|
|
|
-
|
|
|
- GUID parentId = GUID_NULL;
|
|
|
- GUID lookatId = GUID_NULL;
|
|
|
-
|
|
|
- xmlNode->getAttr("Name", name);
|
|
|
- xmlNode->getAttr("Pos", pos);
|
|
|
- if (!xmlNode->getAttr("Rotate", quat))
|
|
|
- {
|
|
|
- // Backward compatibility.
|
|
|
- if (xmlNode->getAttr("Angles", angles))
|
|
|
- {
|
|
|
- angles = DEG2RAD(angles);
|
|
|
- //angles.z += gf_PI/2;
|
|
|
- quat.SetRotationXYZ(angles);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- xmlNode->getAttr("Scale", scale);
|
|
|
- xmlNode->getAttr("ColorRGB", color);
|
|
|
- xmlNode->getAttr("FlattenArea", flattenArea);
|
|
|
- xmlNode->getAttr("Flags", flags);
|
|
|
- xmlNode->getAttr("Parent", parentId);
|
|
|
- xmlNode->getAttr("LookAt", lookatId);
|
|
|
- xmlNode->getAttr("Material", mtlName);
|
|
|
-
|
|
|
- bool bHidden = flags & OBJFLAG_HIDDEN;
|
|
|
- bool bFrozen = flags & OBJFLAG_FROZEN;
|
|
|
-
|
|
|
- m_flags = flags;
|
|
|
- m_flags &= ~OBJFLAG_PERSISTMASK;
|
|
|
- m_flags |= (oldFlags) & (~OBJFLAG_PERSISTMASK);
|
|
|
- //SetFlags( flags & OBJFLAG_PERSISTMASK );
|
|
|
- m_flags &= ~OBJFLAG_SHARED; // clear shared flag
|
|
|
- m_flags &= ~OBJFLAG_DELETED; // clear deleted flag
|
|
|
-
|
|
|
- if (ar.bUndo)
|
|
|
- {
|
|
|
- DetachThis(false);
|
|
|
- }
|
|
|
-
|
|
|
- if (name != m_name)
|
|
|
- {
|
|
|
- // This may change object id.
|
|
|
- SetName(name);
|
|
|
- }
|
|
|
-
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- // Check if position is bad.
|
|
|
- if (fabs(pos.x) > AZ::Constants::MaxFloatBeforePrecisionLoss ||
|
|
|
- fabs(pos.y) > AZ::Constants::MaxFloatBeforePrecisionLoss ||
|
|
|
- fabs(pos.z) > AZ::Constants::MaxFloatBeforePrecisionLoss)
|
|
|
- {
|
|
|
- // File Not found.
|
|
|
- CErrorRecord err;
|
|
|
- err.error = QStringLiteral("Object %1 have invalid position (%2,%3,%4)").arg(GetName()).arg(pos.x).arg(pos.y).arg(pos.z);
|
|
|
- err.pObject = this;
|
|
|
- err.severity = CErrorRecord::ESEVERITY_WARNING;
|
|
|
- GetIEditor()->GetErrorReport()->ReportError(err);
|
|
|
- }
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
- if (!ar.bUndo)
|
|
|
- {
|
|
|
- SetLocalTM(pos, quat, scale);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- SetLocalTM(pos, quat, scale, eObjectUpdateFlags_Undo);
|
|
|
- }
|
|
|
-
|
|
|
- SetColor(color);
|
|
|
- SetArea(flattenArea);
|
|
|
- SetFrozen(bFrozen);
|
|
|
- SetHidden(bHidden);
|
|
|
-
|
|
|
- ar.SetResolveCallback(this, parentId, [this](CBaseObject* parent) { ResolveParent(parent); });
|
|
|
- ar.SetResolveCallback(this, lookatId, [this](CBaseObject* target) { SetLookAt(target); });
|
|
|
-
|
|
|
- InvalidateTM(0);
|
|
|
- SetModified(false);
|
|
|
-
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Saving.
|
|
|
-
|
|
|
- // This attributed only readed by ObjectManager.
|
|
|
- xmlNode->setAttr("Type", GetTypeName().toUtf8().data());
|
|
|
-
|
|
|
- xmlNode->setAttr("Id", m_guid);
|
|
|
-
|
|
|
- xmlNode->setAttr("Name", GetName().toUtf8().data());
|
|
|
-
|
|
|
- if (m_parent)
|
|
|
- {
|
|
|
- xmlNode->setAttr("Parent", m_parent->GetId());
|
|
|
- }
|
|
|
-
|
|
|
- if (m_lookat)
|
|
|
- {
|
|
|
- xmlNode->setAttr("LookAt", m_lookat->GetId());
|
|
|
- }
|
|
|
-
|
|
|
- if (!IsEquivalent(GetPos(), Vec3(0, 0, 0), 0))
|
|
|
- {
|
|
|
- xmlNode->setAttr("Pos", GetPos());
|
|
|
- }
|
|
|
-
|
|
|
- xmlNode->setAttr("Rotate", m_rotate);
|
|
|
-
|
|
|
- if (!IsEquivalent(GetScale(), Vec3(1, 1, 1), 0))
|
|
|
- {
|
|
|
- xmlNode->setAttr("Scale", GetScale());
|
|
|
- }
|
|
|
-
|
|
|
- xmlNode->setAttr("ColorRGB", GetColor());
|
|
|
-
|
|
|
- if (GetArea() != 0)
|
|
|
- {
|
|
|
- xmlNode->setAttr("FlattenArea", GetArea());
|
|
|
- }
|
|
|
-
|
|
|
- int flags = m_flags & OBJFLAG_PERSISTMASK;
|
|
|
- if (flags != 0)
|
|
|
- {
|
|
|
- xmlNode->setAttr("Flags", flags);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Serialize variables after default entity parameters.
|
|
|
- CVarObject::Serialize(xmlNode, ar.bLoading);
|
|
|
-
|
|
|
- m_pTransformDelegate = pTransformDelegate;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-XmlNodeRef CBaseObject::Export([[maybe_unused]] const QString& levelPath, XmlNodeRef& xmlNode)
|
|
|
-{
|
|
|
- XmlNodeRef objNode = xmlNode->newChild("Object");
|
|
|
-
|
|
|
- objNode->setAttr("Type", GetTypeName().toUtf8().data());
|
|
|
- objNode->setAttr("Name", GetName().toUtf8().data());
|
|
|
-
|
|
|
- Vec3 pos, scale;
|
|
|
- Quat rotate;
|
|
|
- if (m_parent)
|
|
|
- {
|
|
|
- // Export world coordinates.
|
|
|
- AffineParts ap;
|
|
|
- ap.SpectralDecompose(GetWorldTM());
|
|
|
-
|
|
|
- pos = ap.pos;
|
|
|
- rotate = ap.rot;
|
|
|
- scale = ap.scale;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- pos = m_pos;
|
|
|
- rotate = m_rotate;
|
|
|
- scale = m_scale;
|
|
|
- }
|
|
|
-
|
|
|
- if (!IsEquivalent(pos, Vec3(0, 0, 0), 0))
|
|
|
- {
|
|
|
- objNode->setAttr("Pos", pos);
|
|
|
- }
|
|
|
-
|
|
|
- if (!rotate.IsIdentity())
|
|
|
- {
|
|
|
- objNode->setAttr("Rotate", rotate);
|
|
|
- }
|
|
|
-
|
|
|
- if (!IsEquivalent(scale, Vec3(0, 0, 0), 0))
|
|
|
- {
|
|
|
- objNode->setAttr("Scale", scale);
|
|
|
- }
|
|
|
-
|
|
|
- // Save variables.
|
|
|
- CVarObject::Serialize(objNode, false);
|
|
|
-
|
|
|
- return objNode;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-CBaseObject* CBaseObject::FindObject(REFGUID id) const
|
|
|
-{
|
|
|
- return GetObjectManager()->FindObject(id);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::StoreUndo(bool minimal, int flags)
|
|
|
-{
|
|
|
- // Don't use Sandbox undo for AZ entities, except for the move & scale tools, which rely on it.
|
|
|
- const bool isGizmoTool = 0 != (flags & (eObjectUpdateFlags_MoveTool | eObjectUpdateFlags_ScaleTool | eObjectUpdateFlags_UserInput));
|
|
|
- if (!isGizmoTool && 0 != (m_flags & OBJFLAG_DONT_SAVE))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (CUndo::IsRecording())
|
|
|
- {
|
|
|
- if (minimal)
|
|
|
- {
|
|
|
- CUndo::Record(new CUndoBaseObjectMinimal(this, flags));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- CUndo::Record(new CUndoBaseObject(this));
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-QString CBaseObject::GetTypeName() const
|
|
|
-{
|
|
|
- QString className = m_classDesc->ClassName();
|
|
|
- QString subClassName = strstr(className.toUtf8().data(), "::");
|
|
|
- if (subClassName.isEmpty())
|
|
|
- {
|
|
|
- return className;
|
|
|
- }
|
|
|
-
|
|
|
- QString name;
|
|
|
- name.append(className.midRef(0, className.length() - subClassName.length()));
|
|
|
- return name;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::IntersectRectBounds(const AABB& bbox)
|
|
|
-{
|
|
|
- AABB aabb;
|
|
|
- GetBoundBox(aabb);
|
|
|
-
|
|
|
- return aabb.IsIntersectBox(bbox);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::IntersectRayBounds(const Ray& ray)
|
|
|
-{
|
|
|
- Vec3 tmpPnt;
|
|
|
- AABB aabb;
|
|
|
- GetBoundBox(aabb);
|
|
|
-
|
|
|
- return Intersect::Ray_AABB(ray, aabb, tmpPnt);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-namespace
|
|
|
-{
|
|
|
- using Edge2D = std::pair<Vec2, Vec2>;
|
|
|
-}
|
|
|
-bool IsIncludePointsInConvexHull(Edge2D* pEdgeArray0, int nEdgeArray0Size, Edge2D* pEdgeArray1, int nEdgeArray1Size)
|
|
|
-{
|
|
|
- if (!pEdgeArray0 || !pEdgeArray1 || nEdgeArray0Size <= 0 || nEdgeArray1Size <= 0)
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- static const float kPointEdgeMaxInsideDistance(0.05f);
|
|
|
-
|
|
|
- bool bInside(true);
|
|
|
- for (int i = 0; i < nEdgeArray0Size; ++i)
|
|
|
- {
|
|
|
- const Vec2& v(pEdgeArray0[i].first);
|
|
|
- bInside = true;
|
|
|
- for (int k = 0; k < nEdgeArray1Size; ++k)
|
|
|
- {
|
|
|
- Vec2 v0 = pEdgeArray1[k].first;
|
|
|
- Vec2 v1 = pEdgeArray1[k].second;
|
|
|
- Vec3 direction(v1.x - v0.x, v1.y - v0.y, 0);
|
|
|
- Vec3 up(0, 0, 1);
|
|
|
- Vec3 z = up.Cross(direction);
|
|
|
- Vec2 normal;
|
|
|
- normal.x = z.x;
|
|
|
- normal.y = z.y;
|
|
|
- normal.Normalize();
|
|
|
- float distance = -normal.Dot(v0);
|
|
|
- if (normal.Dot(v) + distance > kPointEdgeMaxInsideDistance)
|
|
|
- {
|
|
|
- bInside = false;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- if (bInside)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return bInside;
|
|
|
-}
|
|
|
-
|
|
|
-void ModifyConvexEdgeDirection(Edge2D* pEdgeArray, int nEdgeArraySize)
|
|
|
-{
|
|
|
- if (!pEdgeArray || nEdgeArraySize < 2)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- Vec3 v0(pEdgeArray[0].first.x - pEdgeArray[0].second.x, pEdgeArray[0].first.y - pEdgeArray[0].second.y, 0);
|
|
|
- Vec3 v1(pEdgeArray[1].second.x - pEdgeArray[1].first.x, pEdgeArray[1].second.y - pEdgeArray[1].first.y, 0);
|
|
|
- Vec3 vCross = v0.Cross(v1);
|
|
|
- if (vCross.z < 0)
|
|
|
- {
|
|
|
- for (int i = 0; i < nEdgeArraySize; ++i)
|
|
|
- {
|
|
|
- std::swap(pEdgeArray[i].first, pEdgeArray[i].second);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-bool CBaseObject::HitTestRectBounds(HitContext& hc, const AABB& box)
|
|
|
-{
|
|
|
- if (hc.bUseSelectionHelpers)
|
|
|
- {
|
|
|
- if (IsSkipSelectionHelper())
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- static const int kNumberOfBoundBoxPt(8);
|
|
|
-
|
|
|
- // transform all 8 vertices into view space.
|
|
|
- QPoint p[kNumberOfBoundBoxPt] =
|
|
|
- {
|
|
|
- hc.view->WorldToView(Vec3(box.min.x, box.min.y, box.min.z)),
|
|
|
- hc.view->WorldToView(Vec3(box.min.x, box.max.y, box.min.z)),
|
|
|
- hc.view->WorldToView(Vec3(box.max.x, box.min.y, box.min.z)),
|
|
|
- hc.view->WorldToView(Vec3(box.max.x, box.max.y, box.min.z)),
|
|
|
- hc.view->WorldToView(Vec3(box.min.x, box.min.y, box.max.z)),
|
|
|
- hc.view->WorldToView(Vec3(box.min.x, box.max.y, box.max.z)),
|
|
|
- hc.view->WorldToView(Vec3(box.max.x, box.min.y, box.max.z)),
|
|
|
- hc.view->WorldToView(Vec3(box.max.x, box.max.y, box.max.z))
|
|
|
- };
|
|
|
-
|
|
|
- QRect objrc;
|
|
|
- objrc.setLeft(10000);
|
|
|
- objrc.setTop(10000);
|
|
|
- objrc.setRight(-10000);
|
|
|
- objrc.setBottom(-10000);
|
|
|
-
|
|
|
- // find new min/max values
|
|
|
- for (int i = 0; i < 8; i++)
|
|
|
- {
|
|
|
- objrc.setLeft(min(objrc.left(), p[i].x()));
|
|
|
- objrc.setRight(max(objrc.right(), p[i].x()));
|
|
|
- objrc.setTop(min(objrc.top(), p[i].y()));
|
|
|
- objrc.setBottom(max(objrc.bottom(), p[i].y()));
|
|
|
- }
|
|
|
- if (objrc.isEmpty())
|
|
|
- {
|
|
|
- // Make objrc at least of size 1.
|
|
|
- objrc.moveBottomRight(objrc.bottomRight() + QPoint(1, 1));
|
|
|
- }
|
|
|
-
|
|
|
- if (hc.rect.contains(objrc.topLeft()) &&
|
|
|
- hc.rect.contains(objrc.bottomLeft()) &&
|
|
|
- hc.rect.contains(objrc.topRight()) &&
|
|
|
- hc.rect.contains(objrc.bottomRight()))
|
|
|
- {
|
|
|
- hc.object = this;
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (objrc.intersects(hc.rect))
|
|
|
- {
|
|
|
- AABB localAABB;
|
|
|
- GetLocalBounds(localAABB);
|
|
|
- CBaseObject* pOldObj = hc.object;
|
|
|
- hc.object = this;
|
|
|
- if (localAABB.IsEmpty())
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- const int kMaxSizeOfEdgeList0(4);
|
|
|
- Edge2D edgelist0[kMaxSizeOfEdgeList0] = {
|
|
|
- Edge2D(Vec2(static_cast<f32>(hc.rect.left()), static_cast<f32>(hc.rect.top())), Vec2(static_cast<f32>(hc.rect.right()), static_cast<f32>(hc.rect.top()))),
|
|
|
- Edge2D(Vec2(static_cast<f32>(hc.rect.right()), static_cast<f32>(hc.rect.top())), Vec2(static_cast<f32>(hc.rect.right()), static_cast<f32>(hc.rect.bottom()))),
|
|
|
- Edge2D(Vec2(static_cast<f32>(hc.rect.right()), static_cast<f32>(hc.rect.bottom())), Vec2(static_cast<f32>(hc.rect.left()), static_cast<f32>(hc.rect.bottom()))),
|
|
|
- Edge2D(Vec2(static_cast<f32>(hc.rect.left()), static_cast<f32>(hc.rect.bottom())), Vec2(static_cast<f32>(hc.rect.left()), static_cast<f32>(hc.rect.top())))
|
|
|
- };
|
|
|
-
|
|
|
- const int kMaxSizeOfEdgeList1(8);
|
|
|
- Edge2D edgelist1[kMaxSizeOfEdgeList1];
|
|
|
- int nEdgeList1Count(kMaxSizeOfEdgeList1);
|
|
|
-
|
|
|
- const Matrix34& worldTM(GetWorldTM());
|
|
|
- OBB obb = OBB::CreateOBBfromAABB(Matrix33(worldTM), localAABB);
|
|
|
- Vec3 ax = obb.m33.GetColumn0() * obb.h.x;
|
|
|
- Vec3 ay = obb.m33.GetColumn1() * obb.h.y;
|
|
|
- Vec3 az = obb.m33.GetColumn2() * obb.h.z;
|
|
|
- QPoint obb_p[kMaxSizeOfEdgeList1] =
|
|
|
- {
|
|
|
- hc.view->WorldToView(-ax - ay - az + worldTM.GetTranslation()),
|
|
|
- hc.view->WorldToView(-ax - ay + az + worldTM.GetTranslation()),
|
|
|
- hc.view->WorldToView(-ax + ay - az + worldTM.GetTranslation()),
|
|
|
- hc.view->WorldToView(-ax + ay + az + worldTM.GetTranslation()),
|
|
|
- hc.view->WorldToView(ax - ay - az + worldTM.GetTranslation()),
|
|
|
- hc.view->WorldToView(ax - ay + az + worldTM.GetTranslation()),
|
|
|
- hc.view->WorldToView(ax + ay - az + worldTM.GetTranslation()),
|
|
|
- hc.view->WorldToView(ax + ay + az + worldTM.GetTranslation())
|
|
|
- };
|
|
|
-
|
|
|
- std::vector<Vec3> pointsForRegion1;
|
|
|
- pointsForRegion1.reserve(kMaxSizeOfEdgeList1);
|
|
|
- for (int i = 0; i < kMaxSizeOfEdgeList1; ++i)
|
|
|
- {
|
|
|
- pointsForRegion1.push_back(Vec3(static_cast<f32>(obb_p[i].x()), static_cast<f32>(obb_p[i].y()), 0.0f));
|
|
|
- }
|
|
|
-
|
|
|
- std::vector<Vec3> convexHullForRegion1;
|
|
|
- ConvexHull2D(convexHullForRegion1, pointsForRegion1);
|
|
|
- nEdgeList1Count = static_cast<int>(convexHullForRegion1.size());
|
|
|
- if (nEdgeList1Count < 3 || nEdgeList1Count > kMaxSizeOfEdgeList1)
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- for (int i = 0; i < nEdgeList1Count; ++i)
|
|
|
- {
|
|
|
- int iNextI = (i + 1) % nEdgeList1Count;
|
|
|
- edgelist1[i] = Edge2D(Vec2(convexHullForRegion1[i].x, convexHullForRegion1[i].y), Vec2(convexHullForRegion1[iNextI].x, convexHullForRegion1[iNextI].y));
|
|
|
- }
|
|
|
-
|
|
|
- ModifyConvexEdgeDirection(edgelist0, kMaxSizeOfEdgeList0);
|
|
|
- ModifyConvexEdgeDirection(edgelist1, nEdgeList1Count);
|
|
|
-
|
|
|
- bool bInside = IsIncludePointsInConvexHull(edgelist0, kMaxSizeOfEdgeList0, edgelist1, nEdgeList1Count);
|
|
|
- if (!bInside)
|
|
|
- {
|
|
|
- bInside = IsIncludePointsInConvexHull(edgelist1, nEdgeList1Count, edgelist0, kMaxSizeOfEdgeList0);
|
|
|
- }
|
|
|
- if (!bInside)
|
|
|
- {
|
|
|
- hc.object = pOldObj;
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::HitTestRect(HitContext& hc)
|
|
|
-{
|
|
|
- AZ_PROFILE_FUNCTION(Editor);
|
|
|
-
|
|
|
- AABB box;
|
|
|
-
|
|
|
- if (hc.bUseSelectionHelpers)
|
|
|
- {
|
|
|
- if (IsSkipSelectionHelper())
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- box.min = GetWorldPos();
|
|
|
- box.max = box.min;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Retrieve world space bound box.
|
|
|
- GetBoundBox(box);
|
|
|
- }
|
|
|
-
|
|
|
- bool bHit = HitTestRectBounds(hc, box);
|
|
|
- m_bInSelectionBox = bHit;
|
|
|
- if (bHit)
|
|
|
- {
|
|
|
- hc.object = this;
|
|
|
- }
|
|
|
- return bHit;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-CBaseObject* CBaseObject::GetChild(size_t const i) const
|
|
|
-{
|
|
|
- assert(i < m_childs.size());
|
|
|
- return m_childs[i];
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::AttachChild(CBaseObject* child, bool bKeepPos)
|
|
|
-{
|
|
|
- Matrix34 childTM;
|
|
|
- ITransformDelegate* pTransformDelegate;
|
|
|
- ITransformDelegate* pChildTransformDelegate;
|
|
|
-
|
|
|
- {
|
|
|
- CScopedSuspendUndo suspendUndo;
|
|
|
-
|
|
|
- assert(child);
|
|
|
- if (!child || child == GetLookAt())
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- child->NotifyListeners(bKeepPos ? ON_PREATTACHEDKEEPXFORM : ON_PREATTACHED);
|
|
|
-
|
|
|
- pTransformDelegate = m_pTransformDelegate;
|
|
|
- pChildTransformDelegate = child->m_pTransformDelegate;
|
|
|
- SetTransformDelegate(nullptr);
|
|
|
- child->SetTransformDelegate(nullptr);
|
|
|
-
|
|
|
- if (bKeepPos)
|
|
|
- {
|
|
|
- child->InvalidateTM(0);
|
|
|
- childTM = child->GetWorldTM();
|
|
|
- }
|
|
|
-
|
|
|
- // If not already attached to this node.
|
|
|
- if (child->m_parent == this)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // Add to child list first to make sure node not get deleted while reattaching.
|
|
|
- m_childs.push_back(child);
|
|
|
- if (child->m_parent)
|
|
|
- {
|
|
|
- child->DetachThis(bKeepPos); // Detach node if attached to other parent.
|
|
|
- }
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- child->m_parent = this; // Assign this node as parent to child node.
|
|
|
- }
|
|
|
-
|
|
|
- {
|
|
|
- CScopedSuspendUndo suspendUndo;
|
|
|
-
|
|
|
- {
|
|
|
- if (bKeepPos)
|
|
|
- {
|
|
|
- child->SetWorldTM(childTM);
|
|
|
- }
|
|
|
-
|
|
|
- child->InvalidateTM(0);
|
|
|
- }
|
|
|
-
|
|
|
- m_pTransformDelegate = pTransformDelegate;
|
|
|
- child->m_pTransformDelegate = pChildTransformDelegate;
|
|
|
-
|
|
|
- child->NotifyListeners(ON_ATTACHED);
|
|
|
-
|
|
|
- NotifyListeners(ON_CHILDATTACHED);
|
|
|
- }
|
|
|
-
|
|
|
- if (CUndo::IsRecording())
|
|
|
- {
|
|
|
- CUndo::Record(new CUndoAttachBaseObject(child, bKeepPos, true));
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::DetachAll(bool bKeepPos)
|
|
|
-{
|
|
|
- while (!m_childs.empty())
|
|
|
- {
|
|
|
- CBaseObject* child = *m_childs.begin();
|
|
|
- child->DetachThis(bKeepPos);
|
|
|
- NotifyListeners(ON_CHILDDETACHED);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::DetachThis(bool bKeepPos)
|
|
|
-{
|
|
|
- if (m_parent)
|
|
|
- {
|
|
|
- if (CUndo::IsRecording())
|
|
|
- {
|
|
|
- CUndo::Record(new CUndoAttachBaseObject(this, bKeepPos, false));
|
|
|
- }
|
|
|
-
|
|
|
- Matrix34 worldTM;
|
|
|
- ITransformDelegate* pTransformDelegate;
|
|
|
-
|
|
|
- {
|
|
|
- CScopedSuspendUndo suspendUndo;
|
|
|
- NotifyListeners(bKeepPos ? ON_PREDETACHEDKEEPXFORM : ON_PREDETACHED);
|
|
|
-
|
|
|
- pTransformDelegate = m_pTransformDelegate;
|
|
|
- SetTransformDelegate(nullptr);
|
|
|
-
|
|
|
- if (bKeepPos)
|
|
|
- {
|
|
|
- ITransformDelegate* pParentTransformDelegate = m_parent->m_pTransformDelegate;
|
|
|
- m_parent->SetTransformDelegate(nullptr);
|
|
|
- worldTM = GetWorldTM();
|
|
|
- m_parent->SetTransformDelegate(pParentTransformDelegate);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- {
|
|
|
- CScopedSuspendUndo suspendUndo;
|
|
|
-
|
|
|
- // Copy parent to temp var, erasing child from parent may delete this node if child referenced only from parent.
|
|
|
- CBaseObject* parent = m_parent;
|
|
|
- m_parent = nullptr;
|
|
|
- parent->RemoveChild(this);
|
|
|
-
|
|
|
- if (bKeepPos)
|
|
|
- {
|
|
|
- // Keep old world space transformation.
|
|
|
- SetWorldTM(worldTM);
|
|
|
- }
|
|
|
-
|
|
|
- SetTransformDelegate(pTransformDelegate);
|
|
|
-
|
|
|
- NotifyListeners(ON_DETACHED);
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::RemoveChild(CBaseObject* node)
|
|
|
-{
|
|
|
- Childs::iterator it = std::find(m_childs.begin(), m_childs.end(), node);
|
|
|
- if (it != m_childs.end())
|
|
|
- {
|
|
|
- m_childs.erase(it);
|
|
|
- NotifyListeners(ON_CHILDDETACHED);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::ResolveParent(CBaseObject* parent)
|
|
|
-{
|
|
|
- // even though parent is same as m_parent, adding the member to the parent must be done.
|
|
|
- if (parent)
|
|
|
- {
|
|
|
- parent->AddMember(this, false);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- DetachThis(false);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::CalcLocalTM(Matrix34& tm) const
|
|
|
-{
|
|
|
- tm.SetIdentity();
|
|
|
-
|
|
|
- if (m_lookat)
|
|
|
- {
|
|
|
- Vec3 pos = GetPos();
|
|
|
-
|
|
|
- if (m_parent)
|
|
|
- {
|
|
|
- // Get our world position.
|
|
|
- pos = GetParentAttachPointWorldTM().TransformPoint(pos);
|
|
|
- }
|
|
|
-
|
|
|
- // Calculate local TM matrix differently.
|
|
|
- Vec3 lookatPos = m_lookat->GetWorldPos();
|
|
|
- if (lookatPos == pos) // if target at object pos
|
|
|
- {
|
|
|
- tm.SetTranslation(pos);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- tm = Matrix34(Matrix33::CreateRotationVDir((lookatPos - pos).GetNormalized()), pos);
|
|
|
- }
|
|
|
- if (m_parent)
|
|
|
- {
|
|
|
- Matrix34 invParentTM = m_parent->GetWorldTM();
|
|
|
- invParentTM.Invert();
|
|
|
- tm = invParentTM * tm;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- tm = Matrix34::Create(GetScale(), GetRotation(), GetPos());
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-const Matrix34& CBaseObject::GetWorldTM() const
|
|
|
-{
|
|
|
- if (!m_bMatrixValid)
|
|
|
- {
|
|
|
- m_worldTM = GetLocalTM();
|
|
|
- m_bMatrixValid = true;
|
|
|
- m_bMatrixInWorldSpace = false;
|
|
|
- m_bWorldBoxValid = false;
|
|
|
- }
|
|
|
- if (!m_bMatrixInWorldSpace)
|
|
|
- {
|
|
|
- CBaseObject* parent = GetParent();
|
|
|
- if (parent)
|
|
|
- {
|
|
|
- m_worldTM = GetParentAttachPointWorldTM() * m_worldTM;
|
|
|
- }
|
|
|
- m_bMatrixInWorldSpace = true;
|
|
|
- m_bWorldBoxValid = false;
|
|
|
- }
|
|
|
- return m_worldTM;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-Matrix34 CBaseObject::GetParentAttachPointWorldTM() const
|
|
|
-{
|
|
|
- CBaseObject* pParent = GetParent();
|
|
|
- if (pParent)
|
|
|
- {
|
|
|
- return pParent->GetWorldTM();
|
|
|
- }
|
|
|
-
|
|
|
- return Matrix34(IDENTITY);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::InvalidateTM([[maybe_unused]] int flags)
|
|
|
-{
|
|
|
- bool bMatrixWasValid = m_bMatrixValid;
|
|
|
-
|
|
|
- m_bMatrixInWorldSpace = false;
|
|
|
- m_bMatrixValid = false;
|
|
|
- m_bWorldBoxValid = false;
|
|
|
-
|
|
|
- // If matrix was valid, invalidate all childs.
|
|
|
- if (bMatrixWasValid)
|
|
|
- {
|
|
|
- if (m_lookatSource)
|
|
|
- {
|
|
|
- m_lookatSource->InvalidateTM(eObjectUpdateFlags_ParentChanged);
|
|
|
- }
|
|
|
-
|
|
|
- // Invalidate matrices off all child objects.
|
|
|
- for (int i = 0; i < m_childs.size(); i++)
|
|
|
- {
|
|
|
- if (m_childs[i] != nullptr && m_childs[i]->m_bMatrixValid)
|
|
|
- {
|
|
|
- m_childs[i]->InvalidateTM(eObjectUpdateFlags_ParentChanged);
|
|
|
- }
|
|
|
- }
|
|
|
- NotifyListeners(ON_TRANSFORM);
|
|
|
-
|
|
|
- // Notify parent that we were modified.
|
|
|
- if (m_parent)
|
|
|
- {
|
|
|
- m_parent->OnChildModified();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (m_pTransformDelegate)
|
|
|
- {
|
|
|
- m_pTransformDelegate->MatrixInvalidated();
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetLocalTM(const Vec3& pos, const Quat& rotate, const Vec3& scale, int flags)
|
|
|
-{
|
|
|
- const bool b1 = SetPos(pos, flags | eObjectUpdateFlags_DoNotInvalidate);
|
|
|
- const bool b2 = SetRotation(rotate, flags | eObjectUpdateFlags_DoNotInvalidate);
|
|
|
- const bool b3 = SetScale(scale, flags | eObjectUpdateFlags_DoNotInvalidate);
|
|
|
-
|
|
|
- if (b1 || b2 || b3 || flags == eObjectUpdateFlags_Animated)
|
|
|
- {
|
|
|
- flags = (b1) ? (flags | eObjectUpdateFlags_PositionChanged) : (flags & (~eObjectUpdateFlags_PositionChanged));
|
|
|
- flags = (b2) ? (flags | eObjectUpdateFlags_RotationChanged) : (flags & (~eObjectUpdateFlags_RotationChanged));
|
|
|
- flags = (b3) ? (flags | eObjectUpdateFlags_ScaleChanged) : (flags & (~eObjectUpdateFlags_ScaleChanged));
|
|
|
- InvalidateTM(flags);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetLocalTM(const Matrix34& tm, int flags)
|
|
|
-{
|
|
|
- if (m_lookat)
|
|
|
- {
|
|
|
- bool b1 = SetPos(tm.GetTranslation(), eObjectUpdateFlags_DoNotInvalidate);
|
|
|
- flags = (b1) ? (flags | eObjectUpdateFlags_PositionChanged) : (flags & (~eObjectUpdateFlags_PositionChanged));
|
|
|
- InvalidateTM(flags);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- AffineParts affineParts;
|
|
|
- affineParts.SpectralDecompose(tm);
|
|
|
- SetLocalTM(affineParts.pos, affineParts.rot, affineParts.scale, flags);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetWorldPos(const Vec3& pos, int flags)
|
|
|
-{
|
|
|
- if (GetParent())
|
|
|
- {
|
|
|
- Matrix34 invParentTM = GetParentAttachPointWorldTM();
|
|
|
- invParentTM.Invert();
|
|
|
- Vec3 posLocal = invParentTM * pos;
|
|
|
- SetPos(posLocal, flags);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- SetPos(pos, flags);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetWorldTM(const Matrix34& tm, int flags)
|
|
|
-{
|
|
|
- if (GetParent())
|
|
|
- {
|
|
|
- Matrix34 invParentTM = GetParentAttachPointWorldTM();
|
|
|
- invParentTM.Invert();
|
|
|
- Matrix34 localTM = invParentTM * tm;
|
|
|
- SetLocalTM(localTM, flags);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- SetLocalTM(tm, flags);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::UpdateVisibility(bool bVisible)
|
|
|
-{
|
|
|
- if (bVisible == CheckFlags(OBJFLAG_INVISIBLE))
|
|
|
- {
|
|
|
- if (IObjectManager* objectManager = GetObjectManager())
|
|
|
- {
|
|
|
- objectManager->InvalidateVisibleList();
|
|
|
- }
|
|
|
-
|
|
|
- if (!bVisible)
|
|
|
- {
|
|
|
- m_flags |= OBJFLAG_INVISIBLE;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- m_flags &= ~OBJFLAG_INVISIBLE;
|
|
|
- }
|
|
|
-
|
|
|
- NotifyListeners(ON_VISIBILITY);
|
|
|
-
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::SetLookAt(CBaseObject* target)
|
|
|
-{
|
|
|
- if (m_lookat == target)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- StoreUndo();
|
|
|
-
|
|
|
- if (m_lookat)
|
|
|
- {
|
|
|
- // Unbind current lookat.
|
|
|
- m_lookat->m_lookatSource = nullptr;
|
|
|
- }
|
|
|
- m_lookat = target;
|
|
|
- if (m_lookat)
|
|
|
- {
|
|
|
- m_lookat->m_lookatSource = this;
|
|
|
- }
|
|
|
-
|
|
|
- InvalidateTM(0);
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::IsLookAtTarget() const
|
|
|
-{
|
|
|
- return m_lookatSource != nullptr;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::AddEventListener(EventListener* listener)
|
|
|
-{
|
|
|
- if (find(m_eventListeners.begin(), m_eventListeners.end(), listener) == m_eventListeners.end())
|
|
|
- {
|
|
|
- m_eventListeners.push_back(listener);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::RemoveEventListener(EventListener* listener)
|
|
|
-{
|
|
|
- std::vector<EventListener*>::iterator listenerFound = find(m_eventListeners.begin(), m_eventListeners.end(), listener);
|
|
|
- if (listenerFound != m_eventListeners.end())
|
|
|
- {
|
|
|
- (*listenerFound) = nullptr;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool IsBaseObjectEventCallbackNULL(CBaseObject::EventListener* listener) { return listener == nullptr; }
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::NotifyListeners(EObjectListenerEvent event)
|
|
|
-{
|
|
|
- for (auto it = m_eventListeners.begin(); it != m_eventListeners.end(); ++it)
|
|
|
- {
|
|
|
- // Call listener callback.
|
|
|
- if (*it)
|
|
|
- {
|
|
|
- (*it)->OnObjectEvent(this, event);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- m_eventListeners.erase(remove_if(m_eventListeners.begin(), m_eventListeners.end(), IsBaseObjectEventCallbackNULL), std::end(m_eventListeners));
|
|
|
-}
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::ConvertFromObject(CBaseObject* object)
|
|
|
-{
|
|
|
- SetLocalTM(object->GetLocalTM());
|
|
|
- SetName(object->GetName());
|
|
|
- SetColor(object->GetColor());
|
|
|
- m_flattenArea = object->m_flattenArea;
|
|
|
- if (object->GetParent())
|
|
|
- {
|
|
|
- object->GetParent()->AttachChild(this);
|
|
|
- }
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::IsPotentiallyVisible() const
|
|
|
-{
|
|
|
- if (CheckFlags(OBJFLAG_HIDDEN))
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- if (gSettings.objectHideMask & GetType())
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-//! Analyze errors for this object.
|
|
|
-void CBaseObject::Validate(IErrorReport* report)
|
|
|
-{
|
|
|
- // Checks for invalid values in base object.
|
|
|
-
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- // Check if position is bad.
|
|
|
- const Vec3 pos = GetPos();
|
|
|
-
|
|
|
- if (fabs(pos.x) > AZ::Constants::MaxFloatBeforePrecisionLoss ||
|
|
|
- fabs(pos.y) > AZ::Constants::MaxFloatBeforePrecisionLoss ||
|
|
|
- fabs(pos.z) > AZ::Constants::MaxFloatBeforePrecisionLoss)
|
|
|
- {
|
|
|
- // File Not found.
|
|
|
- CErrorRecord err;
|
|
|
- err.error = QStringLiteral("Object %1 have invalid position (%2,%3,%4)").arg(GetName()).arg(pos.x).arg(pos.y).arg(pos.z);
|
|
|
- err.pObject = this;
|
|
|
- report->ReportError(err);
|
|
|
- }
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
-
|
|
|
- float minScale = 0.01f;
|
|
|
- float maxScale = 1000.0f;
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
- // Check if position is bad.
|
|
|
- if (m_scale.x < minScale || m_scale.x > maxScale ||
|
|
|
- m_scale.y < minScale || m_scale.y > maxScale ||
|
|
|
- m_scale.z < minScale || m_scale.z > maxScale)
|
|
|
- {
|
|
|
- // File Not found.
|
|
|
- CErrorRecord err;
|
|
|
- err.error = QStringLiteral("Object %1 have invalid scale (%2,%3,%4)").arg(GetName()).arg(m_scale.x).arg(m_scale.y).arg(m_scale.z);
|
|
|
- err.pObject = this;
|
|
|
- report->ReportError(err);
|
|
|
- }
|
|
|
- //////////////////////////////////////////////////////////////////////////
|
|
|
-};
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-void CBaseObject::GatherUsedResources(CUsedResources& resources)
|
|
|
-{
|
|
|
- if (GetVarBlock())
|
|
|
- {
|
|
|
- GetVarBlock()->GatherUsedResources(resources);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-bool CBaseObject::IsSimilarObject(CBaseObject* pObject)
|
|
|
-{
|
|
|
- if (pObject->GetClassDesc() == GetClassDesc() && pObject->metaObject() == metaObject())
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-EScaleWarningLevel CBaseObject::GetScaleWarningLevel() const
|
|
|
-{
|
|
|
- EScaleWarningLevel scaleWarningLevel = eScaleWarningLevel_None;
|
|
|
-
|
|
|
- const float kScaleThreshold = 0.001f;
|
|
|
-
|
|
|
- if (fabs(m_scale.x - 1.0f) > kScaleThreshold
|
|
|
- || fabs(m_scale.y - 1.0f) > kScaleThreshold
|
|
|
- || fabs(m_scale.z - 1.0f) > kScaleThreshold)
|
|
|
- {
|
|
|
- if (fabs(m_scale.x - m_scale.y) < kScaleThreshold
|
|
|
- && fabs(m_scale.y - m_scale.z) < kScaleThreshold)
|
|
|
- {
|
|
|
- scaleWarningLevel = eScaleWarningLevel_Rescaled;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- scaleWarningLevel = eScaleWarningLevel_RescaledNonUniform;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return scaleWarningLevel;
|
|
|
-}
|
|
|
-
|
|
|
-//////////////////////////////////////////////////////////////////////////
|
|
|
-ERotationWarningLevel CBaseObject::GetRotationWarningLevel() const
|
|
|
-{
|
|
|
- ERotationWarningLevel rotationWarningLevel = eRotationWarningLevel_None;
|
|
|
-
|
|
|
- const float kRotationThreshold = 0.01f;
|
|
|
-
|
|
|
- Ang3 eulerRotation = Ang3(GetRotation());
|
|
|
-
|
|
|
- if (fabs(eulerRotation.x) > kRotationThreshold
|
|
|
- || fabs(eulerRotation.y) > kRotationThreshold
|
|
|
- || fabs(eulerRotation.z) > kRotationThreshold)
|
|
|
- {
|
|
|
- const float xRotationMod = fabs(fmod(eulerRotation.x, gf_PI / 2.0f));
|
|
|
- const float yRotationMod = fabs(fmod(eulerRotation.y, gf_PI / 2.0f));
|
|
|
- const float zRotationMod = fabs(fmod(eulerRotation.z, gf_PI / 2.0f));
|
|
|
-
|
|
|
- if ((xRotationMod < kRotationThreshold || xRotationMod > (gf_PI / 2.0f - kRotationThreshold))
|
|
|
- && (yRotationMod < kRotationThreshold || yRotationMod > (gf_PI / 2.0f - kRotationThreshold))
|
|
|
- && (zRotationMod < kRotationThreshold || zRotationMod > (gf_PI / 2.0f - kRotationThreshold)))
|
|
|
- {
|
|
|
- rotationWarningLevel = eRotationWarningLevel_Rotated;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- rotationWarningLevel = eRotationWarningLevel_RotatedNonRectangular;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return rotationWarningLevel;
|
|
|
-}
|
|
|
-
|
|
|
-bool CBaseObject::IsSkipSelectionHelper() const
|
|
|
-{
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
-bool CBaseObject::CanBeHightlighted() const
|
|
|
-{
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-Matrix33 CBaseObject::GetWorldRotTM() const
|
|
|
-{
|
|
|
- if (GetParent())
|
|
|
- {
|
|
|
- return GetParent()->GetWorldRotTM() * Matrix33(GetRotation());
|
|
|
- }
|
|
|
- return Matrix33(GetRotation());
|
|
|
-}
|
|
|
-
|
|
|
-Matrix33 CBaseObject::GetWorldScaleTM() const
|
|
|
-{
|
|
|
- if (GetParent())
|
|
|
- {
|
|
|
- return GetParent()->GetWorldScaleTM() * Matrix33::CreateScale(GetScale());
|
|
|
- }
|
|
|
- return Matrix33::CreateScale(GetScale());
|
|
|
-}
|
|
|
-
|
|
|
-void CBaseObject::SetTransformDelegate(ITransformDelegate* pTransformDelegate)
|
|
|
-{
|
|
|
- m_pTransformDelegate = pTransformDelegate;
|
|
|
- InvalidateTM(0);
|
|
|
-}
|
|
|
-
|
|
|
-void CBaseObject::AddMember(CBaseObject* pMember, bool bKeepPos /*=true */)
|
|
|
-{
|
|
|
- AttachChild(pMember, bKeepPos);
|
|
|
-}
|
|
|
-
|
|
|
-void CBaseObject::OnBeforeAreaChange()
|
|
|
-{
|
|
|
- AABB aabb;
|
|
|
- GetBoundBox(aabb);
|
|
|
- GetIEditor()->GetGameEngine()->OnAreaModified(aabb);
|
|
|
-}
|
|
|
-
|
|
|
-#include <Objects/moc_BaseObject.cpp>
|