You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2806 lines
97 KiB
C++
2806 lines
97 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
#include "ComponentEntityEditorPlugin_precompiled.h"
|
|
|
|
#include "SandboxIntegration.h"
|
|
|
|
#include <AzCore/Component/ComponentApplicationBus.h>
|
|
#include <AzCore/Component/Entity.h>
|
|
#include <AzCore/Component/TransformBus.h>
|
|
#include <AzCore/Debug/Profiler.h>
|
|
#include <AzCore/Math/Transform.h>
|
|
#include <AzCore/RTTI/AttributeReader.h>
|
|
#include <AzCore/Slice/SliceComponent.h>
|
|
#include <AzCore/std/functional.h>
|
|
#include <AzCore/std/string/string.h>
|
|
#include <AzCore/Asset/AssetManager.h>
|
|
#include <AzCore/Outcome/Outcome.h>
|
|
#include <AzCore/Interface/Interface.h>
|
|
#include <AzFramework/API/ApplicationAPI.h>
|
|
#include <AzFramework/Asset/AssetSystemBus.h>
|
|
#include <AzFramework/Entity/EntityContextBus.h>
|
|
#include <AzFramework/Physics/Material.h>
|
|
#include <AzFramework/StringFunc/StringFunc.h>
|
|
#include <AzFramework/API/AtomActiveInterface.h>
|
|
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
|
#include <AzToolsFramework/API/EntityCompositionRequestBus.h>
|
|
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
|
#include <AzToolsFramework/AssetBrowser/AssetBrowserBus.h>
|
|
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
|
|
#include <AzToolsFramework/AssetBrowser/AssetSelectionModel.h>
|
|
#include <AzToolsFramework/Commands/EntityStateCommand.h>
|
|
#include <AzToolsFramework/Commands/SelectionCommand.h>
|
|
#include <AzToolsFramework/Commands/SliceDetachEntityCommand.h>
|
|
#include <AzToolsFramework/Editor/EditorContextMenuBus.h>
|
|
#include <AzToolsFramework/Entity/EditorEntityHelpers.h>
|
|
#include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
|
|
#include <AzToolsFramework/Entity/SliceEditorEntityOwnershipServiceBus.h>
|
|
#include <AzToolsFramework/Slice/SliceRequestBus.h>
|
|
#include <AzToolsFramework/Slice/SliceUtilities.h>
|
|
#include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
|
|
#include <AzToolsFramework/ToolsComponents/EditorLayerComponent.h>
|
|
#include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
|
|
#include <AzToolsFramework/Undo/UndoSystem.h>
|
|
#include <AzToolsFramework/UI/EditorEntityUi/EditorEntityUiInterface.h>
|
|
#include <AzToolsFramework/UI/Layer/AddToLayerMenu.h>
|
|
#include <AzToolsFramework/UI/Prefab/PrefabIntegrationInterface.h>
|
|
#include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
|
|
#include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
|
|
#include <AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx>
|
|
#include <AzToolsFramework/UI/Layer/NameConflictWarning.hxx>
|
|
#include <MathConversion.h>
|
|
|
|
#include "Objects/ComponentEntityObject.h"
|
|
#include "ComponentEntityDebugPrinter.h"
|
|
#include "ISourceControl.h"
|
|
#include "UI/QComponentEntityEditorMainWindow.h"
|
|
|
|
#include <LmbrCentral/Rendering/EditorLightComponentBus.h>
|
|
#include <LmbrCentral/Scripting/TagComponentBus.h>
|
|
#include <LmbrCentral/Scripting/EditorTagComponentBus.h>
|
|
|
|
// Sandbox imports.
|
|
#include <Editor/ActionManager.h>
|
|
#include <Editor/CryEditDoc.h>
|
|
#include <Editor/GameEngine.h>
|
|
#include <Editor/DisplaySettings.h>
|
|
#include <Editor/Util/CubemapUtils.h>
|
|
#include <Editor/IconManager.h>
|
|
#include <Editor/Settings.h>
|
|
#include <Editor/StringDlg.h>
|
|
#include <Editor/QtViewPaneManager.h>
|
|
#include <IResourceSelectorHost.h>
|
|
#include "CryEdit.h"
|
|
|
|
#include <QMenu>
|
|
#include <QAction>
|
|
#include <QWidgetAction>
|
|
#include <QHBoxLayout>
|
|
#include "MainWindow.h"
|
|
|
|
#include "Include/IObjectManager.h"
|
|
|
|
#include <AzCore/std/algorithm.h>
|
|
|
|
#ifdef CreateDirectory
|
|
#undef CreateDirectory
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Gathers all selected entities, culling any that have an ancestor in the selection.
|
|
void GetSelectedEntitiesSetWithFlattenedHierarchy(AzToolsFramework::EntityIdSet& out)
|
|
{
|
|
AzToolsFramework::EntityIdList entities;
|
|
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(
|
|
entities,
|
|
&AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
|
|
|
|
for (const AZ::EntityId& entityId : entities)
|
|
{
|
|
bool selectionIncludesTransformHeritage = false;
|
|
AZ::EntityId parent = entityId;
|
|
do
|
|
{
|
|
AZ::EntityId nextParentId;
|
|
AZ::TransformBus::EventResult(
|
|
/*result*/ nextParentId,
|
|
/*address*/ parent,
|
|
&AZ::TransformBus::Events::GetParentId);
|
|
parent = nextParentId;
|
|
if (!parent.IsValid())
|
|
{
|
|
break;
|
|
}
|
|
for (const AZ::EntityId& parentCheck : entities)
|
|
{
|
|
if (parentCheck == parent)
|
|
{
|
|
selectionIncludesTransformHeritage = true;
|
|
break;
|
|
}
|
|
}
|
|
} while (parent.IsValid() && !selectionIncludesTransformHeritage);
|
|
|
|
if (!selectionIncludesTransformHeritage)
|
|
{
|
|
out.insert(entityId);
|
|
}
|
|
}
|
|
}
|
|
|
|
SandboxIntegrationManager::SandboxIntegrationManager()
|
|
: m_inObjectPickMode(false)
|
|
, m_startedUndoRecordingNestingLevel(0)
|
|
, m_dc(nullptr)
|
|
, m_notificationWindowManager(new AzToolsFramework::SliceOverridesNotificationWindowManager())
|
|
, m_entityDebugPrinter(aznew ComponentEntityDebugPrinter())
|
|
{
|
|
// Required to receive events from the Cry Engine undo system
|
|
GetIEditor()->GetUndoManager()->AddListener(this);
|
|
}
|
|
|
|
SandboxIntegrationManager::~SandboxIntegrationManager()
|
|
{
|
|
GetIEditor()->GetUndoManager()->RemoveListener(this);
|
|
}
|
|
|
|
void SandboxIntegrationManager::Setup()
|
|
{
|
|
AzFramework::AssetCatalogEventBus::Handler::BusConnect();
|
|
AzToolsFramework::ToolsApplicationEvents::Bus::Handler::BusConnect();
|
|
AzToolsFramework::EditorRequests::Bus::Handler::BusConnect();
|
|
AzToolsFramework::EditorWindowRequests::Bus::Handler::BusConnect();
|
|
|
|
// if the new viewport interaction model is enabled, then object picking is handled via
|
|
// EditorPickEntitySelection and SandboxIntegrationManager is not required
|
|
if (!IsNewViewportInteractionModelEnabled())
|
|
{
|
|
AzFramework::EntityContextId pickModeEntityContextId = GetEntityContextId();
|
|
if (!pickModeEntityContextId.IsNull())
|
|
{
|
|
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusConnect(pickModeEntityContextId);
|
|
}
|
|
}
|
|
|
|
AzToolsFramework::EditorEvents::Bus::Handler::BusConnect();
|
|
AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusConnect();
|
|
AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusConnect();
|
|
// turn on the this debug display request bus implementation if no other implementation is active
|
|
if( !(AZ::Interface<AzFramework::AtomActiveInterface>::Get() && AzFramework::DebugDisplayRequestBus::HasHandlers()))
|
|
{
|
|
m_debugDisplayBusImplementationActive = true;
|
|
AzFramework::DebugDisplayRequestBus::Handler::BusConnect(
|
|
AzToolsFramework::ViewportInteraction::g_mainViewportEntityDebugDisplayId);
|
|
}
|
|
|
|
AzFramework::DisplayContextRequestBus::Handler::BusConnect();
|
|
SetupFileExtensionMap();
|
|
AzToolsFramework::NewViewportInteractionModelEnabledRequestBus::Handler::BusConnect();
|
|
|
|
MainWindow::instance()->GetActionManager()->RegisterActionHandler(ID_FILE_SAVE_SLICE_TO_ROOT, [this]() {
|
|
SaveSlice(false);
|
|
});
|
|
MainWindow::instance()->GetActionManager()->RegisterActionHandler(ID_FILE_SAVE_SELECTED_SLICE, [this]() {
|
|
SaveSlice(true);
|
|
});
|
|
|
|
// Keep a reference to the interface EditorEntityUiInterface.
|
|
// This is used to register layer entities to their UI handler when the layer component is activated.
|
|
m_editorEntityUiInterface = AZ::Interface<AzToolsFramework::EditorEntityUiInterface>::Get();
|
|
|
|
AZ_Assert((m_editorEntityUiInterface != nullptr),
|
|
"SandboxIntegrationManager requires a EditorEntityUiInterface instance to be present on Setup().");
|
|
|
|
m_prefabIntegrationInterface = AZ::Interface<AzToolsFramework::Prefab::PrefabIntegrationInterface>::Get();
|
|
|
|
AZ_Assert(
|
|
(m_prefabIntegrationInterface != nullptr),
|
|
"SandboxIntegrationManager requires a PrefabIntegrationInterface instance to be present on Setup().");
|
|
|
|
AzToolsFramework::Layers::EditorLayerComponentNotificationBus::Handler::BusConnect();
|
|
}
|
|
|
|
void SandboxIntegrationManager::SaveSlice(const bool& QuickPushToFirstLevel)
|
|
{
|
|
AzToolsFramework::EntityIdList selectedEntities;
|
|
GetSelectedEntities(selectedEntities);
|
|
if (selectedEntities.size() == 0)
|
|
{
|
|
m_notificationWindowManager->CreateNotificationWindow(AzToolsFramework::SliceOverridesNotificationWindow::EType::TypeError, "Nothing selected - Select a slice entity with overrides and try again");
|
|
return;
|
|
}
|
|
|
|
AzToolsFramework::EntityIdList relevantEntities;
|
|
AZ::u32 entitiesInSlices;
|
|
AZStd::vector<AZ::SliceComponent::SliceInstanceAddress> sliceInstances;
|
|
GetEntitiesInSlices(selectedEntities, entitiesInSlices, sliceInstances);
|
|
if (entitiesInSlices > 0)
|
|
{
|
|
// Gather the set of relevant entities from the selected entities and all descendants
|
|
AzToolsFramework::EntityIdSet relevantEntitiesSet;
|
|
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(relevantEntitiesSet,
|
|
&AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, selectedEntities);
|
|
|
|
relevantEntities.reserve(relevantEntitiesSet.size());
|
|
for (AZ::EntityId& id : relevantEntitiesSet)
|
|
{
|
|
relevantEntities.push_back(id);
|
|
}
|
|
}
|
|
|
|
int numEntitiesToAdd = 0;
|
|
int numEntitiesToRemove = 0;
|
|
int numEntitiesToUpdate = 0;
|
|
if (AzToolsFramework::SliceUtilities::SaveSlice(relevantEntities, numEntitiesToAdd, numEntitiesToRemove, numEntitiesToUpdate, QuickPushToFirstLevel))
|
|
{
|
|
if (numEntitiesToAdd > 0 || numEntitiesToRemove > 0 || numEntitiesToUpdate > 0)
|
|
{
|
|
m_notificationWindowManager->CreateNotificationWindow(
|
|
AzToolsFramework::SliceOverridesNotificationWindow::EType::TypeSuccess,
|
|
QString("Save slice to parent - %1 saved successfully").arg(numEntitiesToUpdate + numEntitiesToAdd + numEntitiesToRemove));
|
|
}
|
|
else
|
|
{
|
|
m_notificationWindowManager->CreateNotificationWindow(
|
|
AzToolsFramework::SliceOverridesNotificationWindow::EType::TypeError,
|
|
"Selected has no overrides - Select a slice entity with overrides and try again");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_notificationWindowManager->CreateNotificationWindow(
|
|
AzToolsFramework::SliceOverridesNotificationWindow::EType::TypeError,
|
|
"Save slice to parent - Failed");
|
|
}
|
|
}
|
|
|
|
// This event handler is queued on main thread.
|
|
void SandboxIntegrationManager::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
|
|
{
|
|
bool prefabSystemEnabled = false;
|
|
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
|
prefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
|
|
|
if (!prefabSystemEnabled)
|
|
{
|
|
AZ::SliceComponent* editorRootSlice = nullptr;
|
|
AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::BroadcastResult(
|
|
editorRootSlice, &AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Events::GetEditorRootSlice);
|
|
AZ_Assert(editorRootSlice, "Editor root slice missing!");
|
|
|
|
for (auto restoreItr = m_sliceAssetDeletionErrorRestoreInfos.begin(); restoreItr != m_sliceAssetDeletionErrorRestoreInfos.end();)
|
|
{
|
|
if (restoreItr->m_assetId == assetId)
|
|
{
|
|
for (const auto& entityRestore : restoreItr->m_entityRestoreInfos)
|
|
{
|
|
const AZ::EntityId& entityId = entityRestore.first;
|
|
const AZ::SliceComponent::EntityRestoreInfo& restoreInfo = entityRestore.second;
|
|
|
|
AZ::Entity* entity = editorRootSlice->FindEntity(entityId);
|
|
if (entity)
|
|
{
|
|
AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Broadcast(
|
|
&AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Events::RestoreSliceEntity, entity, restoreInfo,
|
|
AzToolsFramework::SliceEntityRestoreType::Detached);
|
|
}
|
|
else
|
|
{
|
|
AZ_Error(
|
|
"DetachSliceEntity", entity, "Unable to find previous detached entity of Id %s. Cannot undo \"Detach\" action.",
|
|
entityId.ToString().c_str());
|
|
}
|
|
}
|
|
|
|
restoreItr = m_sliceAssetDeletionErrorRestoreInfos.erase(restoreItr);
|
|
}
|
|
else
|
|
{
|
|
restoreItr++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// No mutex is used for now because the only
|
|
// operation writing to shared resource is queued on main thread.
|
|
void SandboxIntegrationManager::OnCatalogAssetRemoved(const AZ::Data::AssetId& assetId, const AZ::Data::AssetInfo& assetInfo)
|
|
{
|
|
// Check to see if the removed slice asset has any instance in the level, then check if
|
|
// those dangling instances are directly under the root slice (not sub-slices). If yes,
|
|
// detach them and save necessary information so they can be restored when their slice asset
|
|
// comes back.
|
|
|
|
if (assetInfo.m_assetType == AZ::AzTypeInfo<AZ::SliceAsset>::Uuid())
|
|
{
|
|
AZ::SliceComponent* rootSlice = nullptr;
|
|
AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::BroadcastResult(rootSlice,
|
|
&AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Events::GetEditorRootSlice);
|
|
AZ_Assert(rootSlice, "Editor root slice missing!");
|
|
|
|
AZStd::vector<AZ::EntityId> entitiesToDetach;
|
|
const AZ::SliceComponent::SliceList& subSlices = rootSlice->GetSlices();
|
|
for (const AZ::SliceComponent::SliceReference& subSliceRef : subSlices)
|
|
{
|
|
if (subSliceRef.GetSliceAsset().GetId() == assetId)
|
|
{
|
|
for (const AZ::SliceComponent::SliceInstance& sliceInst : subSliceRef.GetInstances())
|
|
{
|
|
const AZ::SliceComponent::InstantiatedContainer* instContainer = sliceInst.GetInstantiated();
|
|
for (AZ::Entity* entity : instContainer->m_entities)
|
|
{
|
|
entitiesToDetach.emplace_back(entity->GetId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
AZ_Error("Editor", false, "The slice asset %s is deleted from disk, to prevent further data corruption, all of its root level slice instances are detached. "
|
|
"Restoring the slice asset on disk will revert the detaching operation.", assetInfo.m_relativePath.c_str());
|
|
|
|
AZ::SystemTickBus::QueueFunction([this, assetId, entitiesToDetach]() {
|
|
AZStd::vector<AZStd::pair<AZ::EntityId, AZ::SliceComponent::EntityRestoreInfo>> restoreInfos;
|
|
bool detachSuccess = false;
|
|
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
|
detachSuccess, &AzToolsFramework::ToolsApplicationRequestBus::Events::DetachEntities, entitiesToDetach, restoreInfos);
|
|
if (detachSuccess)
|
|
{
|
|
m_sliceAssetDeletionErrorRestoreInfos.emplace_back(assetId, AZStd::move(restoreInfos));
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::GetEntitiesInSlices(
|
|
const AzToolsFramework::EntityIdList& selectedEntities,
|
|
AZ::u32& entitiesInSlices,
|
|
AZStd::vector<AZ::SliceComponent::SliceInstanceAddress>& sliceInstances)
|
|
{
|
|
// Identify all slice instances affected by the selected entity set.
|
|
entitiesInSlices = 0;
|
|
for (const AZ::EntityId& entityId : selectedEntities)
|
|
{
|
|
AZ::SliceComponent::SliceInstanceAddress sliceAddress;
|
|
AzFramework::SliceEntityRequestBus::EventResult(sliceAddress, entityId,
|
|
&AzFramework::SliceEntityRequestBus::Events::GetOwningSlice);
|
|
|
|
if (sliceAddress.IsValid())
|
|
{
|
|
++entitiesInSlices;
|
|
|
|
if (sliceInstances.end() == AZStd::find(sliceInstances.begin(), sliceInstances.end(), sliceAddress))
|
|
{
|
|
sliceInstances.push_back(sliceAddress);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::Teardown()
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentNotificationBus::Handler::BusDisconnect();
|
|
AzToolsFramework::NewViewportInteractionModelEnabledRequestBus::Handler::BusDisconnect();
|
|
AzFramework::DisplayContextRequestBus::Handler::BusDisconnect();
|
|
if( m_debugDisplayBusImplementationActive)
|
|
{
|
|
AzFramework::DebugDisplayRequestBus::Handler::BusDisconnect();
|
|
m_debugDisplayBusImplementationActive = false;
|
|
}
|
|
AzToolsFramework::SliceEditorEntityOwnershipServiceNotificationBus::Handler::BusDisconnect();
|
|
AzToolsFramework::EditorEntityContextNotificationBus::Handler::BusDisconnect();
|
|
AzToolsFramework::EditorEvents::Bus::Handler::BusDisconnect();
|
|
|
|
if (!IsNewViewportInteractionModelEnabled())
|
|
{
|
|
AzToolsFramework::EditorPickModeNotificationBus::Handler::BusDisconnect();
|
|
}
|
|
|
|
AzToolsFramework::EditorWindowRequests::Bus::Handler::BusDisconnect();
|
|
AzToolsFramework::EditorRequests::Bus::Handler::BusDisconnect();
|
|
AzToolsFramework::ToolsApplicationEvents::Bus::Handler::BusDisconnect();
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetDC(DisplayContext* dc)
|
|
{
|
|
m_dc = dc;
|
|
}
|
|
|
|
DisplayContext* SandboxIntegrationManager::GetDC()
|
|
{
|
|
return m_dc;
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnBeginUndo([[maybe_unused]] const char* label)
|
|
{
|
|
AzToolsFramework::UndoSystem::URSequencePoint* currentBatch = nullptr;
|
|
EBUS_EVENT_RESULT(currentBatch, AzToolsFramework::ToolsApplicationRequests::Bus, GetCurrentUndoBatch);
|
|
|
|
AZ_Assert(currentBatch, "No undo batch is active.");
|
|
|
|
// Only generate a Sandbox placeholder for root-level undo batches.
|
|
if (nullptr == currentBatch->GetParent())
|
|
{
|
|
// start Cry Undo
|
|
if (!CUndo::IsRecording())
|
|
{
|
|
GetIEditor()->BeginUndo();
|
|
// flag that we started recording the undo batch
|
|
m_startedUndoRecordingNestingLevel = 1;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if (m_startedUndoRecordingNestingLevel)
|
|
{
|
|
// if we previously started recording the undo, increment the nesting level so we can
|
|
// detect when we need to accept the undo in OnEndUndo()
|
|
m_startedUndoRecordingNestingLevel++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnEndUndo(const char* label, bool changed)
|
|
{
|
|
// Add the undo only after we know it's got a legit change, we can't remove undos from the cry undo system so we do it here instead of OnBeginUndo
|
|
if (changed && CUndo::IsRecording())
|
|
{
|
|
CUndo::Record(new CToolsApplicationUndoLink(label));
|
|
}
|
|
if (m_startedUndoRecordingNestingLevel)
|
|
{
|
|
m_startedUndoRecordingNestingLevel--;
|
|
if (m_startedUndoRecordingNestingLevel == 0)
|
|
{
|
|
if (changed)
|
|
{
|
|
// only accept the undo batch that we initially started undo recording on
|
|
GetIEditor()->AcceptUndo(label);
|
|
}
|
|
else
|
|
{
|
|
GetIEditor()->CancelUndo();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::EntityParentChanged(
|
|
const AZ::EntityId entityId,
|
|
const AZ::EntityId newParentId,
|
|
const AZ::EntityId oldParentId)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
|
|
|
if (m_unsavedEntities.find(entityId) != m_unsavedEntities.end())
|
|
{
|
|
// New layers need the level to be saved.
|
|
bool isEntityLayer = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
isEntityLayer,
|
|
entityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
if (isEntityLayer)
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::Event(
|
|
entityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::AddLevelSaveDependency);
|
|
}
|
|
// Don't need to track any other unsaved changes, this is a new entity that hasn't been saved yet.
|
|
return;
|
|
}
|
|
|
|
// If an entity is moved to or from a layer, then that layer can only safely be saved when the other layer or level saves, to prevent
|
|
// accidental duplication of entities.
|
|
// This logic doesn't clear the dependency flag if an entity changes parents multiple times between saves, so if an entity visits many layers
|
|
// before finally being saved, it will result in all of those layers saving, too.
|
|
AZ::EntityId oldAncestor = oldParentId;
|
|
|
|
bool wasNotInLayer = false;
|
|
AZ::EntityId oldLayer;
|
|
do
|
|
{
|
|
if (!oldAncestor.IsValid())
|
|
{
|
|
wasNotInLayer = true;
|
|
break;
|
|
}
|
|
|
|
bool isOldAncestorLayer = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
isOldAncestorLayer,
|
|
oldAncestor,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
if (isOldAncestorLayer)
|
|
{
|
|
oldLayer = oldAncestor;
|
|
break;
|
|
}
|
|
|
|
// Must pass in an invalid id, because if no parent then nothing will modify the id variable to be invalid and stop at the no-parent case
|
|
AZ::EntityId nextParentId;
|
|
AZ::TransformBus::EventResult(
|
|
/*result*/ nextParentId,
|
|
/*address*/ oldAncestor,
|
|
&AZ::TransformBus::Events::GetParentId);
|
|
oldAncestor = nextParentId;
|
|
} while (oldAncestor.IsValid());
|
|
|
|
AZ::EntityId newAncestors = newParentId;
|
|
AZ::EntityId newAncestor = newParentId;
|
|
|
|
bool isGoingToRootScene = false;
|
|
AZ::EntityId newLayer;
|
|
do
|
|
{
|
|
if (!newAncestor.IsValid())
|
|
{
|
|
isGoingToRootScene = true;
|
|
break;
|
|
}
|
|
|
|
bool isNewAncestorLayer = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
isNewAncestorLayer,
|
|
newAncestor,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
if (isNewAncestorLayer)
|
|
{
|
|
newLayer = newAncestor;
|
|
break;
|
|
}
|
|
// The parent may not be connected to the bus yet, so start with an invalid entity ID
|
|
// to prevent an infinite loop.
|
|
AZ::EntityId ancestorParent;
|
|
AZ::TransformBus::EventResult(
|
|
/*result*/ ancestorParent,
|
|
/*address*/ newAncestor,
|
|
&AZ::TransformBus::Events::GetParentId);
|
|
newAncestor = ancestorParent;
|
|
} while (newAncestor.IsValid());
|
|
|
|
if (oldLayer.IsValid() && newLayer != oldLayer)
|
|
{
|
|
if (newLayer.IsValid())
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::Event(
|
|
oldLayer,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::AddLayerSaveDependency,
|
|
newLayer);
|
|
}
|
|
else
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::Event(
|
|
oldLayer,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::AddLevelSaveDependency);
|
|
}
|
|
}
|
|
|
|
if (newLayer.IsValid() && newLayer != oldLayer)
|
|
{
|
|
if (oldLayer.IsValid())
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::Event(
|
|
newLayer,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::AddLayerSaveDependency,
|
|
oldLayer);
|
|
}
|
|
else
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::Event(
|
|
newLayer,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::AddLevelSaveDependency);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnSaveLevel()
|
|
{
|
|
m_unsavedEntities.clear();
|
|
}
|
|
|
|
void SandboxIntegrationManager::PopulateEditorGlobalContextMenu(QMenu* menu, const AZ::Vector2& point, int flags)
|
|
{
|
|
if (!IsLevelDocumentOpen())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (flags & AzToolsFramework::EditorEvents::eECMF_USE_VIEWPORT_CENTER)
|
|
{
|
|
CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
|
|
int width = 0;
|
|
int height = 0;
|
|
// If there is no 3D Viewport active to aid in the positioning of context menu
|
|
// operations, we don't need to store anything but default values here. Any code
|
|
// using these numbers for placement should default to the origin when there's
|
|
// no 3D viewport to raycast into.
|
|
if (view)
|
|
{
|
|
view->GetDimensions(&width, &height);
|
|
}
|
|
m_contextMenuViewPoint.Set(width / 2, height / 2);
|
|
}
|
|
else
|
|
{
|
|
m_contextMenuViewPoint = point;
|
|
}
|
|
|
|
CGameEngine* gameEngine = GetIEditor()->GetGameEngine();
|
|
if (!gameEngine || !gameEngine->IsLevelLoaded())
|
|
{
|
|
return;
|
|
}
|
|
|
|
menu->setToolTipsVisible(true);
|
|
|
|
AzToolsFramework::EntityIdList selected;
|
|
GetSelectedOrHighlightedEntities(selected);
|
|
|
|
QAction* action = nullptr;
|
|
|
|
action = menu->addAction(QObject::tr("Create entity"));
|
|
QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_NewEntity(); });
|
|
|
|
if (selected.size() == 1)
|
|
{
|
|
action = menu->addAction(QObject::tr("Create child entity"));
|
|
QObject::connect(action, &QAction::triggered, action, [selected]
|
|
{
|
|
EBUS_EVENT(AzToolsFramework::EditorRequests::Bus, CreateNewEntityAsChild, selected.front());
|
|
});
|
|
}
|
|
|
|
bool prefabSystemEnabled = false;
|
|
AzFramework::ApplicationRequests::Bus::BroadcastResult(prefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
|
|
|
if (!prefabSystemEnabled)
|
|
{
|
|
menu->addSeparator();
|
|
|
|
action = menu->addAction(QObject::tr("Create layer"));
|
|
QObject::connect(action, &QAction::triggered, [this] { ContextMenu_NewLayer(); });
|
|
|
|
SetupLayerContextMenu(menu);
|
|
AzToolsFramework::EntityIdSet flattenedSelection;
|
|
GetSelectedEntitiesSetWithFlattenedHierarchy(flattenedSelection);
|
|
AzToolsFramework::SetupAddToLayerMenu(menu, flattenedSelection, [this] { return ContextMenu_NewLayer(); });
|
|
|
|
SetupSliceContextMenu(menu);
|
|
}
|
|
else
|
|
{
|
|
menu->addSeparator();
|
|
|
|
// Allow handlers to append menu items to the context menu
|
|
AzToolsFramework::EditorContextMenuBus::Broadcast(&AzToolsFramework::EditorContextMenuEvents::PopulateEditorGlobalContextMenu, menu);
|
|
}
|
|
|
|
bool prefabWipFeaturesEnabled = false;
|
|
AzFramework::ApplicationRequests::Bus::BroadcastResult(
|
|
prefabWipFeaturesEnabled, &AzFramework::ApplicationRequests::ArePrefabWipFeaturesEnabled);
|
|
|
|
if (!prefabSystemEnabled || (prefabSystemEnabled && prefabWipFeaturesEnabled))
|
|
{
|
|
action = menu->addAction(QObject::tr("Duplicate"));
|
|
QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_Duplicate(); });
|
|
if (selected.size() == 0)
|
|
{
|
|
action->setDisabled(true);
|
|
}
|
|
}
|
|
|
|
if (!prefabSystemEnabled)
|
|
{
|
|
action = menu->addAction(QObject::tr("Delete"));
|
|
QObject::connect(action, &QAction::triggered, action, [this] { ContextMenu_DeleteSelected(); });
|
|
if (selected.size() == 0)
|
|
{
|
|
action->setDisabled(true);
|
|
}
|
|
}
|
|
|
|
menu->addSeparator();
|
|
|
|
if (selected.size() > 0)
|
|
{
|
|
action = menu->addAction(QObject::tr("Open pinned Inspector"));
|
|
QObject::connect(action, &QAction::triggered, action, [this, selected]
|
|
{
|
|
AzToolsFramework::EntityIdSet pinnedEntities(selected.begin(), selected.end());
|
|
OpenPinnedInspector(pinnedEntities);
|
|
});
|
|
if (selected.size() > 0)
|
|
{
|
|
action = menu->addAction(QObject::tr("Find in Entity Outliner"));
|
|
QObject::connect(action, &QAction::triggered, [this, selected]
|
|
{
|
|
AzToolsFramework::EditorEntityContextNotificationBus::Broadcast(&EditorEntityContextNotification::OnFocusInEntityOutliner, selected);
|
|
});
|
|
}
|
|
menu->addSeparator();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::OpenPinnedInspector(const AzToolsFramework::EntityIdSet& entities)
|
|
{
|
|
QDockWidget* dockWidget = InstanceViewPane(LyViewPane::EntityInspectorPinned);
|
|
if (dockWidget)
|
|
{
|
|
QComponentEntityEditorInspectorWindow* editor = static_cast<QComponentEntityEditorInspectorWindow*>(dockWidget->widget());
|
|
if (editor && editor->GetPropertyEditor())
|
|
{
|
|
editor->GetPropertyEditor()->SetOverrideEntityIds(entities);
|
|
|
|
AZStd::string widgetTitle;
|
|
if (entities.size() == 1)
|
|
{
|
|
AZStd::string entityName;
|
|
AZ::ComponentApplicationBus::BroadcastResult(entityName, &AZ::ComponentApplicationBus::Events::GetEntityName, *entities.begin());
|
|
widgetTitle = AZStd::string::format("%s Inspector", entityName.c_str());
|
|
|
|
QObject::connect(editor->GetPropertyEditor(), &AzToolsFramework::EntityPropertyEditor::SelectedEntityNameChanged, [dockWidget](const AZ::EntityId& /*entityId*/, const AZStd::string& name)
|
|
{
|
|
AZStd::string newTitle = AZStd::string::format("%s Inspector", name.c_str());
|
|
dockWidget->setWindowTitle(newTitle.c_str());
|
|
});
|
|
}
|
|
else
|
|
{
|
|
widgetTitle = AZStd::string::format("%zu Entities - Inspector", entities.size());
|
|
}
|
|
|
|
dockWidget->setWindowTitle(widgetTitle.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::ClosePinnedInspector(AzToolsFramework::EntityPropertyEditor* editor)
|
|
{
|
|
QWidget* currentWidget = editor->parentWidget();
|
|
while (currentWidget)
|
|
{
|
|
QDockWidget* dockWidget = qobject_cast<QDockWidget*>(currentWidget);
|
|
if (dockWidget)
|
|
{
|
|
QtViewPaneManager::instance()->ClosePaneInstance(LyViewPane::EntityInspectorPinned, dockWidget);
|
|
return;
|
|
}
|
|
currentWidget = currentWidget->parentWidget();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetupLayerContextMenu(QMenu* menu)
|
|
{
|
|
// First verify that the selection contains some layers.
|
|
AzToolsFramework::EntityIdList selectedEntities;
|
|
GetSelectedOrHighlightedEntities(selectedEntities);
|
|
|
|
// Nothing selected, no layer context menus to add.
|
|
if (selectedEntities.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
AZStd::unordered_set<AZ::EntityId> layersInSelection;
|
|
|
|
for (AZ::EntityId entityId : selectedEntities)
|
|
{
|
|
bool isLayerEntity = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
isLayerEntity,
|
|
entityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
if (isLayerEntity)
|
|
{
|
|
layersInSelection.insert(entityId);
|
|
}
|
|
}
|
|
|
|
// No layers directly selected, do not add context, even if a selected entity
|
|
// is a child of a layer.
|
|
if (layersInSelection.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
menu->addSeparator();
|
|
|
|
const int selectedLayerCount = layersInSelection.size();
|
|
QString saveTitle = QObject::tr("Save layer");
|
|
if(selectedLayerCount > 1)
|
|
{
|
|
saveTitle = QObject::tr("Save %0 layers").arg(selectedLayerCount);
|
|
}
|
|
|
|
QAction* saveLayerAction = menu->addAction(saveTitle);
|
|
saveLayerAction->setToolTip(QObject::tr("Save the selected layers."));
|
|
QObject::connect(saveLayerAction, &QAction::triggered, [this, layersInSelection] { ContextMenu_SaveLayers(layersInSelection); });
|
|
|
|
if (layersInSelection.size() == 1)
|
|
{
|
|
const AZ::EntityId& id = *layersInSelection.begin();
|
|
AZ::Outcome<AZStd::string, AZStd::string> layerFullFilePathResult = AZ::Failure(AZStd::string());
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
layerFullFilePathResult,
|
|
id,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::GetLayerFullFilePath,
|
|
Path::GetPath(GetIEditor()->GetDocument()->GetActivePathName()));
|
|
|
|
// Only add option to find the layer in the Asset Browser if the layer has been saved to disk
|
|
if (layerFullFilePathResult.IsSuccess())
|
|
{
|
|
AZStd::string fullFilePath = layerFullFilePathResult.GetValue();
|
|
|
|
QAction* findLayerAssetAction = menu->addAction(QObject::tr("Find layer in Asset Browser"));
|
|
findLayerAssetAction->setToolTip(QObject::tr("Selects this layer in the Asset Browser"));
|
|
QObject::connect(findLayerAssetAction, &QAction::triggered, [this, fullFilePath] {
|
|
QtViewPaneManager::instance()->OpenPane(LyViewPane::AssetBrowser);
|
|
|
|
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(
|
|
&AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Events::ClearFilter);
|
|
|
|
AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Broadcast(
|
|
&AzToolsFramework::AssetBrowser::AssetBrowserViewRequestBus::Events::SelectFileAtPath,
|
|
fullFilePath);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetupSliceContextMenu(QMenu* menu)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Editor);
|
|
AzToolsFramework::EntityIdList selectedEntities;
|
|
GetSelectedOrHighlightedEntities(selectedEntities);
|
|
|
|
menu->addSeparator();
|
|
|
|
if (!selectedEntities.empty())
|
|
{
|
|
bool anySelectedEntityFromExistingSlice = false;
|
|
bool layerInSelection = false;
|
|
for (AZ::EntityId entityId : selectedEntities)
|
|
{
|
|
if (!anySelectedEntityFromExistingSlice)
|
|
{
|
|
AZ::SliceComponent::SliceInstanceAddress sliceAddress(nullptr, nullptr);
|
|
AzFramework::SliceEntityRequestBus::EventResult(sliceAddress, entityId,
|
|
&AzFramework::SliceEntityRequestBus::Events::GetOwningSlice);
|
|
if (sliceAddress.GetReference())
|
|
{
|
|
anySelectedEntityFromExistingSlice = true;
|
|
}
|
|
}
|
|
if (!layerInSelection)
|
|
{
|
|
bool isLayerEntity = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
isLayerEntity,
|
|
entityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
if (isLayerEntity)
|
|
{
|
|
layerInSelection = true;
|
|
}
|
|
}
|
|
// Everything being searched for was found, so exit the loop.
|
|
if (layerInSelection && anySelectedEntityFromExistingSlice)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Layers can't be in slices.
|
|
if (!layerInSelection)
|
|
{
|
|
QAction* createAction = menu->addAction(QObject::tr("Create slice..."));
|
|
createAction->setToolTip(QObject::tr("Creates a slice out of the currently selected entities."));
|
|
if (anySelectedEntityFromExistingSlice)
|
|
{
|
|
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] { ContextMenu_MakeSlice(selectedEntities); });
|
|
}
|
|
else
|
|
{
|
|
QObject::connect(createAction, &QAction::triggered, createAction, [this, selectedEntities] { ContextMenu_InheritSlice(selectedEntities); });
|
|
}
|
|
}
|
|
}
|
|
|
|
QAction* instantiateAction = menu->addAction(QObject::tr("Instantiate slice..."));
|
|
instantiateAction->setToolTip(QObject::tr("Instantiates a pre-existing slice asset into the level"));
|
|
QObject::connect(instantiateAction, &QAction::triggered, instantiateAction, [this] { ContextMenu_InstantiateSlice(); });
|
|
|
|
AzToolsFramework::EditorEvents::Bus::Broadcast(&AzToolsFramework::EditorEvents::Bus::Events::PopulateEditorGlobalContextMenu_SliceSection, menu, AZ::Vector2::CreateZero(),
|
|
AzToolsFramework::EditorEvents::eECMF_HIDE_ENTITY_CREATION | AzToolsFramework::EditorEvents::eECMF_USE_VIEWPORT_CENTER);
|
|
|
|
if (selectedEntities.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
AZ::u32 entitiesInSlices;
|
|
AZStd::vector<AZ::SliceComponent::SliceInstanceAddress> sliceInstances;
|
|
GetEntitiesInSlices(selectedEntities, entitiesInSlices, sliceInstances);
|
|
// Offer slice-related options if any selected entities belong to slice instances.
|
|
if (0 == entitiesInSlices)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Setup push and revert options (quick push and 'advanced' push UI).
|
|
SetupSliceContextMenu_Modify(menu, selectedEntities, entitiesInSlices);
|
|
|
|
menu->addSeparator();
|
|
|
|
// PopulateFindSliceMenu takes a callback to run when a slice is selected, which is called before the slice is selected in the asset browser.
|
|
// This is so the AssetBrowser can be opened first, which can only be done from a Sandbox module. PopulateFindSliceMenu exists in the AzToolsFramework
|
|
// module in SliceUtilities, so it can share logic with similar menus, like Quick Push.
|
|
// Similarly, it takes a callback for the SliceRelationshipView.
|
|
AzToolsFramework::SliceUtilities::PopulateSliceSubMenus(*menu, selectedEntities,
|
|
[]
|
|
{
|
|
// This will open the AssetBrowser if it's not open, and do nothing if it's already opened.
|
|
QtViewPaneManager::instance()->OpenPane(LyViewPane::AssetBrowser);
|
|
},
|
|
[]
|
|
{
|
|
//open SliceRelationshipView if necessary, and populate it
|
|
QtViewPaneManager::instance()->OpenPane(LyViewPane::SliceRelationships);
|
|
});
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetupSliceContextMenu_Modify(QMenu* menu, const AzToolsFramework::EntityIdList& selectedEntities, [[maybe_unused]] const AZ::u32 numEntitiesInSlices)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Editor);
|
|
using namespace AzToolsFramework;
|
|
|
|
// Gather the set of relevant entities from the selected entities and all descendants
|
|
AzToolsFramework::EntityIdSet relevantEntitiesSet;
|
|
EBUS_EVENT_RESULT(relevantEntitiesSet, AzToolsFramework::ToolsApplicationRequests::Bus, GatherEntitiesAndAllDescendents, selectedEntities);
|
|
AzToolsFramework::EntityIdList relevantEntities;
|
|
relevantEntities.reserve(relevantEntitiesSet.size());
|
|
for (AZ::EntityId& id : relevantEntitiesSet)
|
|
{
|
|
relevantEntities.push_back(id);
|
|
}
|
|
|
|
SliceUtilities::PopulateQuickPushMenu(*menu, relevantEntities);
|
|
|
|
SliceUtilities::PopulateDetachMenu(*menu, selectedEntities, relevantEntitiesSet);
|
|
|
|
bool canRevert = false;
|
|
|
|
for (AZ::EntityId id : relevantEntitiesSet)
|
|
{
|
|
bool entityHasOverrides = false;
|
|
AzToolsFramework::EditorEntityInfoRequestBus::EventResult(entityHasOverrides, id, &AzToolsFramework::EditorEntityInfoRequestBus::Events::HasSliceEntityOverrides);
|
|
if (entityHasOverrides)
|
|
{
|
|
canRevert = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
QAction* revertAction = menu->addAction(QObject::tr("Revert overrides"));
|
|
revertAction->setToolTip(QObject::tr("Revert all slice entities and their children to their last saved state."));
|
|
|
|
QObject::connect(revertAction, &QAction::triggered, [this, relevantEntities]
|
|
{
|
|
ContextMenu_ResetToSliceDefaults(relevantEntities);
|
|
});
|
|
|
|
revertAction->setEnabled(canRevert);
|
|
}
|
|
|
|
void SandboxIntegrationManager::HandleObjectModeSelection(const AZ::Vector2& point, [[maybe_unused]] int flags, bool& handled)
|
|
{
|
|
// Todo - Use a custom "edit tool". This will eliminate the need for this bus message entirely, which technically
|
|
// makes this feature less intrusive on Sandbox.
|
|
// UPDATE: This is now provided by EditorPickEntitySelection when the new Viewport Interaction Model changes are enabled.
|
|
if (m_inObjectPickMode)
|
|
{
|
|
CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
|
|
const QPoint viewPoint(point.GetX(), point.GetY());
|
|
|
|
HitContext hitInfo;
|
|
hitInfo.view = view;
|
|
if (view->HitTest(viewPoint, hitInfo))
|
|
{
|
|
if (hitInfo.object && (hitInfo.object->GetType() == OBJTYPE_AZENTITY))
|
|
{
|
|
CComponentEntityObject* entityObject = static_cast<CComponentEntityObject*>(hitInfo.object);
|
|
AzToolsFramework::EditorPickModeRequestBus::Broadcast(
|
|
&AzToolsFramework::EditorPickModeRequests::PickModeSelectEntity, entityObject->GetAssociatedEntityId());
|
|
}
|
|
}
|
|
|
|
AzToolsFramework::EditorPickModeRequestBus::Broadcast(
|
|
&AzToolsFramework::EditorPickModeRequests::StopEntityPickMode);
|
|
|
|
handled = true;
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::UpdateObjectModeCursor(AZ::u32& cursorId, AZStd::string& cursorStr)
|
|
{
|
|
if (m_inObjectPickMode)
|
|
{
|
|
cursorId = static_cast<AZ::u64>(STD_CURSOR_HAND);
|
|
cursorStr = "Pick an entity...";
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnEntityPickModeStarted()
|
|
{
|
|
m_inObjectPickMode = true;
|
|
|
|
// Currently this object pick mode is activated only via PropertyEntityIdCtrl picker.
|
|
// When the picker button is clicked, we transfer focus to the viewport so the
|
|
// spacebar can still be used to activate selection helpers.
|
|
if (CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport())
|
|
{
|
|
view->SetFocus();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnEntityPickModeStopped()
|
|
{
|
|
m_inObjectPickMode = false;
|
|
}
|
|
|
|
void SandboxIntegrationManager::CreateEditorRepresentation(AZ::Entity* entity)
|
|
{
|
|
IEditor* editor = GetIEditor();
|
|
|
|
if (CComponentEntityObject* existingObject = CComponentEntityObject::FindObjectForEntity(entity->GetId()))
|
|
{
|
|
// Refresh sandbox object if one already exists for this AZ::EntityId.
|
|
existingObject->AssignEntity(entity, false);
|
|
return;
|
|
}
|
|
|
|
CBaseObjectPtr object = editor->NewObject("ComponentEntity", "", entity->GetName().c_str(), 0.f, 0.f, 0.f, false);
|
|
|
|
if (object)
|
|
{
|
|
static_cast<CComponentEntityObject*>(object.get())->AssignEntity(entity);
|
|
|
|
// If this object type was hidden by category, re-display it.
|
|
int hideMask = editor->GetDisplaySettings()->GetObjectHideMask();
|
|
hideMask = hideMask & ~(object->GetType());
|
|
editor->GetDisplaySettings()->SetObjectHideMask(hideMask);
|
|
}
|
|
}
|
|
|
|
bool SandboxIntegrationManager::DestroyEditorRepresentation(AZ::EntityId entityId, bool deleteAZEntity)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
|
|
|
IEditor* editor = GetIEditor();
|
|
if (editor->GetObjectManager())
|
|
{
|
|
CEntityObject* object = nullptr;
|
|
EBUS_EVENT_ID_RESULT(object, entityId, AzToolsFramework::ComponentEntityEditorRequestBus, GetSandboxObject);
|
|
|
|
if (object && (object->GetType() == OBJTYPE_AZENTITY))
|
|
{
|
|
static_cast<CComponentEntityObject*>(object)->AssignEntity(nullptr, deleteAZEntity);
|
|
{
|
|
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::AzToolsFramework, "SandboxIntegrationManager::DestroyEditorRepresentation:ObjManagerDeleteObject");
|
|
editor->GetObjectManager()->DeleteObject(object);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void SandboxIntegrationManager::GoToSelectedOrHighlightedEntitiesInViewports()
|
|
{
|
|
AzToolsFramework::EntityIdList entityIds;
|
|
GetSelectedOrHighlightedEntities(entityIds);
|
|
GoToEntitiesInViewports(entityIds);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void SandboxIntegrationManager::GoToSelectedEntitiesInViewports()
|
|
{
|
|
AzToolsFramework::EntityIdList entityIds;
|
|
GetSelectedEntities(entityIds);
|
|
GoToEntitiesInViewports(entityIds);
|
|
}
|
|
|
|
bool SandboxIntegrationManager::CanGoToSelectedEntitiesInViewports()
|
|
{
|
|
AzToolsFramework::EntityIdList entityIds;
|
|
GetSelectedEntities(entityIds);
|
|
|
|
if (entityIds.size() == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (const AZ::EntityId& entityId : entityIds)
|
|
{
|
|
if (CanGoToEntityOrChildren(entityId))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SandboxIntegrationManager::CanGoToEntityOrChildren(const AZ::EntityId& entityId) const
|
|
{
|
|
bool isLayerEntity = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
isLayerEntity,
|
|
entityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
// If this entity is not a layer
|
|
if (!isLayerEntity)
|
|
{
|
|
// check if the entity exists to determine if we can go to it (e.g. system & internal entities are not visible in the viewport)
|
|
AZ::Entity* entity = nullptr;
|
|
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
|
|
return entity != nullptr;
|
|
}
|
|
|
|
AZStd::vector<AZ::EntityId> layerChildren;
|
|
AZ::TransformBus::EventResult(
|
|
/*result*/ layerChildren,
|
|
/*address*/ entityId,
|
|
&AZ::TransformBus::Events::GetChildren);
|
|
|
|
for (const AZ::EntityId& childId : layerChildren)
|
|
{
|
|
if (CanGoToEntityOrChildren(childId))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
AZ::Vector3 SandboxIntegrationManager::GetWorldPositionAtViewportCenter()
|
|
{
|
|
if (GetIEditor() && GetIEditor()->GetViewManager())
|
|
{
|
|
CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
|
|
if (view)
|
|
{
|
|
int width, height;
|
|
view->GetDimensions(&width, &height);
|
|
return LYVec3ToAZVec3(view->ViewToWorld(QPoint(width / 2, height / 2)));
|
|
}
|
|
}
|
|
|
|
return AZ::Vector3::CreateZero();
|
|
}
|
|
|
|
int SandboxIntegrationManager::GetIconTextureIdFromEntityIconPath(const AZStd::string& entityIconPath)
|
|
{
|
|
return GetIEditor()->GetIconManager()->GetIconTexture(entityIconPath.c_str());
|
|
}
|
|
|
|
void SandboxIntegrationManager::ClearRedoStack()
|
|
{
|
|
// We have two separate undo systems that are assumed to be kept in sync,
|
|
// So here we tell the legacy Undo system to clear the redo stack and at the same time
|
|
// tell the new AZ undo system to clear redo stack ("slice" the stack)
|
|
|
|
// Clear legacy redo stack
|
|
GetIEditor()->ClearRedoStack();
|
|
|
|
// Clear AZ redo stack
|
|
AzToolsFramework::UndoSystem::UndoStack* undoStack = nullptr;
|
|
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(undoStack, &AzToolsFramework::ToolsApplicationRequestBus::Events::GetUndoStack);
|
|
if (undoStack)
|
|
{
|
|
undoStack->Slice();
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void SandboxIntegrationManager::CloneSelection(bool& handled)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
|
|
|
AzToolsFramework::EntityIdSet duplicationSet;
|
|
GetSelectedEntitiesSetWithFlattenedHierarchy(duplicationSet);
|
|
|
|
if (duplicationSet.size() > 0)
|
|
{
|
|
AZStd::unordered_set<AZ::EntityId> clonedEntities;
|
|
handled = AzToolsFramework::CloneInstantiatedEntities(duplicationSet, clonedEntities);
|
|
m_unsavedEntities.insert(clonedEntities.begin(), clonedEntities.end());
|
|
}
|
|
else
|
|
{
|
|
handled = false;
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DeleteSelectedEntities(const bool includeDescendants)
|
|
{
|
|
if (IsNewViewportInteractionModelEnabled())
|
|
{
|
|
AzToolsFramework::EntityIdList selectedEntityIds;
|
|
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(
|
|
selectedEntityIds, &AzToolsFramework::ToolsApplicationRequests::GetSelectedEntities);
|
|
|
|
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(
|
|
&AzToolsFramework::ToolsApplicationRequests::DeleteEntitiesAndAllDescendants, selectedEntityIds);
|
|
}
|
|
else
|
|
{
|
|
CCryEditApp::instance()->DeleteSelectedEntities(includeDescendants);
|
|
}
|
|
}
|
|
|
|
AZ::EntityId SandboxIntegrationManager::CreateNewEntity(AZ::EntityId parentId)
|
|
{
|
|
AZ::Vector3 position = AZ::Vector3::CreateZero();
|
|
|
|
bool parentIsValid = parentId.IsValid();
|
|
if (parentIsValid)
|
|
{
|
|
// If a valid parent is a Layer, we should get our position from the viewport as all Layers are positioned at 0,0,0.
|
|
bool parentIsLayer = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
parentIsLayer,
|
|
parentId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
parentIsValid = !parentIsLayer;
|
|
}
|
|
// If we have an invalid parent, base new entity's position on the viewport.
|
|
if (!parentIsValid)
|
|
{
|
|
position = GetWorldPositionAtViewportCenter();
|
|
}
|
|
return CreateNewEntityAtPosition(position, parentId);
|
|
}
|
|
|
|
AZ::EntityId SandboxIntegrationManager::CreateNewEntityAsChild(AZ::EntityId parentId)
|
|
{
|
|
AZ_Assert(parentId.IsValid(), "Entity created as a child of an invalid parent entity.");
|
|
auto newEntityId = CreateNewEntity(parentId);
|
|
|
|
// Some modules need to know that this special action has taken place; broadcast an event.
|
|
ToolsApplicationEvents::Bus::Broadcast(&ToolsApplicationEvents::EntityCreatedAsChild, newEntityId, parentId);
|
|
return newEntityId;
|
|
}
|
|
|
|
AZ::EntityId SandboxIntegrationManager::CreateNewEntityAtPosition(const AZ::Vector3& pos, AZ::EntityId parentId)
|
|
{
|
|
using namespace AzToolsFramework;
|
|
|
|
bool prefabSystemEnabled = false;
|
|
AzFramework::ApplicationRequests::Bus::BroadcastResult(prefabSystemEnabled, &AzFramework::ApplicationRequests::IsPrefabSystemEnabled);
|
|
|
|
AZ::EntityId newEntityId;
|
|
|
|
if (!prefabSystemEnabled)
|
|
{
|
|
const AZStd::string name = AZStd::string::format("Entity%d", GetIEditor()->GetObjectManager()->GetObjectCount() + 1);
|
|
EditorEntityContextRequestBus::BroadcastResult(newEntityId, &EditorEntityContextRequests::CreateNewEditorEntity, name.c_str());
|
|
|
|
if (newEntityId.IsValid())
|
|
{
|
|
m_unsavedEntities.insert(newEntityId);
|
|
|
|
AZ::Transform transform = AZ::Transform::CreateIdentity();
|
|
transform.SetTranslation(pos);
|
|
if (parentId.IsValid())
|
|
{
|
|
AZ::TransformBus::Event(newEntityId, &AZ::TransformInterface::SetParent, parentId);
|
|
AZ::TransformBus::Event(newEntityId, &AZ::TransformInterface::SetLocalTM, transform);
|
|
}
|
|
else
|
|
{
|
|
AZ::TransformBus::Event(newEntityId, &AZ::TransformInterface::SetWorldTM, transform);
|
|
}
|
|
|
|
// Select the new entity (and deselect others).
|
|
AzToolsFramework::EntityIdList selection = {newEntityId};
|
|
|
|
ScopedUndoBatch undo("New Entity");
|
|
auto selectionCommand = AZStd::make_unique<AzToolsFramework::SelectionCommand>(selection, "");
|
|
selectionCommand->SetParent(undo.GetUndoBatch());
|
|
selectionCommand.release();
|
|
|
|
EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus, SetSelectedEntities, selection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newEntityId = m_prefabIntegrationInterface->CreateNewEntityAtPosition(pos, parentId);
|
|
}
|
|
return newEntityId;
|
|
}
|
|
|
|
AzFramework::EntityContextId SandboxIntegrationManager::GetEntityContextId()
|
|
{
|
|
AzFramework::EntityContextId editorEntityContextId = AzFramework::EntityContextId::CreateNull();
|
|
AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(editorEntityContextId, &AzToolsFramework::EditorEntityContextRequestBus::Events::GetEditorEntityContextId);
|
|
|
|
return editorEntityContextId;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
QWidget* SandboxIntegrationManager::GetAppMainWindow()
|
|
{
|
|
return MainWindow::instance();
|
|
}
|
|
|
|
QWidget* SandboxIntegrationManager::GetMainWindow()
|
|
{
|
|
return MainWindow::instance();
|
|
}
|
|
|
|
IEditor* SandboxIntegrationManager::GetEditor()
|
|
{
|
|
return GetIEditor();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool SandboxIntegrationManager::GetUndoSliceOverrideSaveValue()
|
|
{
|
|
return GetIEditor()->GetEditorSettings()->m_undoSliceOverrideSaveValue;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool SandboxIntegrationManager::GetShowCircularDependencyError()
|
|
{
|
|
return GetIEditor()->GetEditorSettings()->m_showCircularDependencyError;
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetShowCircularDependencyError(const bool& showCircularDependencyError)
|
|
{
|
|
GetIEditor()->GetEditorSettings()->m_showCircularDependencyError = showCircularDependencyError;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void SandboxIntegrationManager::SetEditTool(const char* tool)
|
|
{
|
|
GetIEditor()->SetEditTool(tool);
|
|
}
|
|
|
|
void SandboxIntegrationManager::LaunchLuaEditor(const char* files)
|
|
{
|
|
CCryEditApp::instance()->OpenLUAEditor(files);
|
|
}
|
|
|
|
bool SandboxIntegrationManager::IsLevelDocumentOpen()
|
|
{
|
|
return (GetIEditor() && GetIEditor()->GetDocument() && GetIEditor()->GetDocument()->IsDocumentReady());
|
|
}
|
|
|
|
AZStd::string SandboxIntegrationManager::GetLevelName()
|
|
{
|
|
return AZStd::string(GetIEditor()->GetGameEngine()->GetLevelName().toUtf8().constData());
|
|
}
|
|
|
|
AZStd::string SandboxIntegrationManager::SelectResource(const AZStd::string& resourceType, const AZStd::string& previousValue)
|
|
{
|
|
SResourceSelectorContext context;
|
|
context.parentWidget = GetMainWindow();
|
|
context.typeName = resourceType.c_str();
|
|
|
|
QString resource = GetEditor()->GetResourceSelectorHost()->SelectResource(context, previousValue.c_str());
|
|
return AZStd::string(resource.toUtf8().constData());
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnContextReset()
|
|
{
|
|
// Deselect everything.
|
|
EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus, SetSelectedEntities, AzToolsFramework::EntityIdList());
|
|
|
|
std::vector<CBaseObject*> objects;
|
|
objects.reserve(128);
|
|
IObjectManager* objectManager = GetIEditor()->GetObjectManager();
|
|
objectManager->FindObjectsOfType(OBJTYPE_AZENTITY, objects);
|
|
for (CBaseObject* object : objects)
|
|
{
|
|
CComponentEntityObject* componentEntity = static_cast<CComponentEntityObject*>(object);
|
|
componentEntity->AssignEntity(nullptr, false);
|
|
objectManager->DeleteObject(componentEntity);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnSliceInstantiated(const AZ::Data::AssetId& /*sliceAssetId*/, AZ::SliceComponent::SliceInstanceAddress& sliceAddress, const AzFramework::SliceInstantiationTicket& /*ticket*/)
|
|
{
|
|
// The instantiated slice isn't valid. Other systems will report this as an error.
|
|
// Bail out here, this is nothing to track in this case.
|
|
if (!sliceAddress.GetInstance())
|
|
{
|
|
return;
|
|
}
|
|
|
|
const AZ::SliceComponent::EntityIdToEntityIdMap& sliceInstanceEntityIdMap = sliceAddress.GetInstance()->GetEntityIdMap();
|
|
|
|
for (const auto& sliceInstantEntityIdPair : sliceInstanceEntityIdMap)
|
|
{
|
|
// The second in the pair is the local instance's entity ID.
|
|
m_unsavedEntities.insert(sliceInstantEntityIdPair.second);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnLayerComponentActivated(AZ::EntityId entityId)
|
|
{
|
|
m_editorEntityUiInterface->RegisterEntity(entityId, m_layerUiOverrideHandler.GetHandlerId());
|
|
}
|
|
|
|
void SandboxIntegrationManager::OnLayerComponentDeactivated(AZ::EntityId entityId)
|
|
{
|
|
m_editorEntityUiInterface->UnregisterEntity(entityId);
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_NewEntity()
|
|
{
|
|
AZ::Vector3 worldPosition = AZ::Vector3::CreateZero();
|
|
|
|
CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
|
|
// If we don't have a viewport active to aid in placement, the object
|
|
// will be created at the origin.
|
|
if (view)
|
|
{
|
|
const QPoint viewPoint(m_contextMenuViewPoint.GetX(), m_contextMenuViewPoint.GetY());
|
|
worldPosition = LYVec3ToAZVec3(view->SnapToGrid(view->ViewToWorld(viewPoint)));
|
|
}
|
|
|
|
CreateNewEntityAtPosition(worldPosition);
|
|
}
|
|
|
|
AZ::EntityId SandboxIntegrationManager::ContextMenu_NewLayer()
|
|
{
|
|
const int objectCount = GetIEditor()->GetObjectManager()->GetObjectCount();
|
|
const AZStd::string name = AZStd::string::format("Layer%d", objectCount + 1);
|
|
|
|
// Make sure the color is created fully opaque.
|
|
static QColor newLayerDefaultColor = GetIEditor()->GetColorByName("NewLayerDefaultColor");
|
|
AZ::Color newLayerColor(
|
|
aznumeric_cast<float>(newLayerDefaultColor.redF()),
|
|
aznumeric_cast<float>(newLayerDefaultColor.greenF()),
|
|
aznumeric_cast<float>(newLayerDefaultColor.blueF()),
|
|
aznumeric_cast<float>(newLayerDefaultColor.alphaF()));
|
|
|
|
AZ::EntityId newEntityId = AzToolsFramework::Layers::EditorLayerComponent::CreateLayerEntity(
|
|
name, newLayerColor, AzToolsFramework::Layers::LayerProperties::SaveFormat::Xml);
|
|
if (!newEntityId.IsValid())
|
|
{
|
|
// CreateLayerEntity already handled reporting errors if it couldn't make a new layer.
|
|
return AZ::EntityId();
|
|
}
|
|
m_unsavedEntities.insert(newEntityId);
|
|
|
|
return newEntityId;
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_SaveLayers(const AZStd::unordered_set<AZ::EntityId>& layers)
|
|
{
|
|
AZStd::unordered_map<AZStd::string, int> nameConflictMapping;
|
|
for (AZ::EntityId layerEntityId : layers)
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::Event(
|
|
layerEntityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::UpdateLayerNameConflictMapping,
|
|
nameConflictMapping);
|
|
}
|
|
|
|
if (!nameConflictMapping.empty())
|
|
{
|
|
AzToolsFramework::Layers::NameConflictWarning* nameConflictWarning = new AzToolsFramework::Layers::NameConflictWarning(GetMainWindow(), nameConflictMapping);
|
|
nameConflictWarning->exec();
|
|
return;
|
|
}
|
|
|
|
AZStd::unordered_set<AZ::EntityId> allLayersToSave(layers);
|
|
bool mustSaveLevel = false;
|
|
bool mustSaveOtherContent = false;
|
|
|
|
for (AZ::EntityId layerEntityId : layers)
|
|
{
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
mustSaveOtherContent,
|
|
layerEntityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::GatherSaveDependencies,
|
|
allLayersToSave,
|
|
mustSaveLevel);
|
|
}
|
|
|
|
if (mustSaveOtherContent)
|
|
{
|
|
QWidget* mainWindow = nullptr;
|
|
AzToolsFramework::EditorRequestBus::BroadcastResult(
|
|
mainWindow,
|
|
&AzToolsFramework::EditorRequestBus::Events::GetMainWindow);
|
|
QMessageBox saveAdditionalContentMessage(mainWindow);
|
|
saveAdditionalContentMessage.setWindowTitle(QObject::tr("Unsaved content"));
|
|
saveAdditionalContentMessage.setText(QObject::tr("You have moved entities to or from the layer(s) that you are trying to save."));
|
|
if (mustSaveLevel)
|
|
{
|
|
saveAdditionalContentMessage.setInformativeText(QObject::tr("The level and all layers will be saved."));
|
|
|
|
}
|
|
else
|
|
{
|
|
saveAdditionalContentMessage.setInformativeText(QObject::tr("All relevant layers will be saved."));
|
|
}
|
|
saveAdditionalContentMessage.setIcon(QMessageBox::Warning);
|
|
saveAdditionalContentMessage.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
|
|
saveAdditionalContentMessage.setDefaultButton(QMessageBox::Save);
|
|
int saveAdditionalContentMessageResult = saveAdditionalContentMessage.exec();
|
|
switch (saveAdditionalContentMessageResult)
|
|
{
|
|
case QMessageBox::Cancel:
|
|
// The user chose to cancel this operation.
|
|
return;
|
|
case QMessageBox::Save:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (mustSaveLevel)
|
|
{
|
|
// Saving the level causes all layers to save.
|
|
GetIEditor()->GetDocument()->Save();
|
|
return;
|
|
}
|
|
}
|
|
|
|
QString levelAbsoluteFolder = Path::GetPath(GetIEditor()->GetDocument()->GetActivePathName());
|
|
|
|
// Not used here, but needed for the ebus event.
|
|
AZStd::vector<AZ::Entity*> layerEntities;
|
|
AZ::SliceComponent::SliceReferenceToInstancePtrs instancesInLayers;
|
|
for (AZ::EntityId layerEntityId : allLayersToSave)
|
|
{
|
|
AzToolsFramework::Layers::LayerResult layerSaveResult(AzToolsFramework::Layers::LayerResult::CreateSuccess());
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
layerSaveResult,
|
|
layerEntityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::WriteLayerAndGetEntities,
|
|
levelAbsoluteFolder,
|
|
layerEntities,
|
|
instancesInLayers);
|
|
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::Event(
|
|
layerEntityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::RestoreEditorData);
|
|
layerSaveResult.MessageResult();
|
|
|
|
m_unsavedEntities.erase(layerEntityId);
|
|
}
|
|
|
|
// Update the unsaved entities list so these entities are no longer tracked as unsaved.
|
|
for (const AZ::Entity* entity : layerEntities)
|
|
{
|
|
m_unsavedEntities.erase(entity->GetId());
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_MakeSlice(AzToolsFramework::EntityIdList entities)
|
|
{
|
|
QChar bulletChar(0x2022);
|
|
|
|
QMessageBox createSliceBox(GetMainWindow());
|
|
createSliceBox.setWindowTitle(QObject::tr("Create Slice"));
|
|
createSliceBox.setText(QString(QObject::tr("Your selection contains slice instances. What kind of slice do you want to create?"))
|
|
+ "\n\n" + QString(bulletChar) + " " + "Fresh slice that doesn't inherit existing slice references."
|
|
+ "\n" + QString(bulletChar) + " " + "Nested slice that inherits existing slice references."
|
|
+ "\n\n");
|
|
createSliceBox.setIcon(QMessageBox::Warning);
|
|
|
|
QPushButton* freshSliceButton = createSliceBox.addButton(QObject::tr("Fresh Slice"), QMessageBox::ActionRole);
|
|
QPushButton* nestedSliceButton = createSliceBox.addButton(QObject::tr("Nested Slice"), QMessageBox::ActionRole);
|
|
createSliceBox.addButton(QMessageBox::Cancel);
|
|
|
|
createSliceBox.exec();
|
|
|
|
if (createSliceBox.clickedButton() == freshSliceButton)
|
|
{
|
|
MakeSliceFromEntities(entities, false, GetIEditor()->GetEditorSettings()->sliceSettings.dynamicByDefault);
|
|
}
|
|
else if (createSliceBox.clickedButton() == nestedSliceButton)
|
|
{
|
|
ContextMenu_InheritSlice(entities);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_InheritSlice(AzToolsFramework::EntityIdList entities)
|
|
{
|
|
MakeSliceFromEntities(entities, true, GetIEditor()->GetEditorSettings()->sliceSettings.dynamicByDefault);
|
|
}
|
|
void SandboxIntegrationManager::ContextMenu_InstantiateSlice()
|
|
{
|
|
AssetSelectionModel selection = AssetSelectionModel::AssetTypeSelection("Slice");
|
|
BrowseForAssets(selection);
|
|
|
|
if (selection.IsValid())
|
|
{
|
|
auto product = azrtti_cast<const ProductAssetBrowserEntry*>(selection.GetResult());
|
|
AZ_Assert(product, "Incorrect entry type selected. Expected product.");
|
|
|
|
InstantiateSliceFromAssetId(product->GetAssetId());
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::InstantiateSliceFromAssetId(const AZ::Data::AssetId& assetId)
|
|
{
|
|
AZ::Transform sliceWorldTransform = AZ::Transform::CreateIdentity();
|
|
|
|
CViewport* view = GetIEditor()->GetViewManager()->GetGameViewport();
|
|
// If we don't have a viewport active to aid in placement, the slice
|
|
// will be instantiated at the origin.
|
|
if (view)
|
|
{
|
|
const QPoint viewPoint(m_contextMenuViewPoint.GetX(), m_contextMenuViewPoint.GetY());
|
|
sliceWorldTransform = AZ::Transform::CreateTranslation(LYVec3ToAZVec3(view->SnapToGrid(view->ViewToWorld(viewPoint))));
|
|
}
|
|
|
|
AzToolsFramework::SliceRequestBus::Broadcast(&AzToolsFramework::SliceRequests::InstantiateSliceFromAssetId, assetId, sliceWorldTransform);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Returns true if at least one non-layer entity was found.
|
|
bool CollectEntityBoundingBoxesForZoom(const AZ::EntityId& entityId, AABB& selectionBounds)
|
|
{
|
|
bool isLayerEntity = false;
|
|
AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
|
|
isLayerEntity,
|
|
entityId,
|
|
&AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
|
|
|
|
if (isLayerEntity)
|
|
{
|
|
// If a layer is in the selection, zoom to its children and ignore the layer itself.
|
|
AZStd::vector<AZ::EntityId> layerChildren;
|
|
AZ::TransformBus::EventResult(
|
|
/*result*/ layerChildren,
|
|
/*address*/ entityId,
|
|
&AZ::TransformBus::Events::GetChildren);
|
|
bool childResults = false;
|
|
for (const AZ::EntityId& childId : layerChildren)
|
|
{
|
|
if (CollectEntityBoundingBoxesForZoom(childId, selectionBounds))
|
|
{
|
|
// At least one child is not a layer.
|
|
childResults = true;
|
|
}
|
|
}
|
|
return childResults;
|
|
}
|
|
else
|
|
{
|
|
AABB entityBoundingBox;
|
|
CEntityObject* componentEntityObject = nullptr;
|
|
AzToolsFramework::ComponentEntityEditorRequestBus::EventResult(
|
|
/*result*/ componentEntityObject,
|
|
/*address*/ entityId,
|
|
&AzToolsFramework::ComponentEntityEditorRequestBus::Events::GetSandboxObject);
|
|
|
|
if (componentEntityObject)
|
|
{
|
|
componentEntityObject->GetBoundBox(entityBoundingBox);
|
|
selectionBounds.Add(entityBoundingBox.min);
|
|
selectionBounds.Add(entityBoundingBox.max);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void SandboxIntegrationManager::GoToEntitiesInViewports(const AzToolsFramework::EntityIdList& entityIds)
|
|
{
|
|
if (entityIds.size() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
AABB selectionBounds;
|
|
selectionBounds.Reset();
|
|
bool entitiesAvailableForGoTo = false;
|
|
|
|
for (const AZ::EntityId& entityId : entityIds)
|
|
{
|
|
if(CollectEntityBoundingBoxesForZoom(entityId, selectionBounds))
|
|
{
|
|
entitiesAvailableForGoTo = true;
|
|
}
|
|
}
|
|
|
|
if (entitiesAvailableForGoTo)
|
|
{
|
|
int numViews = GetIEditor()->GetViewManager()->GetViewCount();
|
|
for (int viewIndex = 0; viewIndex < numViews; ++viewIndex)
|
|
{
|
|
CViewport* viewport = GetIEditor()->GetViewManager()->GetView(viewIndex);
|
|
if (viewport)
|
|
{
|
|
viewport->CenterOnAABB(selectionBounds);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_SelectSlice()
|
|
{
|
|
AzToolsFramework::EntityIdList selectedEntities;
|
|
GetSelectedOrHighlightedEntities(selectedEntities);
|
|
|
|
AzToolsFramework::EntityIdList newSelectedEntities;
|
|
|
|
for (const AZ::EntityId& entityId : selectedEntities)
|
|
{
|
|
AZ::SliceComponent::SliceInstanceAddress sliceAddress;
|
|
AzFramework::SliceEntityRequestBus::EventResult(sliceAddress, entityId,
|
|
&AzFramework::SliceEntityRequestBus::Events::GetOwningSlice);
|
|
|
|
if (sliceAddress.IsValid())
|
|
{
|
|
const AZ::SliceComponent::InstantiatedContainer* instantiated = sliceAddress.GetInstance()->GetInstantiated();
|
|
|
|
if (instantiated)
|
|
{
|
|
for (AZ::Entity* entityInSlice : instantiated->m_entities)
|
|
{
|
|
newSelectedEntities.push_back(entityInSlice->GetId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus,
|
|
SetSelectedEntities, newSelectedEntities);
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_PushEntitiesToSlice(AzToolsFramework::EntityIdList entities,
|
|
AZ::SliceComponent::EntityAncestorList ancestors,
|
|
AZ::Data::AssetId targetAncestorId,
|
|
bool affectEntireHierarchy)
|
|
{
|
|
(void)ancestors;
|
|
(void)targetAncestorId;
|
|
(void)affectEntireHierarchy;
|
|
|
|
AZ::SerializeContext* serializeContext = NULL;
|
|
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
|
|
AZ_Assert(serializeContext, "No serialize context");
|
|
|
|
AzToolsFramework::SliceUtilities::PushEntitiesModal(GetMainWindow(), entities, serializeContext);
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_Duplicate()
|
|
{
|
|
bool handled = true;
|
|
AzToolsFramework::EditorRequestBus::Broadcast(&AzToolsFramework::EditorRequests::CloneSelection, handled);
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_DeleteSelected()
|
|
{
|
|
DeleteSelectedEntities(true);
|
|
}
|
|
|
|
void SandboxIntegrationManager::ContextMenu_ResetToSliceDefaults(AzToolsFramework::EntityIdList entities)
|
|
{
|
|
AzToolsFramework::SliceEditorEntityOwnershipServiceRequestBus::Broadcast(
|
|
&AzToolsFramework::SliceEditorEntityOwnershipServiceRequests::ResetEntitiesToSliceDefaults, entities);
|
|
}
|
|
|
|
void SandboxIntegrationManager::GetSelectedEntities(AzToolsFramework::EntityIdList& entities)
|
|
{
|
|
EBUS_EVENT_RESULT(entities,
|
|
AzToolsFramework::ToolsApplicationRequests::Bus,
|
|
GetSelectedEntities);
|
|
}
|
|
|
|
void SandboxIntegrationManager::GetSelectedOrHighlightedEntities(AzToolsFramework::EntityIdList& entities)
|
|
{
|
|
AzToolsFramework::EntityIdList selectedEntities;
|
|
AzToolsFramework::EntityIdList highlightedEntities;
|
|
|
|
EBUS_EVENT_RESULT(selectedEntities,
|
|
AzToolsFramework::ToolsApplicationRequests::Bus,
|
|
GetSelectedEntities);
|
|
|
|
EBUS_EVENT_RESULT(highlightedEntities,
|
|
AzToolsFramework::ToolsApplicationRequests::Bus,
|
|
GetHighlightedEntities);
|
|
|
|
entities = AZStd::move(selectedEntities);
|
|
|
|
for (AZ::EntityId highlightedId : highlightedEntities)
|
|
{
|
|
if (entities.end() == AZStd::find(entities.begin(), entities.end(), highlightedId))
|
|
{
|
|
entities.push_back(highlightedId);
|
|
}
|
|
}
|
|
}
|
|
|
|
AZStd::string SandboxIntegrationManager::GetComponentEditorIcon(const AZ::Uuid& componentType, AZ::Component* component)
|
|
{
|
|
AZStd::string iconPath = GetComponentIconPath(componentType, AZ::Edit::Attributes::Icon, component);
|
|
return iconPath;
|
|
}
|
|
|
|
AZStd::string SandboxIntegrationManager::GetComponentIconPath(const AZ::Uuid& componentType,
|
|
AZ::Crc32 componentIconAttrib, AZ::Component* component)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzToolsFramework);
|
|
if (componentIconAttrib != AZ::Edit::Attributes::Icon
|
|
&& componentIconAttrib != AZ::Edit::Attributes::ViewportIcon
|
|
&& componentIconAttrib != AZ::Edit::Attributes::HideIcon)
|
|
{
|
|
AZ_Warning("SandboxIntegration", false, "Unrecognized component icon attribute!");
|
|
}
|
|
|
|
// return blank path if component shouldn't have icon at all
|
|
AZStd::string iconPath;
|
|
|
|
AZ::SerializeContext* serializeContext = nullptr;
|
|
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
|
|
AZ_Assert(serializeContext, "No serialize context");
|
|
|
|
auto classData = serializeContext->FindClassData(componentType);
|
|
if (classData && classData->m_editData)
|
|
{
|
|
// check if component icon should be hidden
|
|
bool hideIcon = false;
|
|
|
|
auto editorElementData = classData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData);
|
|
if (editorElementData)
|
|
{
|
|
if (auto hideIconAttribute = editorElementData->FindAttribute(AZ::Edit::Attributes::HideIcon))
|
|
{
|
|
auto hideIconAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<bool>*>(hideIconAttribute);
|
|
if (hideIconAttributeData)
|
|
{
|
|
hideIcon = hideIconAttributeData->Get(nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hideIcon)
|
|
{
|
|
// component should have icon. start with default
|
|
iconPath = GetDefaultComponentEditorIcon();
|
|
|
|
// check for specific icon
|
|
if (editorElementData)
|
|
{
|
|
if (auto iconAttribute = editorElementData->FindAttribute(componentIconAttrib))
|
|
{
|
|
if (auto iconAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<const char*>*>(iconAttribute))
|
|
{
|
|
AZStd::string iconAttributeValue = iconAttributeData->Get(component);
|
|
if (!iconAttributeValue.empty())
|
|
{
|
|
iconPath = AZStd::move(iconAttributeValue);
|
|
}
|
|
}
|
|
|
|
auto iconOverrideAttribute = editorElementData->FindAttribute(AZ::Edit::Attributes::DynamicIconOverride);
|
|
|
|
// If it has an override and we're given an instance, then get any potential override from the instance here
|
|
if (component &&
|
|
(componentIconAttrib == AZ::Edit::Attributes::Icon || componentIconAttrib == AZ::Edit::Attributes::ViewportIcon) &&
|
|
iconOverrideAttribute)
|
|
{
|
|
AZStd::string iconValue;
|
|
AZ::AttributeReader iconReader(const_cast<AZ::Component*>(component), iconOverrideAttribute);
|
|
iconReader.Read<AZStd::string>(iconValue);
|
|
|
|
if (!iconValue.empty())
|
|
{
|
|
iconPath = AZStd::move(iconValue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// If Qt doesn't know where the relative path is we have to use the more expensive full path
|
|
if (!QFile::exists(QString(iconPath.c_str())))
|
|
{
|
|
// use absolute path if possible
|
|
AZStd::string iconFullPath;
|
|
bool pathFound = false;
|
|
using AssetSysReqBus = AzToolsFramework::AssetSystemRequestBus;
|
|
AssetSysReqBus::BroadcastResult(
|
|
pathFound, &AssetSysReqBus::Events::GetFullSourcePathFromRelativeProductPath,
|
|
iconPath, iconFullPath);
|
|
if (pathFound)
|
|
{
|
|
iconPath = AZStd::move(iconFullPath);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return iconPath;
|
|
}
|
|
|
|
void SandboxIntegrationManager::UndoStackFlushed()
|
|
{
|
|
AzToolsFramework::ToolsApplicationRequestBus::Broadcast(&AzToolsFramework::ToolsApplicationRequestBus::Events::FlushUndo);
|
|
}
|
|
|
|
void SandboxIntegrationManager::MakeSliceFromEntities(const AzToolsFramework::EntityIdList& entities, bool inheritSlices, bool setAsDynamic)
|
|
{
|
|
// expand the list of entities to include all transform descendant entities
|
|
AzToolsFramework::EntityIdSet entitiesAndDescendants;
|
|
AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(entitiesAndDescendants,
|
|
&AzToolsFramework::ToolsApplicationRequestBus::Events::GatherEntitiesAndAllDescendents, entities);
|
|
|
|
const AZStd::string slicesAssetsPath = "@devassets@/Slices";
|
|
|
|
if (!gEnv->pFileIO->Exists(slicesAssetsPath.c_str()))
|
|
{
|
|
gEnv->pFileIO->CreatePath(slicesAssetsPath.c_str());
|
|
}
|
|
|
|
char path[AZ_MAX_PATH_LEN] = { 0 };
|
|
gEnv->pFileIO->ResolvePath(slicesAssetsPath.c_str(), path, AZ_MAX_PATH_LEN);
|
|
AzToolsFramework::SliceUtilities::MakeNewSlice(entitiesAndDescendants, path, inheritSlices, setAsDynamic);
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetupFileExtensionMap()
|
|
{
|
|
// There's no central registry for geometry file types.
|
|
const char* geometryFileExtensions[] =
|
|
{
|
|
CRY_GEOMETRY_FILE_EXT, // .cgf
|
|
CRY_SKEL_FILE_EXT, // .chr
|
|
CRY_CHARACTER_DEFINITION_FILE_EXT, // .cdf
|
|
};
|
|
|
|
// Cry geometry file extensions.
|
|
for (const char* extension : geometryFileExtensions)
|
|
{
|
|
m_extensionToFileType[AZ::Crc32(extension)] = IFileUtil::EFILE_TYPE_GEOMETRY;
|
|
}
|
|
|
|
// Cry image file extensions.
|
|
for (size_t i = 0; i < IResourceCompilerHelper::GetNumSourceImageFormats(); ++i)
|
|
{
|
|
const char* extension = IResourceCompilerHelper::GetSourceImageFormat(i, false);
|
|
m_extensionToFileType[AZ::Crc32(extension)] = IFileUtil::EFILE_TYPE_TEXTURE;
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::RegisterViewPane(const char* name, const char* category, const AzToolsFramework::ViewPaneOptions& viewOptions, const WidgetCreationFunc& widgetCreationFunc)
|
|
{
|
|
QtViewPaneManager::instance()->RegisterPane(name, category, widgetCreationFunc, viewOptions);
|
|
}
|
|
|
|
void SandboxIntegrationManager::RegisterCustomViewPane(const char* name, const char* category, const AzToolsFramework::ViewPaneOptions& viewOptions)
|
|
{
|
|
QtViewPaneManager::instance()->RegisterPane(name, category, nullptr, viewOptions);
|
|
}
|
|
|
|
void SandboxIntegrationManager::UnregisterViewPane(const char* name)
|
|
{
|
|
QtViewPaneManager::instance()->UnregisterPane(name);
|
|
}
|
|
|
|
QWidget* SandboxIntegrationManager::GetViewPaneWidget(const char* viewPaneName)
|
|
{
|
|
return FindViewPane<QWidget>(viewPaneName);
|
|
}
|
|
|
|
void SandboxIntegrationManager::OpenViewPane(const char* paneName)
|
|
{
|
|
const QtViewPane* pane = QtViewPaneManager::instance()->OpenPane(paneName);
|
|
if (pane)
|
|
{
|
|
pane->m_dockWidget->raise();
|
|
pane->m_dockWidget->activateWindow();
|
|
}
|
|
}
|
|
|
|
QDockWidget* SandboxIntegrationManager::InstanceViewPane(const char* paneName)
|
|
{
|
|
return QtViewPaneManager::instance()->InstancePane(paneName);
|
|
}
|
|
|
|
void SandboxIntegrationManager::CloseViewPane(const char* paneName)
|
|
{
|
|
QtViewPaneManager::instance()->ClosePane(paneName);
|
|
}
|
|
|
|
void SandboxIntegrationManager::BrowseForAssets(AssetSelectionModel& selection)
|
|
{
|
|
AssetBrowserComponentRequestBus::Broadcast(&AssetBrowserComponentRequests::PickAssets, selection, GetMainWindow());
|
|
}
|
|
|
|
void SandboxIntegrationManager::GenerateCubemapForEntity(AZ::EntityId entityId, AZStd::string* cubemapOutputPath, bool hideEntity)
|
|
{
|
|
GenerateCubemapWithIDForEntity(entityId, AZ::Uuid::CreateNull(), cubemapOutputPath, hideEntity, false);
|
|
}
|
|
|
|
void SandboxIntegrationManager::GenerateCubemapWithIDForEntity(AZ::EntityId entityId, AZ::Uuid cubemapId,
|
|
AZStd::string* cubemapOutputPath, bool hideEntity, bool hasCubemapId)
|
|
{
|
|
AZ::u32 resolution = 0;
|
|
EBUS_EVENT_ID_RESULT(resolution, entityId, LmbrCentral::EditorLightComponentRequestBus, GetCubemapResolution);
|
|
|
|
if (resolution > 0)
|
|
{
|
|
CComponentEntityObject* componentEntity = CComponentEntityObject::FindObjectForEntity(entityId);
|
|
|
|
if (componentEntity)
|
|
{
|
|
QString levelfolder = GetIEditor()->GetGameEngine()->GetLevelPath();
|
|
QString levelname = Path::GetFile(levelfolder).toLower();
|
|
QString fullGameFolder = QString(Path::GetEditingGameDataFolder().c_str());
|
|
QString texturename;
|
|
if (hasCubemapId)
|
|
{
|
|
texturename = QStringLiteral("%1_cm.tif").arg(cubemapId.ToString<QString>(false, false));
|
|
}
|
|
else
|
|
{
|
|
texturename = QStringLiteral("%1_cm.tif").arg(static_cast<qulonglong>(componentEntity->GetAssociatedEntityId()));
|
|
}
|
|
texturename = texturename.toLower();
|
|
|
|
QString fullFolder = Path::SubDirectoryCaseInsensitive(fullGameFolder, {"textures", "cubemaps", levelname});
|
|
QString fullFilename = QDir(fullFolder).absoluteFilePath(texturename);
|
|
QString relFilename = QDir(fullGameFolder).relativeFilePath(fullFilename);
|
|
|
|
bool directlyExists = CFileUtil::CreateDirectory(fullFolder.toUtf8().data());
|
|
if (!directlyExists)
|
|
{
|
|
QMessageBox::warning(GetMainWindow(), QObject::tr("Cubemap Generation Failed"), QString(QObject::tr("Failed to create destination path '%1'")).arg(fullFolder));
|
|
return;
|
|
}
|
|
|
|
if (CubemapUtils::GenCubemapWithObjectPathAndSize(fullFilename, componentEntity, static_cast<int>(resolution), hideEntity))
|
|
{
|
|
AZStd::string assetPath = relFilename.toUtf8().data();
|
|
AzFramework::StringFunc::Path::ReplaceExtension(assetPath, ".dds");
|
|
|
|
EBUS_EVENT_ID(entityId, LmbrCentral::EditorLightComponentRequestBus, SetCubemap, assetPath);
|
|
|
|
if (cubemapOutputPath)
|
|
{
|
|
*cubemapOutputPath = AZStd::move(assetPath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
QMessageBox::warning(GetMainWindow(), QObject::tr("Cubemap Generation Failed"), QObject::tr("Unspecified error"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::GenerateAllCubemaps()
|
|
{
|
|
AZStd::string cubemapOutputPath;
|
|
|
|
std::vector<CBaseObject*> results;
|
|
results.reserve(128);
|
|
GetIEditor()->GetObjectManager()->FindObjectsOfType(OBJTYPE_AZENTITY, results);
|
|
for (std::vector<CBaseObject*>::iterator end = results.end(), item = results.begin(); item != end; ++item)
|
|
{
|
|
CComponentEntityObject* componentEntity = static_cast<CComponentEntityObject*>(*item);
|
|
|
|
//check if it's customized cubemap, only generate it if it's not.
|
|
bool isCustomizedCubemap = true;
|
|
EBUS_EVENT_ID_RESULT(isCustomizedCubemap, componentEntity->GetAssociatedEntityId(), LmbrCentral::EditorLightComponentRequestBus, UseCustomizedCubemap);
|
|
|
|
if (isCustomizedCubemap)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GenerateCubemapForEntity(componentEntity->GetAssociatedEntityId(), nullptr, true);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetColor(float r, float g, float b, float a)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->SetColor(Vec3(r, g, b), a);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetColor(const AZ::Color& color)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->SetColor(AZColorToLYColorF(color));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetColor(const AZ::Vector4& color)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->SetColor(AZVec3ToLYVec3(color.GetAsVector3()), color.GetW());
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetAlpha(float a)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->SetAlpha(a);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawQuad(
|
|
AZVec3ToLYVec3(p1),
|
|
AZVec3ToLYVec3(p2),
|
|
AZVec3ToLYVec3(p3),
|
|
AZVec3ToLYVec3(p4));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawQuad(float width, float height)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawQuad(width, height);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireQuad(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireQuad(
|
|
AZVec3ToLYVec3(p1),
|
|
AZVec3ToLYVec3(p2),
|
|
AZVec3ToLYVec3(p3),
|
|
AZVec3ToLYVec3(p4));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireQuad(float width, float height)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireQuad(width, height);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawQuadGradient(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3, const AZ::Vector3& p4, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawQuadGradient(
|
|
AZVec3ToLYVec3(p1),
|
|
AZVec3ToLYVec3(p2),
|
|
AZVec3ToLYVec3(p3),
|
|
AZVec3ToLYVec3(p4),
|
|
ColorF(AZVec3ToLYVec3(firstColor.GetAsVector3()), firstColor.GetW()),
|
|
ColorF(AZVec3ToLYVec3(secondColor.GetAsVector3()), secondColor.GetW()));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTri(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector3& p3)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawTri(
|
|
AZVec3ToLYVec3(p1),
|
|
AZVec3ToLYVec3(p2),
|
|
AZVec3ToLYVec3(p3));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTriangles(const AZStd::vector<AZ::Vector3>& vertices, const AZ::Color& color)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
// transform to world space
|
|
const auto vecTransform = [this](const AZ::Vector3& vec)
|
|
{
|
|
return m_dc->GetMatrix() * AZVec3ToLYVec3(vec);
|
|
};
|
|
|
|
AZStd::vector<Vec3> cryVertices;
|
|
cryVertices.reserve(vertices.size());
|
|
AZStd::transform(vertices.begin(), vertices.end(), AZStd::back_inserter(cryVertices), vecTransform);
|
|
m_dc->DrawTriangles(
|
|
cryVertices,
|
|
AZColorToLYColorF(color));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTrianglesIndexed(const AZStd::vector<AZ::Vector3>& vertices, const AZStd::vector<AZ::u32>& indices, const AZ::Color& color)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
// transform to world space
|
|
const auto vecTransform = [this](const AZ::Vector3& vec)
|
|
{
|
|
return m_dc->GetMatrix() * AZVec3ToLYVec3(vec);
|
|
};
|
|
|
|
AZStd::vector<Vec3> cryVertices;
|
|
cryVertices.reserve(vertices.size());
|
|
AZStd::transform(vertices.begin(), vertices.end(), AZStd::back_inserter(cryVertices), vecTransform);
|
|
m_dc->DrawTrianglesIndexed(
|
|
cryVertices,
|
|
indices,
|
|
AZColorToLYColorF(color));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireBox(const AZ::Vector3& min, const AZ::Vector3& max)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireBox(
|
|
AZVec3ToLYVec3(min),
|
|
AZVec3ToLYVec3(max));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawSolidBox(const AZ::Vector3& min, const AZ::Vector3& max)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawSolidBox(
|
|
AZVec3ToLYVec3(min),
|
|
AZVec3ToLYVec3(max));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawSolidOBB(const AZ::Vector3& center, const AZ::Vector3& axisX, const AZ::Vector3& axisY, const AZ::Vector3& axisZ, const AZ::Vector3& halfExtents)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawSolidOBB(AZVec3ToLYVec3(center), AZVec3ToLYVec3(axisX), AZVec3ToLYVec3(axisY), AZVec3ToLYVec3(axisZ), AZVec3ToLYVec3(halfExtents));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawPoint(const AZ::Vector3& p, int nSize)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawPoint(AZVec3ToLYVec3(p), nSize);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawLine(
|
|
AZVec3ToLYVec3(p1),
|
|
AZVec3ToLYVec3(p2));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawLine(const AZ::Vector3& p1, const AZ::Vector3& p2, const AZ::Vector4& col1, const AZ::Vector4& col2)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawLine(
|
|
AZVec3ToLYVec3(p1),
|
|
AZVec3ToLYVec3(p2),
|
|
ColorF(AZVec3ToLYVec3(col1.GetAsVector3()), col1.GetW()),
|
|
ColorF(AZVec3ToLYVec3(col2.GetAsVector3()), col2.GetW()));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawLines(const AZStd::vector<AZ::Vector3>& lines, const AZ::Color& color)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
// transform to world space
|
|
const auto vecTransform = [this](const AZ::Vector3& vec)
|
|
{
|
|
return m_dc->GetMatrix() * AZVec3ToLYVec3(vec);
|
|
};
|
|
|
|
AZStd::vector<Vec3> cryLines;
|
|
cryLines.reserve(cryLines.size());
|
|
AZStd::transform(lines.begin(), lines.end(), AZStd::back_inserter(cryLines), vecTransform);
|
|
m_dc->DrawLines(cryLines, AZColorToLYColorF(color));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawPolyLine(const AZ::Vector3* pnts, int numPoints, bool cycled)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
Vec3* points = new Vec3[numPoints];
|
|
for (int i = 0; i < numPoints; ++i)
|
|
{
|
|
points[i] = AZVec3ToLYVec3(pnts[i]);
|
|
}
|
|
|
|
m_dc->DrawPolyLine(points, numPoints, cycled);
|
|
|
|
delete[] points;
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireQuad2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireQuad2d(
|
|
QPoint(static_cast<int>(p1.GetX()), static_cast<int>(p1.GetY())),
|
|
QPoint(static_cast<int>(p2.GetX()), static_cast<int>(p2.GetY())),
|
|
z);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawLine2d(const AZ::Vector2& p1, const AZ::Vector2& p2, float z)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawLine2d(
|
|
QPoint(static_cast<int>(p1.GetX()), static_cast<int>(p1.GetY())),
|
|
QPoint(static_cast<int>(p2.GetX()), static_cast<int>(p2.GetY())),
|
|
z);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawLine2dGradient(const AZ::Vector2& p1, const AZ::Vector2& p2, float z, const AZ::Vector4& firstColor, const AZ::Vector4& secondColor)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawLine2dGradient(
|
|
QPoint(static_cast<int>(p1.GetX()), static_cast<int>(p1.GetY())),
|
|
QPoint(static_cast<int>(p2.GetX()), static_cast<int>(p2.GetY())),
|
|
z,
|
|
ColorF(AZVec3ToLYVec3(firstColor.GetAsVector3()), firstColor.GetW()),
|
|
ColorF(AZVec3ToLYVec3(secondColor.GetAsVector3()), secondColor.GetW()));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireCircle2d(const AZ::Vector2& center, float radius, float z)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireCircle2d(
|
|
QPoint(static_cast<int>(center.GetX()), static_cast<int>(center.GetY())),
|
|
radius, z);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTerrainCircle(const AZ::Vector3& worldPos, float radius, float height)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawTerrainCircle(
|
|
AZVec3ToLYVec3(worldPos), radius, height);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTerrainCircle(const AZ::Vector3& center, float radius, float angle1, float angle2, float height)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawTerrainCircle(
|
|
AZVec3ToLYVec3(center), radius, angle1, angle2, height);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, int referenceAxis)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawArc(
|
|
AZVec3ToLYVec3(pos),
|
|
radius,
|
|
startAngleDegrees,
|
|
sweepAngleDegrees,
|
|
angularStepDegrees,
|
|
referenceAxis);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawArc(const AZ::Vector3& pos, float radius, float startAngleDegrees, float sweepAngleDegrees, float angularStepDegrees, const AZ::Vector3& fixedAxis)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawArc(
|
|
AZVec3ToLYVec3(pos),
|
|
radius,
|
|
startAngleDegrees,
|
|
sweepAngleDegrees,
|
|
angularStepDegrees,
|
|
AZVec3ToLYVec3(fixedAxis));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawCircle(const AZ::Vector3& pos, float radius, int nUnchangedAxis)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawCircle(
|
|
AZVec3ToLYVec3(pos),
|
|
radius,
|
|
nUnchangedAxis);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawHalfDottedCircle(const AZ::Vector3& pos, float radius, const AZ::Vector3& viewPos, int nUnchangedAxis)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawHalfDottedCircle(
|
|
AZVec3ToLYVec3(pos),
|
|
radius,
|
|
AZVec3ToLYVec3(viewPos),
|
|
nUnchangedAxis);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawCone(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius, float height, bool drawShaded)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawCone(
|
|
AZVec3ToLYVec3(pos),
|
|
AZVec3ToLYVec3(dir),
|
|
radius,
|
|
height,
|
|
drawShaded);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireCylinder(
|
|
AZVec3ToLYVec3(center),
|
|
AZVec3ToLYVec3(axis),
|
|
radius,
|
|
height);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawSolidCylinder(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height, bool drawShaded)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawSolidCylinder(
|
|
AZVec3ToLYVec3(center),
|
|
AZVec3ToLYVec3(axis),
|
|
radius,
|
|
height,
|
|
drawShaded);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireCapsule(const AZ::Vector3& center, const AZ::Vector3& axis, float radius, float height)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireCapsule(
|
|
AZVec3ToLYVec3(center),
|
|
AZVec3ToLYVec3(axis),
|
|
radius,
|
|
height);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTerrainRect(float x1, float y1, float x2, float y2, float height)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawTerrainRect(x1, y1, x2, y2, height);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTerrainLine(AZ::Vector3 worldPos1, AZ::Vector3 worldPos2)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawTerrainLine(
|
|
AZVec3ToLYVec3(worldPos1),
|
|
AZVec3ToLYVec3(worldPos2));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireSphere(const AZ::Vector3& pos, float radius)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireSphere(AZVec3ToLYVec3(pos), radius);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireSphere(const AZ::Vector3& pos, const AZ::Vector3 radius)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireSphere(
|
|
AZVec3ToLYVec3(pos),
|
|
AZVec3ToLYVec3(radius));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawWireDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawWireDisk(
|
|
AZVec3ToLYVec3(pos),
|
|
AZVec3ToLYVec3(dir),
|
|
radius);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawBall(const AZ::Vector3& pos, float radius, bool drawShaded)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawBall(AZVec3ToLYVec3(pos), radius, drawShaded);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawDisk(const AZ::Vector3& pos, const AZ::Vector3& dir, float radius)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawDisk(
|
|
AZVec3ToLYVec3(pos),
|
|
AZVec3ToLYVec3(dir),
|
|
radius);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawArrow(const AZ::Vector3& src, const AZ::Vector3& trg, float fHeadScale, bool b2SidedArrow)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawArrow(
|
|
AZVec3ToLYVec3(src),
|
|
AZVec3ToLYVec3(trg),
|
|
fHeadScale,
|
|
b2SidedArrow);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTextLabel(const AZ::Vector3& pos, float size, const char* text, const bool bCenter, int srcOffsetX, int srcOffsetY)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawTextLabel(
|
|
AZVec3ToLYVec3(pos),
|
|
size,
|
|
text,
|
|
bCenter,
|
|
srcOffsetX,
|
|
srcOffsetY);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::Draw2dTextLabel(float x, float y, float size, const char* text, bool bCenter)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->Draw2dTextLabel(x, y, size, text, bCenter);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTextOn2DBox(const AZ::Vector3& pos, const char* text, float textScale, const AZ::Vector4& textColor, const AZ::Vector4& textBackColor)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DrawTextOn2DBox(
|
|
AZVec3ToLYVec3(pos),
|
|
text,
|
|
textScale,
|
|
ColorF(AZVec3ToLYVec3(textColor.GetAsVector3()), textColor.GetW()),
|
|
ColorF(AZVec3ToLYVec3(textBackColor.GetAsVector3()), textBackColor.GetW()));
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTextureLabel(ITexture* texture, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
if (texture)
|
|
{
|
|
float textureWidth = aznumeric_caster(texture->GetWidth());
|
|
float textureHeight = aznumeric_caster(texture->GetHeight());
|
|
|
|
// resize the label in proportion to the actual texture size
|
|
if (textureWidth > textureHeight)
|
|
{
|
|
sizeY = sizeX * (textureHeight / textureWidth);
|
|
}
|
|
else
|
|
{
|
|
sizeX = sizeY * (textureWidth / textureHeight);
|
|
}
|
|
|
|
m_dc->DrawTextureLabel(AZVec3ToLYVec3(pos), sizeX, sizeY, texture->GetTextureID(), texIconFlags);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DrawTextureLabel(int textureId, const AZ::Vector3& pos, float sizeX, float sizeY, int texIconFlags)
|
|
{
|
|
ITexture* texture = GetIEditor()->GetRenderer()->EF_GetTextureByID(textureId);
|
|
DrawTextureLabel(texture, pos, sizeX, sizeY, texIconFlags);
|
|
}
|
|
|
|
void SandboxIntegrationManager::SetLineWidth(float width)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->SetLineWidth(width);
|
|
}
|
|
}
|
|
|
|
bool SandboxIntegrationManager::IsVisible(const AZ::Aabb& bounds)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
const AABB aabb(
|
|
AZVec3ToLYVec3(bounds.GetMin()),
|
|
AZVec3ToLYVec3(bounds.GetMax()));
|
|
|
|
return m_dc->IsVisible(aabb);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int SandboxIntegrationManager::SetFillMode(int nFillMode)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
return m_dc->SetFillMode(nFillMode);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
float SandboxIntegrationManager::GetLineWidth()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
return m_dc->GetLineWidth();
|
|
}
|
|
|
|
return 0.f;
|
|
}
|
|
|
|
float SandboxIntegrationManager::GetAspectRatio()
|
|
{
|
|
if (m_dc && m_dc->GetView())
|
|
{
|
|
return m_dc->GetView()->GetAspectRatio();
|
|
}
|
|
|
|
return 0.f;
|
|
}
|
|
|
|
void SandboxIntegrationManager::DepthTestOff()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DepthTestOff();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DepthTestOn()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DepthTestOn();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DepthWriteOff()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DepthWriteOff();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::DepthWriteOn()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->DepthWriteOn();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::CullOff()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->CullOff();
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::CullOn()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->CullOn();
|
|
}
|
|
}
|
|
|
|
bool SandboxIntegrationManager::SetDrawInFrontMode(bool bOn)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
return m_dc->SetDrawInFrontMode(bOn);
|
|
}
|
|
|
|
return 0.f;
|
|
}
|
|
|
|
AZ::u32 SandboxIntegrationManager::GetState()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
return m_dc->GetState();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
AZ::u32 SandboxIntegrationManager::SetState(AZ::u32 state)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
return m_dc->SetState(state);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void SandboxIntegrationManager::PushMatrix(const AZ::Transform& tm)
|
|
{
|
|
if (m_dc)
|
|
{
|
|
const Matrix34 m = AZTransformToLYTransform(tm);
|
|
m_dc->PushMatrix(m);
|
|
}
|
|
}
|
|
|
|
void SandboxIntegrationManager::PopMatrix()
|
|
{
|
|
if (m_dc)
|
|
{
|
|
m_dc->PopMatrix();
|
|
}
|
|
}
|
|
|
|
bool SandboxIntegrationManager::IsNewViewportInteractionModelEnabled()
|
|
{
|
|
return GetIEditor()->IsNewViewportInteractionModelEnabled();
|
|
}
|
|
|
|
bool SandboxIntegrationManager::DisplayHelpersVisible()
|
|
{
|
|
return GetIEditor()->GetDisplaySettings()->IsDisplayHelpers();
|
|
}
|