Merge branch 'development' into Atom/guthadam/atomtools_refactor_main

This commit is contained in:
Guthrie Adams
2021-08-12 23:03:52 -05:00
88 changed files with 944 additions and 342 deletions
+2 -3
View File
@@ -630,7 +630,7 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event)
if (m_renderViewport)
{
m_renderViewport->GetControllerList()->SetEnabled(true);
m_renderViewport->SetInputProcessingEnabled(true);
}
break;
@@ -2697,8 +2697,7 @@ void EditorViewportWidget::RestoreViewportAfterGameMode()
QString(
tr("When leaving \" Game Mode \" the engine will automatically restore your camera position to the default position before you "
"had entered Game mode.<br/><br/><small>If you dislike this setting you can always change this anytime in the global "
"preferences.</small><br/><br/>"))
.arg(EditorPreferencesGeneralRestoreViewportCameraSettingName);
"preferences.</small><br/><br/>"));
QString restoreOnExitGameModePopupDisabledRegKey("Editor/AutoHide/ViewportCameraRestoreOnExitGameMode");
// Read the popup disabled registry value
@@ -1452,7 +1452,7 @@ void SandboxIntegrationManager::ContextMenu_NewEntity()
if (view)
{
const QPoint viewPoint(m_contextMenuViewPoint.GetX(), m_contextMenuViewPoint.GetY());
worldPosition = LYVec3ToAZVec3(view->SnapToGrid(view->ViewToWorld(viewPoint)));
worldPosition = view->GetHitLocation(viewPoint);
}
CreateNewEntityAtPosition(worldPosition);
@@ -20,7 +20,7 @@
#include <QMouseEvent>
OutlinerTreeView::OutlinerTreeView(QWidget* pParent)
: QTreeView(pParent)
: AzQtComponents::StyledTreeView(pParent)
, m_queuedMouseEvent(nullptr)
, m_draggingUnselectedItem(false)
{
@@ -135,16 +135,12 @@ void OutlinerTreeView::startDrag(Qt::DropActions supportedActions)
if (!selectionModel()->isSelected(index))
{
startCustomDrag({ index }, supportedActions);
StartCustomDrag({ index }, supportedActions);
return;
}
}
if (!selectionModel()->selectedIndexes().empty())
{
startCustomDrag(selectionModel()->selectedIndexes(), supportedActions);
return;
}
StyledTreeView::startDrag(supportedActions);
}
void OutlinerTreeView::dragMoveEvent(QDragMoveEvent* event)
@@ -336,14 +332,14 @@ void OutlinerTreeView::processQueuedMousePressedEvent(QMouseEvent* event)
QTreeView::mousePressEvent(&mousePressedEvent);
}
void OutlinerTreeView::startCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
void OutlinerTreeView::StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
{
m_draggingUnselectedItem = true;
//sort by container entity depth and order in hierarchy for proper drag image and drop order
QModelIndexList indexListSorted = indexList;
AZStd::unordered_map<AZ::EntityId, AZStd::list<AZ::u64>> locations;
for (auto index : indexListSorted)
for (const auto& index : indexListSorted)
{
AZ::EntityId entityId(index.data(OutlinerListModel::EntityIdRole).value<AZ::u64>());
AzToolsFramework::GetEntityLocationInHierarchy(entityId, locations[entityId]);
@@ -356,74 +352,7 @@ void OutlinerTreeView::startCustomDrag(const QModelIndexList& indexList, Qt::Dro
return AZStd::lexicographical_compare(locationsE1.begin(), locationsE1.end(), locationsE2.begin(), locationsE2.end());
});
//get the data for the unselected item(s)
QMimeData* mimeData = model()->mimeData(indexListSorted);
if (mimeData)
{
//initiate drag/drop for the item
QDrag* drag = new QDrag(this);
drag->setPixmap(QPixmap::fromImage(createDragImage(indexListSorted)));
drag->setMimeData(mimeData);
Qt::DropAction defDropAction = Qt::IgnoreAction;
if (defaultDropAction() != Qt::IgnoreAction && (supportedActions & defaultDropAction()))
{
defDropAction = defaultDropAction();
}
else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
{
defDropAction = Qt::CopyAction;
}
drag->exec(supportedActions, defDropAction);
}
}
QImage OutlinerTreeView::createDragImage(const QModelIndexList& indexList)
{
//generate a drag image of the item icon and text, normally done internally, and inaccessible
QRect rect(0, 0, 0, 0);
for (auto index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = visualRect(index);
rect.setHeight(rect.height() + itemRect.height());
rect.setWidth(AZStd::GetMax(rect.width(), itemRect.width()));
}
QImage dragImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
QPainter dragPainter(&dragImage);
dragPainter.setCompositionMode(QPainter::CompositionMode_Source);
dragPainter.fillRect(dragImage.rect(), Qt::transparent);
dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
dragPainter.setOpacity(0.35f);
dragPainter.fillRect(rect, QColor("#222222"));
dragPainter.setOpacity(1.0f);
int imageY = 0;
for (auto index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = visualRect(index);
dragPainter.drawPixmap(QPoint(0, imageY),
model()->data(index, Qt::DecorationRole).value<QIcon>().pixmap(QSize(16, 16)));
dragPainter.setPen(
model()->data(index, Qt::ForegroundRole).value<QBrush>().color());
dragPainter.setFont(
font());
dragPainter.drawText(QRect(20, imageY, rect.width() - 20, rect.height()),
model()->data(index, Qt::DisplayRole).value<QString>());
imageY += itemRect.height();
}
dragPainter.end();
return dragImage;
StyledTreeView::StartCustomDrag(indexListSorted, supportedActions);
}
#include <UI/Outliner/moc_OutlinerTreeView.cpp>
@@ -15,7 +15,8 @@
#include <QBasicTimer>
#include <QEvent>
#include <QTreeView>
#include <AzQtComponents/Components/Widgets/TreeView.h>
#endif
#pragma once
@@ -31,7 +32,7 @@ class OutlinerTreeViewModel;
//! allow for dragging and dropping of entities from the outliner into the property editor
//! of other entities. If the selection updates instantly, this would never be possible.
class OutlinerTreeView
: public QTreeView
: public AzQtComponents::StyledTreeView
{
Q_OBJECT;
public:
@@ -66,9 +67,7 @@ private:
void processQueuedMousePressedEvent(QMouseEvent* event);
void startCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions);
QImage createDragImage(const QModelIndexList& indexList);
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
void DrawLayerUI(QPainter* painter, const QRect& rect, const QModelIndex& index) const;
+24 -18
View File
@@ -46,24 +46,7 @@ void QtViewport::BuildDragDropContext(AzQtComponents::ViewportDragContext& conte
PreWidgetRendering(); // required so that the current render cam is set.
Vec3 pos = Vec3(ZERO);
HitContext hit;
if (HitTest(pt, hit))
{
pos = hit.raySrc + hit.rayDir * hit.dist;
pos = SnapToGrid(pos);
}
else
{
bool hitTerrain;
pos = ViewToWorld(pt, &hitTerrain);
if (hitTerrain)
{
pos.z = GetIEditor()->GetTerrainElevation(pos.x, pos.y);
}
pos = SnapToGrid(pos);
}
context.m_hitLocation = AZ::Vector3(pos.x, pos.y, pos.z);
context.m_hitLocation = GetHitLocation(pt);
PostWidgetRendering();
}
@@ -1154,6 +1137,29 @@ bool QtViewport::HitTest(const QPoint& point, HitContext& hitInfo)
return false;
}
AZ::Vector3 QtViewport::GetHitLocation(const QPoint& point)
{
Vec3 pos = Vec3(ZERO);
HitContext hit;
if (HitTest(point, hit))
{
pos = hit.raySrc + hit.rayDir * hit.dist;
pos = SnapToGrid(pos);
}
else
{
bool hitTerrain;
pos = ViewToWorld(point, &hitTerrain);
if (hitTerrain)
{
pos.z = GetIEditor()->GetTerrainElevation(pos.x, pos.y);
}
pos = SnapToGrid(pos);
}
return AZ::Vector3(pos.x, pos.y, pos.z);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::SetZoomFactor(float fZoomFactor)
{
+2
View File
@@ -201,6 +201,7 @@ public:
//! Performs hit testing of 2d point in view to find which object hit.
virtual bool HitTest(const QPoint& point, HitContext& hitInfo) = 0;
virtual AZ::Vector3 GetHitLocation(const QPoint& point) = 0;
virtual void MakeConstructionPlane(int axis) = 0;
@@ -436,6 +437,7 @@ public:
//! Performs hit testing of 2d point in view to find which object hit.
bool HitTest(const QPoint& point, HitContext& hitInfo) override;
AZ::Vector3 GetHitLocation(const QPoint& point) override;
//! Do 2D hit testing of line in world space.
// pToCameraDistance is an optional output parameter in which distance from the camera to the line is returned.
@@ -10,6 +10,17 @@
#include <AzCore/Console/IConsole.h>
void OnVsyncIntervalChanged(uint32_t const& interval)
{
AzFramework::WindowNotificationBus::Broadcast(
&AzFramework::WindowNotificationBus::Events::OnVsyncIntervalChanged, AZ::GetClamp(interval, 0u, 4u));
}
// NOTE: On change, broadcasts the new requested vsync interval to all windows.
// The value of the vsync interval is constrained between 0 and 4
// Vsync intervals greater than 1 are not currently supported on the Vulkan RHI (see #2061 for discussion)
AZ_CVAR(uint32_t, vsync_interval, 1, OnVsyncIntervalChanged, AZ::ConsoleFunctorFlags::Null, "Set swapchain vsync interval");
namespace AzFramework
{
//////////////////////////////////////////////////////////////////////////
@@ -122,6 +133,16 @@ namespace AzFramework
return m_pimpl->GetDpiScaleFactor();
}
uint32_t NativeWindow::GetDisplayRefreshRate() const
{
return m_pimpl->GetDisplayRefreshRate();
}
uint32_t NativeWindow::GetSyncInterval() const
{
return vsync_interval;
}
/*static*/ bool NativeWindow::GetFullScreenStateOfDefaultWindow()
{
NativeWindowHandle defaultWindowHandle = nullptr;
@@ -240,4 +261,10 @@ namespace AzFramework
return 1.0f;
}
uint32_t NativeWindow::Implementation::GetDisplayRefreshRate() const
{
// Default to 60
return 60;
}
} // namespace AzFramework
@@ -130,6 +130,8 @@ namespace AzFramework
bool CanToggleFullScreenState() const override;
void ToggleFullScreenState() override;
float GetDpiScaleFactor() const override;
uint32_t GetSyncInterval() const override;
uint32_t GetDisplayRefreshRate() const override;
//! Get the full screen state of the default window.
//! \return True if the default window is currently in full screen, false otherwise.
@@ -172,6 +174,7 @@ namespace AzFramework
virtual void SetFullScreenState(bool fullScreenState);
virtual bool CanToggleFullScreenState() const;
virtual float GetDpiScaleFactor() const;
virtual uint32_t GetDisplayRefreshRate() const;
protected:
uint32_t m_width = 0;
@@ -74,6 +74,12 @@ namespace AzFramework
//! to a "standard" value of 96, the default for Windows in a DPI unaware setting. This can
//! be used to scale user interface elements to ensure legibility on high density displays.
virtual float GetDpiScaleFactor() const = 0;
//! Returns the sync interval which tells the drivers the number of v-blanks to synchronize with
virtual uint32_t GetSyncInterval() const = 0;
//! Returns the refresh rate of the main display
virtual uint32_t GetDisplayRefreshRate() const = 0;
};
using WindowRequestBus = AZ::EBus<WindowRequests>;
@@ -101,6 +107,9 @@ namespace AzFramework
//! This is called when vsync interval is changed.
virtual void OnVsyncIntervalChanged(uint32_t interval) { AZ_UNUSED(interval); };
//! This is called if the main display's refresh rate changes
virtual void OnRefreshRateChanged([[maybe_unused]] uint32_t refreshRate) {}
};
using WindowNotificationBus = AZ::EBus<WindowNotifications>;
@@ -25,7 +25,7 @@ namespace AzFramework
const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) override;
NativeWindowHandle GetWindowHandle() const override;
uint32_t GetDisplayRefreshRate() const override;
private:
ANativeWindow* m_nativeWindow = nullptr;
};
@@ -55,4 +55,9 @@ namespace AzFramework
return reinterpret_cast<NativeWindowHandle>(m_nativeWindow);
}
uint32_t NativeWindowImpl_Android::GetDisplayRefreshRate() const
{
// Using 60 for now until proper support is added
return 60;
}
} // namespace AzFramework
@@ -23,6 +23,7 @@ namespace AzFramework
const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) override;
NativeWindowHandle GetWindowHandle() const override;
uint32_t GetDisplayRefreshRate() const override;
};
NativeWindow::Implementation* NativeWindow::Implementation::Create()
@@ -44,4 +45,9 @@ namespace AzFramework
return nullptr;
}
uint32_t NativeWindowImpl_Linux::GetDisplayRefreshRate() const
{
//Using 60 for now until proper support is added
return 60;
}
} // namespace AzFramework
@@ -34,12 +34,14 @@ namespace AzFramework
bool GetFullScreenState() const override;
void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override { return true; }
uint32_t GetMainDisplayRefreshRate() const;
private:
static NSWindowStyleMask ConvertToNSWindowStyleMask(const WindowStyleMasks& styleMasks);
NSWindow* m_nativeWindow;
NSString* m_windowTitle;
uint32_t m_mainDisplayRefreshRate = 0;
};
NativeWindow::Implementation* NativeWindow::Implementation::Create()
@@ -76,6 +78,17 @@ namespace AzFramework
// Make the window active
[m_nativeWindow makeKeyAndOrderFront:nil];
m_nativeWindow.title = m_windowTitle;
CGDirectDisplayID display = CGMainDisplayID();
CGDisplayModeRef currentMode = CGDisplayCopyDisplayMode(display);
m_mainDisplayRefreshRate = CGDisplayModeGetRefreshRate(currentMode);
// Assume 60hz if 0 is returned.
// This can happen on OSX. In future we can hopefully use maximumFramesPerSecond which wont have this issue
if (m_mainDisplayRefreshRate == 0)
{
m_mainDisplayRefreshRate = 60;
}
}
NativeWindowHandle NativeWindowImpl_Darwin::GetWindowHandle() const
@@ -128,4 +141,9 @@ namespace AzFramework
const NSWindowStyleMask defaultMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
return nativeMask ? nativeMask : defaultMask;
}
uint32_t NativeWindowImpl_Darwin::GetMainDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
} // namespace AzFramework
@@ -117,9 +117,11 @@ namespace AzFramework
, m_hasFocus(false)
, m_hasTextEntryStarted(false)
{
static const char* s_keyboardCountEnvironmentVarName = "InputDeviceKeyboardInstanceCount";
s_instanceCount = AZ::Environment::FindVariable<int>(s_keyboardCountEnvironmentVarName);
if (!s_instanceCount)
{
s_instanceCount = AZ::Environment::CreateVariable<int>("InputDeviceKeyboardInstanceCount", 1);
s_instanceCount = AZ::Environment::CreateVariable<int>(s_keyboardCountEnvironmentVarName, 1);
// Register for raw keyboard input
RAWINPUTDEVICE rawInputDevice;
@@ -138,9 +138,11 @@ namespace AzFramework
{
memset(&m_lastClientRect, 0, sizeof(m_lastClientRect));
static const char* s_mouseCountEnvironmentVarName = "InputDeviceMouseInstanceCount";
s_instanceCount = AZ::Environment::FindVariable<int>(s_mouseCountEnvironmentVarName);
if (!s_instanceCount)
{
s_instanceCount = AZ::Environment::CreateVariable<int>("InputDeviceMouseInstanceCount", 1);
s_instanceCount = AZ::Environment::CreateVariable<int>(s_mouseCountEnvironmentVarName, 1);
// Register for raw mouse input
RAWINPUTDEVICE rawInputDevice;
@@ -37,6 +37,7 @@ namespace AzFramework
void SetFullScreenState(bool fullScreenState) override;
bool CanToggleFullScreenState() const override { return true; }
float GetDpiScaleFactor() const override;
uint32_t GetDisplayRefreshRate() const override;
private:
static DWORD ConvertToWin32WindowStyleMask(const WindowStyleMasks& styleMasks);
@@ -56,6 +57,7 @@ namespace AzFramework
using GetDpiForWindowType = UINT(HWND hwnd);
GetDpiForWindowType* m_getDpiFunction = nullptr;
uint32_t m_mainDisplayRefreshRate = 0;
};
const wchar_t* NativeWindowImpl_Win32::s_defaultClassName = L"O3DEWin32Class";
@@ -144,6 +146,10 @@ namespace AzFramework
{
SetWindowLongPtr(m_win32Handle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
}
DEVMODE DisplayConfig;
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig);
m_mainDisplayRefreshRate = DisplayConfig.dmDisplayFrequency;
}
void NativeWindowImpl_Win32::Activate()
@@ -263,6 +269,15 @@ namespace AzFramework
WindowNotificationBus::Event(nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnDpiScaleFactorChanged, newScaleFactor);
break;
}
case WM_WINDOWPOSCHANGED:
{
DEVMODE DisplayConfig;
EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DisplayConfig);
uint32_t refreshRate = DisplayConfig.dmDisplayFrequency;
WindowNotificationBus::Event(
nativeWindowImpl->GetWindowHandle(), &WindowNotificationBus::Events::OnRefreshRateChanged, refreshRate);
break;
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
@@ -367,6 +382,11 @@ namespace AzFramework
return aznumeric_cast<float>(dotsPerInch) / aznumeric_cast<float>(defaultDotsPerInch);
}
uint32_t NativeWindowImpl_Win32::GetDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
void NativeWindowImpl_Win32::EnterBorderlessWindowFullScreen()
{
if (m_isInBorderlessWindowFullScreenState)
@@ -27,9 +27,11 @@ namespace AzFramework
const WindowGeometry& geometry,
const WindowStyleMasks& styleMasks) override;
NativeWindowHandle GetWindowHandle() const override;
uint32_t GetMainDisplayRefreshRate() const;
private:
UIWindow* m_nativeWindow;
uint32_t m_mainDisplayRefreshRate = 0;
};
NativeWindow::Implementation* NativeWindow::Implementation::Create()
@@ -56,6 +58,7 @@ namespace AzFramework
m_width = geometry.m_width;
m_height = geometry.m_height;
m_mainDisplayRefreshRate = [[UIScreen mainScreen] maximumFramesPerSecond];
}
NativeWindowHandle NativeWindowImpl_Ios::GetWindowHandle() const
@@ -63,5 +66,9 @@ namespace AzFramework
return m_nativeWindow;
}
uint32_t NativeWindowImpl_Ios::GetMainDisplayRefreshRate() const
{
return m_mainDisplayRefreshRate;
}
} // namespace AzFramework
@@ -8,10 +8,13 @@
#include <AzQtComponents/Components/Widgets/TreeView.h>
#include <QDrag>
#include <QEvent>
#include <QSettings>
#include <QPainter>
#include <AzCore/std/algorithm.h>
#include <AzQtComponents/Components/Style.h>
#include <AzQtComponents/Components/StyleManager.h>
#include <AzQtComponents/Components/ConfigHelpers.h>
@@ -252,5 +255,109 @@ namespace AzQtComponents
return qobject_cast<QTreeView*>(widget) && !qobject_cast<TableView*>(widget);
}
StyledTreeView::StyledTreeView(QWidget* parent)
: QTreeView(parent)
{
}
void StyledTreeView::startDrag(Qt::DropActions supportedActions)
{
if (!selectionModel()->selectedIndexes().empty())
{
StartCustomDrag(selectionModel()->selectedIndexes(), supportedActions);
}
}
void StyledTreeView::StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
{
StartCustomDragInternal(this, indexList, supportedActions);
}
void StyledTreeView::StartCustomDragInternal(QAbstractItemView* itemView, const QModelIndexList& indexList, Qt::DropActions supportedActions)
{
QMimeData* mimeData = itemView->model()->mimeData(indexList);
if (mimeData)
{
QDrag* drag = new QDrag(itemView);
drag->setPixmap(QPixmap::fromImage(CreateDragImage(itemView, indexList)));
drag->setMimeData(mimeData);
Qt::DropAction defDropAction = Qt::IgnoreAction;
if (itemView->defaultDropAction() != Qt::IgnoreAction && (supportedActions & itemView->defaultDropAction()))
{
defDropAction = itemView->defaultDropAction();
}
else if (supportedActions & Qt::CopyAction && itemView->dragDropMode() != QAbstractItemView::InternalMove)
{
defDropAction = Qt::CopyAction;
}
drag->exec(supportedActions, defDropAction);
}
}
QImage StyledTreeView::CreateDragImage(QAbstractItemView* itemView, const QModelIndexList& indexList)
{
// Generate a drag image of the item icon and text, normally done internally, and inaccessible
QRect rect(0, 0, 0, 0);
for (const auto& index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = itemView->visualRect(index);
rect.setHeight(rect.height() + itemRect.height());
rect.setWidth(AZStd::GetMax(rect.width(), itemRect.width()));
}
QImage dragImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
QPainter dragPainter(&dragImage);
dragPainter.setCompositionMode(QPainter::CompositionMode_Source);
dragPainter.fillRect(dragImage.rect(), Qt::transparent);
dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
dragPainter.setOpacity(0.35f);
dragPainter.fillRect(rect, QColor("#222222"));
dragPainter.setOpacity(1.0f);
int imageY = 0;
for (const auto& index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = itemView->visualRect(index);
dragPainter.drawPixmap(QPoint(0, imageY),
itemView->model()->data(index, Qt::DecorationRole).value<QIcon>().pixmap(QSize(16, 16)));
dragPainter.setPen(
itemView->model()->data(index, Qt::ForegroundRole).value<QBrush>().color());
dragPainter.setFont(
itemView->font());
dragPainter.drawText(QRect(20, imageY, rect.width() - 20, rect.height()),
itemView->model()->data(index, Qt::DisplayRole).value<QString>());
imageY += itemRect.height();
}
dragPainter.end();
return dragImage;
}
StyledTreeWidget::StyledTreeWidget(QWidget* parent)
: QTreeWidget(parent)
{
}
void StyledTreeWidget::startDrag(Qt::DropActions supportedActions)
{
if (!selectionModel()->selectedIndexes().empty())
{
StyledTreeView::StartCustomDragInternal(this, selectionModel()->selectedIndexes(), supportedActions);
}
}
} // namespace AzQtComponents
#include <Components/Widgets/moc_TreeView.cpp>
@@ -9,8 +9,11 @@
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzCore/Memory/SystemAllocator.h>
#include <AzQtComponents/AzQtComponentsAPI.h>
#include <AzQtComponents/Components/Widgets/TableView.h>
#include <QTreeWidget>
#endif
namespace AzQtComponents
@@ -68,4 +71,46 @@ namespace AzQtComponents
void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};
//! For most of the custom QTreeView styling, we override in AzQtComponents::Style class,
//! but there are some cases (e.g. drag/drop) that can only be overriden by an actual
//! subclass of the QTreeView
class AZ_QT_COMPONENTS_API StyledTreeView
: public QTreeView
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(StyledTreeView, AZ::SystemAllocator, 0);
explicit StyledTreeView(QWidget* parent = nullptr);
//! NOTE: QTreeWidget derives from QTreeView, but because we need a custom dervied class
//! of QTreeView, then we can't inherit our custom drag methods in our custom derived
//! class of QTreeWidget, so these functions are made static so they can be shared
static void StartCustomDragInternal(QAbstractItemView* itemView, const QModelIndexList& indexList, Qt::DropActions supportedActions);
static QImage CreateDragImage(QAbstractItemView* itemView, const QModelIndexList& indexList);
protected:
void startDrag(Qt::DropActions supportedActions) override;
virtual void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions);
};
//! For most of the custom QTreeWidget styling, we override in AzQtComponents::Style class,
//! but there are some cases (e.g. drag/drop) that can only be overriden by an actual
//! subclass of the QTreeWidget.
class AZ_QT_COMPONENTS_API StyledTreeWidget
: public QTreeWidget
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(StyledTreeWidget, AZ::SystemAllocator, 0);
explicit StyledTreeWidget(QWidget* parent = nullptr);
protected:
void startDrag(Qt::DropActions supportedActions) override;
};
} // namespace AzQtComponents
@@ -27,7 +27,7 @@
namespace AzToolsFramework
{
EntityOutlinerTreeView::EntityOutlinerTreeView(QWidget* pParent)
: QTreeView(pParent)
: AzQtComponents::StyledTreeView(pParent)
, m_queuedMouseEvent(nullptr)
, m_draggingUnselectedItem(false)
{
@@ -144,16 +144,12 @@ namespace AzToolsFramework
if (!selectionModel()->isSelected(index))
{
startCustomDrag({ index }, supportedActions);
StartCustomDrag({ index }, supportedActions);
return;
}
}
if (!selectionModel()->selectedIndexes().empty())
{
startCustomDrag(selectionModel()->selectedIndexes(), supportedActions);
return;
}
StyledTreeView::startDrag(supportedActions);
}
void EntityOutlinerTreeView::dragMoveEvent(QDragMoveEvent* event)
@@ -243,14 +239,14 @@ namespace AzToolsFramework
QTreeView::mousePressEvent(&mousePressedEvent);
}
void EntityOutlinerTreeView::startCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
void EntityOutlinerTreeView::StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions)
{
m_draggingUnselectedItem = true;
//sort by container entity depth and order in hierarchy for proper drag image and drop order
QModelIndexList indexListSorted = indexList;
AZStd::unordered_map<AZ::EntityId, AZStd::list<AZ::u64>> locations;
for (auto index : indexListSorted)
for (const auto& index : indexListSorted)
{
AZ::EntityId entityId(index.data(EntityOutlinerListModel::EntityIdRole).value<AZ::u64>());
AzToolsFramework::GetEntityLocationInHierarchy(entityId, locations[entityId]);
@@ -263,76 +259,8 @@ namespace AzToolsFramework
return AZStd::lexicographical_compare(locationsE1.begin(), locationsE1.end(), locationsE2.begin(), locationsE2.end());
});
//get the data for the unselected item(s)
QMimeData* mimeData = model()->mimeData(indexListSorted);
if (mimeData)
{
//initiate drag/drop for the item
QDrag* drag = new QDrag(this);
drag->setPixmap(QPixmap::fromImage(createDragImage(indexListSorted)));
drag->setMimeData(mimeData);
Qt::DropAction defDropAction = Qt::IgnoreAction;
if (defaultDropAction() != Qt::IgnoreAction && (supportedActions & defaultDropAction()))
{
defDropAction = defaultDropAction();
}
else if (supportedActions & Qt::CopyAction && dragDropMode() != QAbstractItemView::InternalMove)
{
defDropAction = Qt::CopyAction;
}
drag->exec(supportedActions, defDropAction);
}
StyledTreeView::StartCustomDrag(indexListSorted, supportedActions);
}
QImage EntityOutlinerTreeView::createDragImage(const QModelIndexList& indexList)
{
//generate a drag image of the item icon and text, normally done internally, and inaccessible
QRect rect(0, 0, 0, 0);
for (auto index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = visualRect(index);
rect.setHeight(rect.height() + itemRect.height());
rect.setWidth(AZStd::GetMax(rect.width(), itemRect.width()));
}
QImage dragImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
QPainter dragPainter(&dragImage);
dragPainter.setCompositionMode(QPainter::CompositionMode_Source);
dragPainter.fillRect(dragImage.rect(), Qt::transparent);
dragPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
dragPainter.setOpacity(0.35f);
dragPainter.fillRect(rect, QColor("#222222"));
dragPainter.setOpacity(1.0f);
int imageY = 0;
for (auto index : indexList)
{
if (index.column() != 0)
{
continue;
}
QRect itemRect = visualRect(index);
dragPainter.drawPixmap(QPoint(0, imageY),
model()->data(index, Qt::DecorationRole).value<QIcon>().pixmap(QSize(16, 16)));
dragPainter.setPen(
model()->data(index, Qt::ForegroundRole).value<QBrush>().color());
dragPainter.setFont(
font());
dragPainter.drawText(QRect(20, imageY, rect.width() - 20, rect.height()),
model()->data(index, Qt::DisplayRole).value<QString>());
imageY += itemRect.height();
}
dragPainter.end();
return dragImage;
}
}
#include <UI/Outliner/moc_EntityOutlinerTreeView.cpp>
@@ -14,7 +14,8 @@
#include <QBasicTimer>
#include <QEvent>
#include <QTreeView>
#include <AzQtComponents/Components/Widgets/TreeView.h>
#endif
#pragma once
@@ -33,7 +34,7 @@ namespace AzToolsFramework
//! allow for dragging and dropping of entities from the outliner into the property editor
//! of other entities. If the selection updates instantly, this would never be possible.
class EntityOutlinerTreeView
: public QTreeView
: public AzQtComponents::StyledTreeView
{
Q_OBJECT;
public:
@@ -68,9 +69,7 @@ namespace AzToolsFramework
void processQueuedMousePressedEvent(QMouseEvent* event);
void startCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions);
QImage createDragImage(const QModelIndexList& indexList);
void StartCustomDrag(const QModelIndexList& indexList, Qt::DropActions supportedActions) override;
void PaintBranchBackground(QPainter* painter, const QRect& rect, const QModelIndex& index) const;
@@ -7,6 +7,7 @@
*/
#include <unistd.h>
#include <AzCore/std/string/string.h>
namespace GridMate
{
@@ -7,6 +7,7 @@
*/
#include <unistd.h>
#include <AzCore/std/string/string.h>
namespace GridMate
{
@@ -10,6 +10,7 @@
#include <O3DEApplication_Mac.h>
#include <../Common/Apple/Launcher_Apple.h>
#include <../Common/UnixLike/Launcher_UnixLike.h>
#include <AzCore/Math/Vector2.h>
#if AZ_TESTS_ENABLED
@@ -9,6 +9,7 @@
#include <CryCommon/CryLibrary.h>
#include <AzCore/Math/Vector2.h>
#include <AzCore/Memory/SystemAllocator.h>
int APIENTRY WinMain([[maybe_unused]] HINSTANCE hInstance, [[maybe_unused]] HINSTANCE hPrevInstance, [[maybe_unused]] LPSTR lpCmdLine, [[maybe_unused]] int nCmdShow)
{
+15
View File
@@ -226,6 +226,21 @@ typedef uint64 __uint64;
#define _PTRDIFF_T_DEFINED 1
typedef union _LARGE_INTEGER
{
struct
{
DWORD LowPart;
LONG HighPart;
};
struct
{
DWORD LowPart;
LONG HighPart;
} u;
long long QuadPart;
} LARGE_INTEGER;
#define _A_RDONLY (0x01) /* Read only file */
#define _A_HIDDEN (0x02) /* Hidden file */
#define _A_SUBDIR (0x10) /* Subdirectory */
+1 -1
View File
@@ -49,7 +49,7 @@
*/
#include <stdio.h>
#include <AzCore/PlatformDef.h>
#include <AzCore/PlatformIncl.h>
#include <AzCore/Module/Environment.h>
#define INJECT_ENVIRONMENT_FUNCTION "InjectEnvironment"
+2
View File
@@ -26,4 +26,6 @@
typedef uint64_t threadID;
#define VK_CONTROL 0
#endif // CRYINCLUDE_CRYCOMMON_MACSPECIFIC_H
+6 -6
View File
@@ -121,12 +121,6 @@ namespace AzTestRunner
{
const char* cwd = AzTestRunner::get_current_working_directory();
std::cout << "cwd = " << cwd << std::endl;
for (int i = 0; i < argc; i++)
{
std::cout << "arg[" << i << "] " << argv[i] << std::endl;
}
std::cout << "LIB: " << lib << std::endl;
}
@@ -227,6 +221,12 @@ namespace AzTestRunner
testMainFunction.reset();
}
// Construct a retry command if the test fails
if (result != 0)
{
std::cout << "Retry command: " << std::endl << argv[0] << " " << lib << " " << symbol << std::endl;
}
// unload and reset the module here, because it needs to release resources that were used / activated in
// system allocator / etc.
module.reset();
@@ -39,7 +39,7 @@ namespace O3DE::ProjectManager
NewProjectSettingsScreen::NewProjectSettingsScreen(QWidget* parent)
: ProjectSettingsScreen(parent)
{
const QString defaultName{ "NewProject" };
const QString defaultName = GetDefaultProjectName();
const QString defaultPath = QDir::toNativeSeparators(GetDefaultProjectPath() + "/" + defaultName);
m_projectName->lineEdit()->setText(defaultName);
@@ -162,6 +162,17 @@ namespace O3DE::ProjectManager
return defaultPath;
}
QString NewProjectSettingsScreen::GetDefaultProjectName()
{
return "NewProject";
}
QString NewProjectSettingsScreen::GetProjectAutoPath()
{
const QString projectName = m_projectName->lineEdit()->text();
return QDir::toNativeSeparators(GetDefaultProjectPath() + "/" + projectName);
}
ProjectManagerScreen NewProjectSettingsScreen::GetScreenEnum()
{
return ProjectManagerScreen::NewProjectSettings;
@@ -260,4 +271,22 @@ namespace O3DE::ProjectManager
m_projectTemplateButtonGroup->blockSignals(false);
}
}
void NewProjectSettingsScreen::OnProjectNameUpdated()
{
if (ValidateProjectName() && !m_userChangedProjectPath)
{
m_projectPath->setText(GetProjectAutoPath());
}
}
void NewProjectSettingsScreen::OnProjectPathUpdated()
{
const QString defaultPath = QDir::toNativeSeparators(GetDefaultProjectPath() + "/" + GetDefaultProjectName());
const QString autoPath = GetProjectAutoPath();
const QString path = m_projectPath->lineEdit()->text();
m_userChangedProjectPath = path != defaultPath && path != autoPath;
ValidateProjectPath();
}
} // namespace O3DE::ProjectManager
@@ -40,8 +40,14 @@ namespace O3DE::ProjectManager
signals:
void OnTemplateSelectionChanged(int oldIndex, int newIndex);
protected:
void OnProjectNameUpdated() override;
void OnProjectPathUpdated() override;
private:
QString GetDefaultProjectName();
QString GetDefaultProjectPath();
QString GetProjectAutoPath();
QFrame* CreateTemplateDetails(int margin);
void UpdateTemplateDetails(const ProjectTemplateInfo& templateInfo);
@@ -51,6 +57,7 @@ namespace O3DE::ProjectManager
TagContainerWidget* m_templateIncludedGems;
QVector<ProjectTemplateInfo> m_templates;
int m_selectedTemplateIndex = -1;
bool m_userChangedProjectPath = false;
inline constexpr static int s_spacerSize = 20;
inline constexpr static int s_templateDetailsContentMargin = 20;
@@ -40,12 +40,11 @@ namespace O3DE::ProjectManager
m_verticalLayout->setAlignment(Qt::AlignTop);
m_projectName = new FormLineEditWidget(tr("Project name"), "", this);
connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::ValidateProjectName);
connect(m_projectName->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::OnProjectNameUpdated);
m_verticalLayout->addWidget(m_projectName);
m_projectPath = new FormFolderBrowseEditWidget(tr("Project Location"), "", this);
m_projectPath->lineEdit()->setReadOnly(true);
connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::Validate);
connect(m_projectPath->lineEdit(), &QLineEdit::textChanged, this, &ProjectSettingsScreen::OnProjectPathUpdated);
m_verticalLayout->addWidget(m_projectPath);
projectSettingsFrame->setLayout(m_verticalLayout);
@@ -110,28 +109,36 @@ namespace O3DE::ProjectManager
m_projectName->setErrorLabelVisible(!projectNameIsValid);
return projectNameIsValid;
}
bool ProjectSettingsScreen::ValidateProjectPath()
{
bool projectPathIsValid = true;
if (m_projectPath->lineEdit()->text().isEmpty())
QDir path(m_projectPath->lineEdit()->text());
if (!path.isAbsolute())
{
projectPathIsValid = false;
m_projectPath->setErrorLabelText(tr("Please provide a valid location."));
m_projectPath->setErrorLabelText(tr("Please provide an absolute path for the project location."));
}
else
else if (path.exists() && !path.isEmpty())
{
QDir path(m_projectPath->lineEdit()->text());
if (path.exists() && !path.isEmpty())
{
projectPathIsValid = false;
m_projectPath->setErrorLabelText(tr("This folder exists and isn't empty. Please choose a different location."));
}
projectPathIsValid = false;
m_projectPath->setErrorLabelText(tr("This folder exists and isn't empty. Please choose a different location."));
}
m_projectPath->setErrorLabelVisible(!projectPathIsValid);
return projectPathIsValid;
}
void ProjectSettingsScreen::OnProjectNameUpdated()
{
ValidateProjectName();
}
void ProjectSettingsScreen::OnProjectPathUpdated()
{
Validate();
}
bool ProjectSettingsScreen::Validate()
{
return ValidateProjectName() && ValidateProjectPath();
@@ -33,10 +33,13 @@ namespace O3DE::ProjectManager
virtual bool Validate();
protected slots:
virtual bool ValidateProjectName();
virtual bool ValidateProjectPath();
virtual void OnProjectNameUpdated();
virtual void OnProjectPathUpdated();
protected:
bool ValidateProjectName();
virtual bool ValidateProjectPath();
QString GetDefaultProjectPath();
QHBoxLayout* m_horizontalLayout;
@@ -108,10 +108,11 @@ namespace O3DE::ProjectManager
bool UpdateProjectSettingsScreen::ValidateProjectPath()
{
bool projectPathIsValid = true;
if (m_projectPath->lineEdit()->text().isEmpty())
QDir path(m_projectPath->lineEdit()->text());
if (!path.isAbsolute())
{
projectPathIsValid = false;
m_projectPath->setErrorLabelText(tr("Please provide a valid location."));
m_projectPath->setErrorLabelText(tr("Please provide an absolute path for the project location."));
}
m_projectPath->setErrorLabelVisible(!projectPathIsValid);
@@ -230,7 +230,7 @@ namespace TestImpact
processInFlight.m_process = LaunchProcess(AZStd::move(processInfo));
processInFlight.m_startTime = createTime;
}
catch (ProcessException& e)
catch ([[maybe_unused]] ProcessException& e)
{
AZ_Warning("ProcessScheduler", false, e.what());
createResult = LaunchResult::Failure;
@@ -169,7 +169,7 @@ namespace TestImpact
WriteFileContents<TestEngineException>(SerializeTestEnumeration(enumeration.value()), jobInfo->GetCache()->m_file);
}
}
catch (const Exception& e)
catch ([[maybe_unused]] const Exception& e)
{
AZ_Warning("Enumerate", false, e.what());
enumerations[jobId] = AZStd::nullopt;
@@ -105,6 +105,8 @@ class ViewEditController(QObject):
def _create_new_config_file(self) -> None:
configuration: Configuration = self._configuration_manager.configuration
self._set_default_region(configuration)
try:
new_config_file_path: str = file_utils.join_path(
configuration.config_directory, constants.RESOURCE_MAPPING_DEFAULT_CONFIG_FILE_NAME)
@@ -117,6 +119,15 @@ class ViewEditController(QObject):
self._rescan_config_directory()
def _set_default_region(self, configuration: Configuration):
default_region = configuration.region
if not default_region or default_region == 'aws-global':
self.set_notification_frame_text_sender.emit(
notification_label_text.VIEW_EDIT_PAGE_CREATE_NEW_CONFIG_FILE_NO_DEFAULT_REGION_MESSAGE)
logger.warning(notification_label_text.VIEW_EDIT_PAGE_CREATE_NEW_CONFIG_FILE_NO_DEFAULT_REGION_MESSAGE)
configuration.region = constants.RESOURCE_MAPPING_DEFAULT_CONFIG_FILE_REGION
def _delete_table_row(self) -> None:
indices: List[QModelIndex] = self._table_view.selectedIndexes()
self._proxy_model.remove_resources(indices)
@@ -24,6 +24,7 @@ AWS_RESOURCE_REGIONS: List[str] = ["us-east-2", "us-east-1", "us-west-1", "us-we
# Default client&server config file name
RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX: str = "_aws_resource_mappings.json"
RESOURCE_MAPPING_DEFAULT_CONFIG_FILE_NAME: str = "default" + RESOURCE_MAPPING_CONFIG_FILE_NAME_SUFFIX
RESOURCE_MAPPING_DEFAULT_CONFIG_FILE_REGION: str = "us-east-1"
# View related constants
SEARCH_TYPED_RESOURCES_VERSION: str = "Import AWS Resources"
@@ -5,6 +5,8 @@ For complete copyright and license terms please see the LICENSE at the root of t
SPDX-License-Identifier: Apache-2.0 OR MIT
"""
from model import constants
NOTIFICATION_LOADING_MESSAGE: str = "Loading..."
ERROR_PAGE_OK_TEXT: str = "OK"
@@ -21,6 +23,12 @@ VIEW_EDIT_PAGE_RESCAN_TEXT: str = "Rescan"
VIEW_EDIT_PAGE_CONFIG_FILES_PLACEHOLDER_TEXT: str = "Found {} config files"
VIEW_EDIT_PAGE_SEARCH_PLACEHOLDER_TEXT: str = "Search by Key Name, Type, Name/ID, Account ID or Region"
VIEW_EDIT_PAGE_IMPORT_RESOURCES_PLACEHOLDER_TEXT: str = "Import Additional Resources"
VIEW_EDIT_PAGE_CREATE_NEW_CONFIG_FILE_NO_DEFAULT_REGION_MESSAGE: str = \
f"Resource mapping file {constants.RESOURCE_MAPPING_DEFAULT_CONFIG_FILE_NAME} is created"\
f" with {constants.RESOURCE_MAPPING_DEFAULT_CONFIG_FILE_REGION} as the default region. "\
f"See <a href=\"https://docs.o3de.org/docs/user-guide/gems/reference/aws/aws-core/configuring-credentials/\">"\
f"<span style=\"color:#4A90E2;\">documentation</span></a> "\
f"for configuring the AWS credentials and default region."
VIEW_EDIT_PAGE_SELECT_CONFIG_FILE_MESSAGE: str = "Please select the Config file you would like to view and modify..."
VIEW_EDIT_PAGE_NO_CONFIG_FILE_FOUND_MESSAGE: str = \
@@ -482,6 +482,7 @@ class TestViewEditController(TestCase):
mock_json_utils.create_empty_resource_mapping_file.assert_called_once()
mock_file_utils.find_files_with_suffix_under_directory.assert_called_once()
self._mocked_view_edit_page.set_config_files.assert_called_with(expected_config_files)
self._test_view_edit_controller.set_notification_frame_text_sender.emit.assert_called_once()
@patch("controller.view_edit_controller.file_utils")
@patch("controller.view_edit_controller.json_utils")
@@ -496,7 +497,7 @@ class TestViewEditController(TestCase):
mock_file_utils.join_path.assert_called_once()
mock_json_utils.create_empty_resource_mapping_file.assert_called_once()
mock_file_utils.find_files_with_suffix_under_directory.assert_not_called()
self._test_view_edit_controller.set_notification_frame_text_sender.emit.assert_called_once()
assert len(self._test_view_edit_controller.set_notification_frame_text_sender.emit.mock_calls) == 2
@patch("controller.view_edit_controller.file_utils")
def test_page_rescan_button_post_notification_when_find_files_throw_exception(
@@ -42,4 +42,4 @@ namespace AWSGameLift
};
}// namespace AWSGameLift
AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Client, AWSGameLift::AWSGameLiftClientModule)
AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Clients, AWSGameLift::AWSGameLiftClientModule)
@@ -42,4 +42,4 @@ namespace AWSGameLift
};
}// namespace AWSGameLift
AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Server, AWSGameLift::AWSGameLiftServerModule)
AZ_DECLARE_MODULE_CLASS(Gem_AWSGameLift_Servers, AWSGameLift::AWSGameLiftServerModule)
@@ -125,7 +125,6 @@ namespace AZ
Format GetNearestSupportedFormat(Format requestedFormat, FormatCapabilities requestedCapabilities) const;
//! Small API to support getting supported/working swapchain formats for a window.
//! [GFX TODO]ATOM-1125] [RHI] Device::GetValidSwapChainImageFormats()
//! Returns the set of supported formats for swapchain images.
virtual AZStd::vector<Format> GetValidSwapChainImageFormats(const WindowHandle& windowHandle) const;
@@ -85,7 +85,7 @@ namespace Aftermath
#if defined(USE_NSIGHT_AFTERMATH)
AZStd::vector<GFSDK_Aftermath_ContextHandle> cntxtHandles = static_cast<GpuCrashTracker*>(crashTracker)->GetContextHandles();
GFSDK_Aftermath_ContextData* outContextData = new GFSDK_Aftermath_ContextData[cntxtHandles.size()];
GFSDK_Aftermath_Result result = GFSDK_Aftermath_GetData(cntxtHandles.size(), cntxtHandles.data(), outContextData);
GFSDK_Aftermath_Result result = GFSDK_Aftermath_GetData(static_cast<uint32_t>(cntxtHandles.size()), cntxtHandles.data(), outContextData);
AssertOnError(result);
for (int i = 0; i < cntxtHandles.size(); i++)
{
@@ -5,6 +5,8 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AZ
{
namespace Metal
@@ -5,6 +5,8 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
namespace AZ
{
namespace Metal
@@ -77,7 +77,6 @@ namespace AZ
m_samplerCache = [[NSCache alloc]init];
[m_samplerCache setName:@"SamplerCache"];
return RHI::ResultCode::Success;
}
@@ -8,6 +8,7 @@
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/string/string.h>
#include <AzFramework/Windowing/WindowBus.h>
#include <Atom/RHI/CpuProfiler.h>
#include <RHI/Device.h>
#include <RHI/Image.h>
@@ -74,21 +75,16 @@ namespace AZ
AddSubView();
}
m_refreshRate = Platform::GetRefreshRate();
//Assume 60hz if 0 is returned.
//Internal OSX displays have 'flexible' refresh rates, with a max of 60Hz - but report 0hz
if (m_refreshRate < 0.1f)
{
m_refreshRate = 60.0f;
}
m_drawables.resize(descriptor.m_dimensions.m_imageCount);
if (nativeDimensions)
{
*nativeDimensions = descriptor.m_dimensions;
}
AzFramework::WindowRequestBus::EventResult(
m_refreshRate, m_nativeWindow, &AzFramework::WindowRequestBus::Events::GetDisplayRefreshRate);
return RHI::ResultCode::Success;
}
@@ -160,7 +156,10 @@ namespace AZ
const uint32_t currentImageIndex = GetCurrentImageIndex();
//Preset the drawable
Platform::PresentInternal(m_mtlCommandBuffer, m_drawables[currentImageIndex], GetDescriptor().m_verticalSyncInterval, m_refreshRate);
Platform::PresentInternal(
m_mtlCommandBuffer,
m_drawables[currentImageIndex], GetDescriptor().m_verticalSyncInterval,
m_refreshRate);
[m_drawables[currentImageIndex] release];
m_drawables[currentImageIndex] = nil;
@@ -53,7 +53,7 @@ namespace AZ
id<MTLDevice> m_mtlDevice = nil;
NativeWindowType* m_nativeWindow = nullptr;
AZStd::vector<id<CAMetalDrawable>> m_drawables;
float m_refreshRate = 0.0f;
uint32_t m_refreshRate = 0;
};
}
}
@@ -117,6 +117,35 @@ namespace AZ
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::MultiSampleReadOnly2D)].m_sampleCountFlag = VK_SAMPLE_COUNT_4_BIT;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::MultiSampleReadOnly2D)].m_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)] = {};
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_name = "NULL_DESCRIPTOR_GENERAL_ARRAY_2D";
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_sampleCountFlag = VK_SAMPLE_COUNT_1_BIT;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_format = VK_FORMAT_R8G8B8A8_SRGB;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_usageFlagBits =VkImageUsageFlagBits(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_arrayLayers = 1;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_imageCreateFlagBits = VkImageCreateFlagBits(0);
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_layout = VK_IMAGE_LAYOUT_GENERAL;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralArray2D)].m_dimension = imageDimension;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)] = m_imageNullDescriptor.m_images[static_cast<uint32_t>(NullDescriptorManager::ImageTypes::GeneralArray2D)];
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_name = "NULL_DESCRIPTOR_READONLY_ARRAY_2D";
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_sampleCountFlag = VK_SAMPLE_COUNT_1_BIT;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_format = VK_FORMAT_R8G8B8A8_SRGB;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_usageFlagBits = VkImageUsageFlagBits(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT);
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_arrayLayers = 1;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_imageCreateFlagBits = VkImageCreateFlagBits(0);
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::ReadOnlyArray2D)].m_dimension = imageDimension;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)] = m_imageNullDescriptor.m_images[static_cast<uint32_t>(NullDescriptorManager::ImageTypes::General2D)];
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)].m_name = "NULL_DESCRIPTOR_STORAGE_ARRAY_2D";
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)].m_sampleCountFlag = VK_SAMPLE_COUNT_1_BIT;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)].m_format = VK_FORMAT_R32G32B32A32_UINT;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)].m_usageFlagBits = VkImageUsageFlagBits(VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT);
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)].m_arrayLayers = 1;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)].m_layout = VK_IMAGE_LAYOUT_GENERAL;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::StorageArray2D)].m_dimension = 256;
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralCube)] = m_imageNullDescriptor.m_images[static_cast<uint32_t>(NullDescriptorManager::ImageTypes::General2D)];
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralCube)].m_name = "NULL_DESCRIPTOR_GENERAL_CUBE";
m_imageNullDescriptor.m_images[static_cast<uint32_t>(ImageTypes::GeneralCube)].m_arrayLayers = 6;
@@ -243,6 +272,10 @@ namespace AZ
{
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_3D;
}
else if (imageIndex >= static_cast<uint32_t>(ImageTypes::GeneralArray2D) && imageIndex <= static_cast<uint32_t>(ImageTypes::StorageArray2D))
{
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
}
result = vkCreateImageView(device.GetNativeDevice(), &imageViewCreateInfo, nullptr, &m_imageNullDescriptor.m_images[imageIndex].m_view);
RETURN_RESULT_IF_UNSUCCESSFUL(ConvertResult(result));
@@ -366,7 +399,7 @@ namespace AZ
VkDescriptorImageInfo NullDescriptorManager::GetDescriptorImageInfo(RHI::ShaderInputImageType imageType, bool storageImage)
{
if (imageType == RHI::ShaderInputImageType::Image2D || imageType == RHI::ShaderInputImageType::Image2DArray)
if (imageType == RHI::ShaderInputImageType::Image2D)
{
if (storageImage)
{
@@ -377,6 +410,17 @@ namespace AZ
return GetImage(ImageTypes::ReadOnly2D);
}
}
else if (imageType == RHI::ShaderInputImageType::Image2DArray)
{
if (storageImage)
{
return GetImage(ImageTypes::StorageArray2D);
}
else
{
return GetImage(ImageTypes::ReadOnlyArray2D);
}
}
else if (imageType == RHI::ShaderInputImageType::Image2DMultisample)
{
if (storageImage)
@@ -30,6 +30,11 @@ namespace AZ
MultiSampleGeneral2D,
MultiSampleReadOnly2D,
// 2d image arrays
GeneralArray2D,
ReadOnlyArray2D,
StorageArray2D,
// cube images
GeneralCube,
ReadOnlyCube,
@@ -17,19 +17,6 @@
#include <AzCore/Console/IConsole.h>
#include <AzCore/Math/MathUtils.h>
void OnVsyncIntervalChanged(uint32_t const& interval)
{
AzFramework::WindowNotificationBus::Broadcast(
&AzFramework::WindowNotificationBus::Events::OnVsyncIntervalChanged,
AZ::GetClamp(interval, 0u, 4u));
}
// NOTE: On change, broadcasts the new requested vsync interval to all windows.
// The value of the vsync interval is constrained between 0 and 4
// Vsync intervals greater than 1 are not currently supported on the Vulkan RHI (see #2061 for discussion)
AZ_CVAR(uint32_t, rpi_vsync_interval, 1, OnVsyncIntervalChanged, AZ::ConsoleFunctorFlags::Null, "Set swapchain vsync interval");
namespace AZ
{
namespace RPI
@@ -158,9 +145,13 @@ namespace AZ
const RHI::WindowHandle windowHandle = RHI::WindowHandle(reinterpret_cast<uintptr_t>(m_windowHandle));
uint32_t syncInterval = 1;
AzFramework::WindowRequestBus::EventResult(
syncInterval, m_windowHandle, &AzFramework::WindowRequestBus::Events::GetSyncInterval);
RHI::SwapChainDescriptor descriptor;
descriptor.m_window = windowHandle;
descriptor.m_verticalSyncInterval = rpi_vsync_interval;
descriptor.m_verticalSyncInterval = syncInterval;
descriptor.m_dimensions.m_imageWidth = width;
descriptor.m_dimensions.m_imageHeight = height;
descriptor.m_dimensions.m_imageCount = 3;
@@ -121,6 +121,8 @@ namespace AtomToolsFramework
bool CanToggleFullScreenState() const override;
void ToggleFullScreenState() override;
float GetDpiScaleFactor() const override;
uint32_t GetSyncInterval() const override;
uint32_t GetDisplayRefreshRate() const;
protected:
// AzFramework::InputChannelEventListener ...
@@ -465,4 +465,14 @@ namespace AtomToolsFramework
{
return aznumeric_cast<float>(devicePixelRatioF());
}
uint32_t RenderViewportWidget::GetDisplayRefreshRate() const
{
return 60;
}
uint32_t RenderViewportWidget::GetSyncInterval() const
{
return 1;
}
} //namespace AtomToolsFramework
@@ -28,7 +28,7 @@ namespace EMStudio
setWindowTitle("Notification");
// window, no border, no focus, stays on top
setWindowFlags(Qt::Popup | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
setWindowFlags(Qt::Window | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus | Qt::WindowStaysOnTopHint);
// enable the translucent background
setAttribute(Qt::WA_TranslucentBackground);
@@ -90,6 +90,11 @@ namespace EditorPythonBindings
PythonSymbolEventBus::Handler::BusConnect();
EditorPythonBindingsNotificationBus::Handler::BusConnect();
AZ::Interface<AzToolsFramework::EditorPythonConsoleInterface>::Register(this);
if (PythonSymbolEventBus::GetTotalNumOfEventHandlers() > 1)
{
OnPostInitialize();
}
}
void PythonLogSymbolsComponent::Deactivate()
@@ -111,6 +116,7 @@ namespace EditorPythonBindings
m_basePath = pythonSymbolsPath;
}
EditorPythonBindingsNotificationBus::Handler::BusDisconnect();
PythonSymbolEventBus::ExecuteQueuedEvents();
}
void PythonLogSymbolsComponent::WriteMethod(AZ::IO::HandleType handle, AZStd::string_view methodName, const AZ::BehaviorMethod& behaviorMethod, const AZ::BehaviorClass* behaviorClass)
@@ -206,12 +212,12 @@ namespace EditorPythonBindings
AZ::IO::FileIOBase::GetInstance()->Write(handle, buffer.c_str(), buffer.size());
}
void PythonLogSymbolsComponent::LogClass(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass)
void PythonLogSymbolsComponent::LogClass(const AZStd::string moduleName, const AZ::BehaviorClass* behaviorClass)
{
LogClassWithName(moduleName, behaviorClass, behaviorClass->m_name.c_str());
}
void PythonLogSymbolsComponent::LogClassWithName(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass, AZStd::string_view className)
void PythonLogSymbolsComponent::LogClassWithName(const AZStd::string moduleName, const AZ::BehaviorClass* behaviorClass, const AZStd::string className)
{
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
if (fileHandle.IsValid())
@@ -255,7 +261,11 @@ namespace EditorPythonBindings
}
}
void PythonLogSymbolsComponent::LogClassMethod(AZStd::string_view moduleName, AZStd::string_view globalMethodName, AZ::BehaviorClass* behaviorClass, AZ::BehaviorMethod* behaviorMethod)
void PythonLogSymbolsComponent::LogClassMethod(
const AZStd::string moduleName,
const AZStd::string globalMethodName,
const AZ::BehaviorClass* behaviorClass,
const AZ::BehaviorMethod* behaviorMethod)
{
AZ_UNUSED(behaviorClass);
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
@@ -265,7 +275,7 @@ namespace EditorPythonBindings
}
}
void PythonLogSymbolsComponent::LogBus(AZStd::string_view moduleName, AZStd::string_view busName, AZ::BehaviorEBus* behaviorEBus)
void PythonLogSymbolsComponent::LogBus(const AZStd::string moduleName, const AZStd::string busName, const AZ::BehaviorEBus* behaviorEBus)
{
if (behaviorEBus->m_events.empty())
{
@@ -404,7 +414,7 @@ namespace EditorPythonBindings
}
}
void PythonLogSymbolsComponent::LogGlobalMethod(AZStd::string_view moduleName, AZStd::string_view methodName, AZ::BehaviorMethod* behaviorMethod)
void PythonLogSymbolsComponent::LogGlobalMethod(const AZStd::string moduleName, const AZStd::string methodName, const AZ::BehaviorMethod* behaviorMethod)
{
Internal::FileHandle fileHandle(OpenModuleAt(moduleName));
if (fileHandle.IsValid())
@@ -428,7 +438,10 @@ namespace EditorPythonBindings
}
}
void PythonLogSymbolsComponent::LogGlobalProperty(AZStd::string_view moduleName, AZStd::string_view propertyName, AZ::BehaviorProperty* behaviorProperty)
void PythonLogSymbolsComponent::LogGlobalProperty(
const AZStd::string moduleName,
const AZStd::string propertyName,
const AZ::BehaviorProperty* behaviorProperty)
{
if (!behaviorProperty->m_getter || !behaviorProperty->m_getter->GetResult())
{
@@ -51,12 +51,19 @@ namespace EditorPythonBindings
////////////////////////////////////////////////////////////////////////
// PythonSymbolEventBus::Handler
void LogClass(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass) override;
void LogClassWithName(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass, AZStd::string_view className) override;
void LogClassMethod(AZStd::string_view moduleName, AZStd::string_view globalMethodName, AZ::BehaviorClass* behaviorClass, AZ::BehaviorMethod* behaviorMethod) override;
void LogBus(AZStd::string_view moduleName, AZStd::string_view busName, AZ::BehaviorEBus* behaviorEBus) override;
void LogGlobalMethod(AZStd::string_view moduleName, AZStd::string_view methodName, AZ::BehaviorMethod* behaviorMethod) override;
void LogGlobalProperty(AZStd::string_view moduleName, AZStd::string_view propertyName, AZ::BehaviorProperty* behaviorProperty) override;
void LogClass(const AZStd::string moduleName, const AZ::BehaviorClass* behaviorClass) override;
void LogClassWithName(const AZStd::string moduleName, const AZ::BehaviorClass* behaviorClass, const AZStd::string className) override;
void LogClassMethod(
const AZStd::string moduleName,
const AZStd::string globalMethodName,
const AZ::BehaviorClass* behaviorClass,
const AZ::BehaviorMethod* behaviorMethod) override;
void LogBus(const AZStd::string moduleName, const AZStd::string busName, const AZ::BehaviorEBus* behaviorEBus) override;
void LogGlobalMethod(const AZStd::string moduleName, const AZStd::string methodName, const AZ::BehaviorMethod* behaviorMethod) override;
void LogGlobalProperty(
const AZStd::string moduleName,
const AZStd::string propertyName,
const AZ::BehaviorProperty* behaviorProperty) override;
void Finalize() override;
AZStd::string FetchPythonTypeName(const AZ::BehaviorParameter& param) override;
@@ -394,7 +394,7 @@ namespace EditorPythonBindings
// log the bus symbol
AZStd::string subModuleName = pybind11::cast<AZStd::string>(thisBusModule.attr("__name__"));
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogBus, subModuleName, ebusName, behaviorEBus);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogBus, subModuleName, ebusName, behaviorEBus);
}
}
@@ -756,7 +756,7 @@ namespace EditorPythonBindings
}
AZStd::string subModuleName = pybind11::cast<AZStd::string>(subModule.attr("__name__"));
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogClassMethod, subModuleName, globalMethodName, behaviorClass, behaviorMethod);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogClassMethod, subModuleName, globalMethodName, behaviorClass, behaviorMethod);
}
else
{
@@ -782,7 +782,7 @@ namespace EditorPythonBindings
pybind11::setattr(subModule, constantPropertyName.c_str(), constantValue);
AZStd::string subModuleName = pybind11::cast<AZStd::string>(subModule.attr("__name__"));
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogGlobalProperty, subModuleName, constantPropertyName, behaviorProperty);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogGlobalProperty, subModuleName, constantPropertyName, behaviorProperty);
}
}
@@ -809,11 +809,11 @@ namespace EditorPythonBindings
{
return ConstructPythonProxyObjectByTypename(behaviorClassName, pythonArgs);
});
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogClassWithName, subModuleName, behaviorClass, properSyntax);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogClassWithName, subModuleName, behaviorClass, properSyntax);
}
else
{
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogClass, subModuleName, behaviorClass);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogClass, subModuleName, behaviorClass);
}
}
}
@@ -153,7 +153,7 @@ namespace EditorPythonBindings
StaticPropertyHolderMapEntry& entry = iter->second;
entry.second->AddProperty(propertyName, behaviorProperty);
}
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogGlobalProperty, scopeName, propertyName, behaviorProperty);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogGlobalProperty, scopeName, propertyName, behaviorProperty);
}
pybind11::module DetermineScope(pybind11::module scope, const AZStd::string& fullName)
@@ -302,7 +302,7 @@ namespace EditorPythonBindings
// log global method symbol
AZStd::string subModuleName = pybind11::cast<AZStd::string>(targetModule.attr("__name__"));
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogGlobalMethod, subModuleName, methodName, behaviorMethod);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogGlobalMethod, subModuleName, methodName, behaviorMethod);
}
}
@@ -325,7 +325,7 @@ namespace EditorPythonBindings
// log global property symbol
AZStd::string subModuleName = pybind11::cast<AZStd::string>(globalsModule.attr("__name__"));
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::LogGlobalProperty, subModuleName, propertyName, behaviorProperty);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::LogGlobalProperty, subModuleName, propertyName, behaviorProperty);
if (behaviorProperty->m_getter && behaviorProperty->m_setter)
{
@@ -377,7 +377,7 @@ namespace EditorPythonBindings
PythonProxyBusManagement::CreateSubmodule(parentModule);
Internal::RegisterPaths(parentModule);
PythonSymbolEventBus::Broadcast(&PythonSymbolEventBus::Events::Finalize);
PythonSymbolEventBus::QueueBroadcast(&PythonSymbolEventBus::Events::Finalize);
}
}
}
@@ -9,6 +9,14 @@
#include <AzCore/EBus/EBus.h>
namespace AZ
{
class BehaviorClass;
class BehaviorMethod;
class BehaviorEBus;
class BehaviorProperty;
}
namespace EditorPythonBindings
{
//! An interface to track exported Python symbols
@@ -16,23 +24,39 @@ namespace EditorPythonBindings
: public AZ::EBusTraits
{
public:
// the symbols will be written out in the future
static const bool EnableEventQueue = true;
//! logs a behavior class type
virtual void LogClass(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass) = 0;
virtual void LogClass(const AZStd::string moduleName, const AZ::BehaviorClass* behaviorClass) = 0;
//! logs a behavior class type with an override to its name
virtual void LogClassWithName(AZStd::string_view moduleName, AZ::BehaviorClass* behaviorClass, AZStd::string_view className) = 0;
virtual void LogClassWithName(
const AZStd::string moduleName,
const AZ::BehaviorClass* behaviorClass,
const AZStd::string className) = 0;
//! logs a static class method with a specified global method name
virtual void LogClassMethod(AZStd::string_view moduleName, AZStd::string_view globalMethodName, AZ::BehaviorClass* behaviorClass, AZ::BehaviorMethod* behaviorMethod) = 0;
virtual void LogClassMethod(
const AZStd::string moduleName,
const AZStd::string globalMethodName,
const AZ::BehaviorClass* behaviorClass,
const AZ::BehaviorMethod* behaviorMethod) = 0;
//! logs a behavior bus with a specified bus name
virtual void LogBus(AZStd::string_view moduleName, AZStd::string_view busName, AZ::BehaviorEBus* behaviorEBus) = 0;
virtual void LogBus(const AZStd::string moduleName, const AZStd::string busName, const AZ::BehaviorEBus* behaviorEBus) = 0;
//! logs a global method from the behavior context registry with a specified method name
virtual void LogGlobalMethod(AZStd::string_view moduleName, AZStd::string_view methodName, AZ::BehaviorMethod* behaviorMethod) = 0;
virtual void LogGlobalMethod(
const AZStd::string moduleName,
const AZStd::string methodName,
const AZ::BehaviorMethod* behaviorMethod) = 0;
//! logs a global property, enum, or constant from the behavior context registry with a specified property name
virtual void LogGlobalProperty(AZStd::string_view moduleName, AZStd::string_view propertyName, AZ::BehaviorProperty* behaviorProperty) = 0;
virtual void LogGlobalProperty(
const AZStd::string moduleName,
const AZStd::string propertyName,
const AZ::BehaviorProperty* behaviorProperty) = 0;
//! signals the end of the logging of symbols
virtual void Finalize() = 0;
@@ -10,6 +10,7 @@
#include <EditorPythonBindings/EditorPythonBindingsBus.h>
#include <Source/PythonCommon.h>
#include <Source/PythonSymbolsBus.h>
#include <pybind11/pybind11.h>
#include <pybind11/embed.h>
#include <pybind11/eval.h>
@@ -25,6 +26,7 @@
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzCore/std/string/conversions.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/Utils/Utils.h>
@@ -39,7 +41,7 @@
namespace Platform
{
// Implemented in each different platform's implentation files, as it differs per platform.
// Implemented in each different platform's implementation files, as it differs per platform.
bool InsertPythonBinaryLibraryPaths(AZStd::unordered_set<AZStd::string>& paths, const char* pythonPackage, const char* engineRoot);
AZStd::string GetPythonHomePath(const char* pythonPackage, const char* engineRoot);
}
@@ -225,6 +227,37 @@ namespace RedirectOutput
namespace EditorPythonBindings
{
// A stand in bus to capture the log symbol queue events
// so that when/if the PythonLogSymbolsComponent becomes
// active it can write out the python symbols to disk
class PythonSystemComponent::SymbolLogHelper final
: public PythonSymbolEventBus::Handler
{
public:
SymbolLogHelper()
{
PythonSymbolEventBus::Handler::BusConnect();
}
~SymbolLogHelper()
{
PythonSymbolEventBus::ExecuteQueuedEvents();
PythonSymbolEventBus::Handler::BusDisconnect();
}
void LogClass(const AZStd::string, const AZ::BehaviorClass*) override {}
void LogClassWithName(const AZStd::string, const AZ::BehaviorClass*, const AZStd::string) override {}
void LogClassMethod(
const AZStd::string,
const AZStd::string,
const AZ::BehaviorClass*,
const AZ::BehaviorMethod*) override {}
void LogBus(const AZStd::string, const AZStd::string, const AZ::BehaviorEBus*) override {}
void LogGlobalMethod(const AZStd::string, const AZStd::string, const AZ::BehaviorMethod*) override {}
void LogGlobalProperty(const AZStd::string, const AZStd::string, const AZ::BehaviorProperty*) override {}
void Finalize() override {}
};
void PythonSystemComponent::Reflect(AZ::ReflectContext* context)
{
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
@@ -471,8 +504,6 @@ namespace EditorPythonBindings
}
}
bool PythonSystemComponent::StartPythonInterpreter(const PythonPathStack& pythonPathStack)
{
AZStd::unordered_set<AZStd::string> pyPackageSites(pythonPathStack.begin(), pythonPathStack.end());
@@ -520,6 +551,11 @@ namespace EditorPythonBindings
AZStd::lock_guard<decltype(m_lock)> lock(m_lock);
pybind11::gil_scoped_acquire acquire;
if (EditorPythonBindings::PythonSymbolEventBus::GetTotalNumOfEventHandlers() == 0)
{
m_symbolLogHelper = AZStd::make_shared<PythonSystemComponent::SymbolLogHelper>();
}
// print Python version using AZ logging
const int verRet = PyRun_SimpleStringFlags("import sys \nprint (sys.version) \n", nullptr);
AZ_Error("python", verRet == 0, "Error trying to fetch the version number in Python!");
@@ -59,10 +59,13 @@ namespace EditorPythonBindings
////////////////////////////////////////////////////////////////////////
private:
class SymbolLogHelper;
// handle multiple Python initializers and threads
AZStd::atomic_int m_initalizeWaiterCount {0};
AZStd::semaphore m_initalizeWaiter;
AZStd::recursive_mutex m_lock;
AZStd::shared_ptr<SymbolLogHelper> m_symbolLogHelper;
enum class Result
{
@@ -1482,7 +1482,7 @@ bool CUiAnimViewAnimNode::PasteNodesFromClipboard(QWidget* context)
const bool bLightAnimationSetActive = GetSequence()->GetFlags() & IUiAnimSequence::eSeqFlags_LightAnimationSet;
const unsigned int numNodes = animNodesRoot->getChildCount();
for (int i = 0; i < numNodes; ++i)
for (unsigned int i = 0; i < numNodes; ++i)
{
XmlNodeRef xmlNode = animNodesRoot->getChild(i);
+2 -2
View File
@@ -21,7 +21,7 @@
#include <QDragEnterEvent>
HierarchyWidget::HierarchyWidget(EditorWindow* editorWindow)
: QTreeWidget()
: AzQtComponents::StyledTreeWidget()
, m_isDeleting(false)
, m_editorWindow(editorWindow)
, m_entityItemMap()
@@ -391,7 +391,7 @@ void HierarchyWidget::startDrag(Qt::DropActions supportedActions)
// Remember the current selection so that we can revert back to it when the items are dragged back into the hierarchy
m_dragSelection = selectedItems();
QTreeView::startDrag(supportedActions);
AzQtComponents::StyledTreeWidget::startDrag(supportedActions);
}
void HierarchyWidget::dragEnterEvent(QDragEnterEvent* event)
+3 -1
View File
@@ -10,6 +10,8 @@
#if !defined(Q_MOC_RUN)
#include "EditorCommon.h"
#include <AzQtComponents/Components/Widgets/TreeView.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzToolsFramework/ToolsMessaging/EntityHighlightBus.h>
@@ -19,7 +21,7 @@
class QMimeData;
class HierarchyWidget
: public QTreeWidget
: public AzQtComponents::StyledTreeWidget
, private AzToolsFramework::EditorPickModeNotificationBus::Handler
, private AzToolsFramework::EntityHighlightMessages::Bus::Handler
{
@@ -28,4 +28,4 @@ namespace Multiplayer
}
}
AZ_DECLARE_MODULE_CLASS(Gem_Multiplayer_Imgui, Multiplayer::MultiplayerDebugModule);
AZ_DECLARE_MODULE_CLASS(Gem_Multiplayer_Debug, Multiplayer::MultiplayerDebugModule);
@@ -322,11 +322,9 @@ namespace ScriptCanvasEditor
return;
}
auto& variableOverrides = parseOutcome.GetValue();
if (!m_variableOverrides.IsEmpty())
{
variableOverrides.CopyPreviousOverriddenValues(m_variableOverrides);
parseOutcome.GetValue().CopyPreviousOverriddenValues(m_variableOverrides);
}
m_variableOverrides = parseOutcome.TakeValue();
@@ -351,8 +349,7 @@ namespace ScriptCanvasEditor
}
auto runtimeComponent = gameEntity->CreateComponent<ScriptCanvas::RuntimeComponent>();
auto runtimeOverrides = ConvertToRuntime(m_variableOverrides);
runtimeComponent->SetRuntimeDataOverrides(runtimeOverrides);
runtimeComponent->TakeRuntimeDataOverrides(ConvertToRuntime(m_variableOverrides));
}
void EditorScriptCanvasComponent::OnCatalogAssetAdded(const AZ::Data::AssetId& assetId)
@@ -518,8 +515,8 @@ namespace ScriptCanvasEditor
[[maybe_unused]] AZ::Entity* scriptCanvasEntity = assetData->GetScriptCanvasEntity();
AZ_Assert(scriptCanvasEntity, "This graph must have a valid entity");
BuildGameEntityData();
AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
UpdateName();
AzToolsFramework::ToolsApplicationNotificationBus::Broadcast(&AzToolsFramework::ToolsApplicationEvents::InvalidatePropertyDisplay, AzToolsFramework::Refresh_EntireTree_NewContent);
}
}
@@ -283,7 +283,7 @@ namespace ScriptCanvasEditor
loadResult.m_runtimeAsset.Get()->GetData().m_debugMap = luaAssetResult.m_debugMap;
loadResult.m_runtimeComponent = loadResult.m_entity->CreateComponent<ScriptCanvas::RuntimeComponent>();
CopyAssetEntityIdsToOverrides(runtimeDataOverrides);
loadResult.m_runtimeComponent->SetRuntimeDataOverrides(runtimeDataOverrides);
loadResult.m_runtimeComponent->TakeRuntimeDataOverrides(AZStd::move(runtimeDataOverrides));
Execution::Context::InitializeActivationData(loadResult.m_runtimeAsset->GetData());
Execution::InitializeInterpretedStatics(loadResult.m_runtimeAsset->GetData());
}
@@ -311,7 +311,7 @@ namespace ScriptCanvasEditor
{
if (AZStd::wildcard_match("*.scriptcanvas", fullSourceFileName))
{
return AzToolsFramework::AssetBrowser::SourceFileDetails("Icons/AssetBrowser/ScriptCanvas_16.png");
return AzToolsFramework::AssetBrowser::SourceFileDetails("Editor/Icons/AssetBrowser/ScriptCanvas_16.png");
}
// not one of our types.
@@ -80,12 +80,11 @@ namespace ScriptCanvasEditor
GraphCanvas::NodePaletteTreeItem* variablesRoot = root->CreateChildNode<LocalVariablesListNodePaletteTreeItem>("Variables");
root->RegisterCategoryNode(variablesRoot, "Variables");
// We always want to keep these around as place holders
GraphCanvas::NodePaletteTreeItem* customEventRoot = root->GetCategoryNode("Script Events");
customEventRoot->SetAllowPruneOnEmpty(false);
customEventRoot->SetAllowPruneOnEmpty(true);
GraphCanvas::NodePaletteTreeItem* globalFunctionRoot = root->GetCategoryNode("User Functions");
globalFunctionRoot->SetAllowPruneOnEmpty(false);
globalFunctionRoot->SetAllowPruneOnEmpty(true);
}
@@ -20,6 +20,7 @@
namespace AZ
{
class ReflectContext;
class DatumSerializer;
}
namespace ScriptCanvas
@@ -33,6 +34,8 @@ namespace ScriptCanvas
/// in the editor, regardless of their actual ScriptCanvas or BehaviorContext type.
class Datum final
{
friend class AZ::DatumSerializer;
public:
AZ_TYPE_INFO(Datum, "{8B836FC0-98A8-4A81-8651-35C7CA125451}");
AZ_CLASS_ALLOCATOR(Datum, AZ::SystemAllocator, 0);
@@ -509,7 +509,8 @@ namespace ScriptCanvas
bool SubgraphInterface::HasAnyFunctionality() const
{
return IsActiveDefaultObject() || HasPublicFunctionality();
// \todo restore default object addition when ndoes can define an variable, as well
return /*IsActiveDefaultObject() || */ HasPublicFunctionality();
}
bool SubgraphInterface::HasBranches() const
@@ -93,9 +93,9 @@ namespace ScriptCanvas
return m_runtimeOverrides;
}
void RuntimeComponent::SetRuntimeDataOverrides(const RuntimeDataOverrides& overrideData)
void RuntimeComponent::TakeRuntimeDataOverrides(RuntimeDataOverrides&& overrideData)
{
m_runtimeOverrides = overrideData;
m_runtimeOverrides = AZStd::move(overrideData);
m_runtimeOverrides.EnforcePreloadBehavior();
}
@@ -54,7 +54,7 @@ namespace ScriptCanvas
const RuntimeDataOverrides& GetRuntimeDataOverrides() const;
void SetRuntimeDataOverrides(const RuntimeDataOverrides& overrideData);
void TakeRuntimeDataOverrides(RuntimeDataOverrides&& overrideData);
protected:
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
@@ -10,17 +10,17 @@
Category="Nodeables"
GeneratePropertyFriend="True"
Namespace="ScriptCanvas"
Description="Repeats the output signal the given number of times using the specified delay to space the signals out">
Description="Repeats the output signal the given number of times using the specified delay to space the signals out.">
<!-- Input tag is for an execution input that has optional data (parameters) -->
<Input Name="Start" Description="">
<Parameter Name="Repetitions" Type="Data::NumberType" DefaultValue="0.0" Description="How many times to repeat."/>
<Parameter Name="Interval" Type="Data::NumberType" DefaultValue="0.0" Description="The Interval between repetitions."/>
<Parameter Name="Interval" Type="Data::NumberType" DefaultValue="0.0" Description="The Interval between repetitions. If zero, all repititions execute immediately, before On Start"/>
</Input>
<Output Name="Complete" Description="Signaled upon node exit"/>
<Output Name="Action" Description="Signaled every repeition"/>
<Output Name="Action" Description="Signaled every repetition"/>
<PropertyInterface Property="m_timeUnitsInterface" Name="Units" Type="Input" Description="Units to represent the time in."/>
@@ -0,0 +1,178 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Serialization/DatumSerializer.h>
using namespace ScriptCanvas;
namespace AZ
{
AZ_CLASS_ALLOCATOR_IMPL(DatumSerializer, SystemAllocator, 0);
JsonSerializationResult::Result DatumSerializer::Load
( void* outputValue
, [[maybe_unused]] const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context)
{
namespace JSR = JsonSerializationResult;
AZ_Assert(outputValueTypeId == azrtti_typeid<Datum>(), "DatumSerializer Load against output typeID that was not Datum");
AZ_Assert(outputValue, "DatumSerializer Load against null output");
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
auto outputDatum = reinterpret_cast<Datum*>(outputValue);
bool isOverloadedStorage = false;
AZ_Assert(azrtti_typeid<decltype(outputDatum->m_isOverloadedStorage)>() == azrtti_typeid<decltype(isOverloadedStorage)>()
, "overloaded storage type changed and won't load properly");
result.Combine(ContinueLoadingFromJsonObjectField
( &isOverloadedStorage
, azrtti_typeid<decltype(outputDatum->m_isOverloadedStorage)>()
, inputValue
, "isOverloadedStorage"
, context));
ScriptCanvas::Data::Type scType;
AZ_Assert(azrtti_typeid<decltype(outputDatum->m_type)>() == azrtti_typeid<decltype(scType)>()
, "ScriptCanvas::Data::Type type changed and won't load properly");
result.Combine(ContinueLoadingFromJsonObjectField
( &scType
, azrtti_typeid<decltype(outputDatum->m_type)>()
, inputValue
, "scriptCanvasType"
, context));
AZStd::any storage;
{ // datum storage begin
AZ::Uuid typeId = AZ::Uuid::CreateNull();
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeIdMember == inputValue.MemberEnd())
{
return context.Report
( JSR::Tasks::ReadField
, JSR::Outcomes::Missing
, AZStd::string::format("DatumSerializer::Load failed to load the %s member"
, JsonSerialization::TypeIdFieldIdentifier));
}
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
if (typeId.IsNull())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic
, "DatumSerializer::Load failed to load the AZ TypeId of the value");
}
storage = context.GetSerializeContext()->CreateAny(typeId);
if (storage.empty() || storage.type() != typeId)
{
return context.Report(result, "DatumSerializer::Load failed to load a value matched the reported AZ TypeId. "
"The C++ declaration may have been deleted or changed.");
}
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&storage), typeId, inputValue, "value", context));
} // datum storage end
AZStd::string label;
AZ_Assert(azrtti_typeid<decltype(outputDatum->m_datumLabel)>() == azrtti_typeid<decltype(label)>()
, "m_datumLabel type changed and won't load properly");
result.Combine(ContinueLoadingFromJsonObjectField
( &label
, azrtti_typeid<decltype(outputDatum->m_datumLabel)>()
, inputValue
, "label"
, context));
Datum copy(scType, Datum::eOriginality::Original, AZStd::any_cast<void>(&storage), scType.GetAZType());
copy.SetLabel(label);
*outputDatum = copy;
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "DatumSerializer Load finished loading Datum"
: "DatumSerializer Load failed to load Datum");
}
JsonSerializationResult::Result DatumSerializer::Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, [[maybe_unused]] const Uuid& valueTypeId
, JsonSerializerContext& context)
{
namespace JSR = JsonSerializationResult;
AZ_Assert(valueTypeId == azrtti_typeid<Datum>(), "DatumSerializer Store against value typeID that was not Datum");
AZ_Assert(inputValue, "DatumSerializer Store against null inputValue pointer ");
auto inputScriptDataPtr = reinterpret_cast<const Datum*>(inputValue);
auto defaultScriptDataPtr = reinterpret_cast<const Datum*>(defaultValue);
if (defaultScriptDataPtr)
{
if (*inputScriptDataPtr == *defaultScriptDataPtr)
{
return context.Report
( JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "DatumSerializer Store used defaults for Datum");
}
}
JSR::ResultCode result(JSR::Tasks::WriteValue);
outputValue.SetObject();
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "isOverloadedStorage"
, &inputScriptDataPtr->m_isOverloadedStorage
, defaultScriptDataPtr ? &defaultScriptDataPtr->m_isOverloadedStorage : nullptr
, azrtti_typeid<decltype(inputScriptDataPtr->m_isOverloadedStorage)>()
, context));
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "scriptCanvasType"
, &inputScriptDataPtr->GetType()
, defaultScriptDataPtr ? &defaultScriptDataPtr->GetType() : nullptr
, azrtti_typeid<decltype(inputScriptDataPtr->GetType())>()
, context));
{ // datum storage begin
{
rapidjson::Value typeValue;
result.Combine(StoreTypeId(typeValue, inputScriptDataPtr->GetType().GetAZType(), context));
outputValue.AddMember
( rapidjson::StringRef(JsonSerialization::TypeIdFieldIdentifier)
, AZStd::move(typeValue)
, context.GetJsonAllocator());
}
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "value"
, inputScriptDataPtr->GetAsDanger()
, defaultScriptDataPtr ? defaultScriptDataPtr->GetAsDanger() : nullptr
, inputScriptDataPtr->GetType().GetAZType()
, context));
} // datum storage end
result.Combine(ContinueStoringToJsonObjectField
( outputValue
, "label"
, &inputScriptDataPtr->m_datumLabel
, defaultScriptDataPtr ? &defaultScriptDataPtr->m_datumLabel : nullptr
, azrtti_typeid<decltype(inputScriptDataPtr->m_datumLabel)>()
, context));
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "DatumSerializer Store finished saving Datum"
: "DatumSerializer Store failed to save Datum");
}
}
@@ -14,11 +14,11 @@
namespace AZ
{
class ScriptUserDataSerializer
class DatumSerializer
: public BaseJsonSerializer
{
public:
AZ_RTTI(ScriptUserDataSerializer, "{7E5FC193-8CDB-4251-A68B-F337027381DF}", BaseJsonSerializer);
AZ_RTTI(DatumSerializer, "{FBEBF833-465F-49F4-AFB1-CC9D3B25C16C}", BaseJsonSerializer);
AZ_CLASS_ALLOCATOR_DECL;
private:
@@ -8,15 +8,15 @@
#include <AzCore/Serialization/Json/JsonSerialization.h>
#include <ScriptCanvas/Asset/RuntimeAsset.h>
#include <ScriptCanvas/Serialization/ScriptUserDataSerializer.h>
#include <ScriptCanvas/Serialization/RuntimeVariableSerializer.h>
using namespace ScriptCanvas;
namespace AZ
{
AZ_CLASS_ALLOCATOR_IMPL(ScriptUserDataSerializer, SystemAllocator, 0);
AZ_CLASS_ALLOCATOR_IMPL(RuntimeVariableSerializer, SystemAllocator, 0);
JsonSerializationResult::Result ScriptUserDataSerializer::Load
JsonSerializationResult::Result RuntimeVariableSerializer::Load
( void* outputValue
, [[maybe_unused]] const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
@@ -24,8 +24,8 @@ namespace AZ
{
namespace JSR = JsonSerializationResult;
AZ_Assert(outputValueTypeId == azrtti_typeid<RuntimeVariable>(), "ScriptUserDataSerializer Load against output typeID that was not RuntimeVariable");
AZ_Assert(outputValue, "ScriptUserDataSerializer Load against null output");
AZ_Assert(outputValueTypeId == azrtti_typeid<RuntimeVariable>(), "RuntimeVariableSerializer Load against output typeID that was not RuntimeVariable");
AZ_Assert(outputValue, "RuntimeVariableSerializer Load against null output");
auto outputVariable = reinterpret_cast<RuntimeVariable*>(outputValue);
JsonSerializationResult::ResultCode result(JSR::Tasks::ReadField);
@@ -34,28 +34,28 @@ namespace AZ
auto typeIdMember = inputValue.FindMember(JsonSerialization::TypeIdFieldIdentifier);
if (typeIdMember == inputValue.MemberEnd())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, AZStd::string::format("ScriptUserDataSerializer::Load failed to load the %s member", JsonSerialization::TypeIdFieldIdentifier));
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Missing, AZStd::string::format("RuntimeVariableSerializer::Load failed to load the %s member", JsonSerialization::TypeIdFieldIdentifier));
}
result.Combine(LoadTypeId(typeId, typeIdMember->value, context));
if (typeId.IsNull())
{
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "ScriptUserDataSerializer::Load failed to load the AZ TypeId of the value");
return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Catastrophic, "RuntimeVariableSerializer::Load failed to load the AZ TypeId of the value");
}
outputVariable->value = context.GetSerializeContext()->CreateAny(typeId);
if (outputVariable->value.empty() || outputVariable->value.type() != typeId)
{
return context.Report(result, "ScriptUserDataSerializer::Load failed to load a value matched the reported AZ TypeId. The C++ declaration may have been deleted or changed.");
return context.Report(result, "RuntimeVariableSerializer::Load failed to load a value matched the reported AZ TypeId. The C++ declaration may have been deleted or changed.");
}
result.Combine(ContinueLoadingFromJsonObjectField(AZStd::any_cast<void>(&outputVariable->value), typeId, inputValue, "value", context));
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "ScriptUserDataSerializer Load finished loading RuntimeVariable"
: "ScriptUserDataSerializer Load failed to load RuntimeVariable");
? "RuntimeVariableSerializer Load finished loading RuntimeVariable"
: "RuntimeVariableSerializer Load failed to load RuntimeVariable");
}
JsonSerializationResult::Result ScriptUserDataSerializer::Store
JsonSerializationResult::Result RuntimeVariableSerializer::Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
@@ -79,7 +79,7 @@ namespace AZ
if (inputDatum == defaultDatum)
{
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "ScriptUserDataSerializer Store used defaults for RuntimeVariable");
return context.Report(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed, "RuntimeVariableSerializer Store used defaults for RuntimeVariable");
}
}
@@ -95,8 +95,8 @@ namespace AZ
result.Combine(ContinueStoringToJsonObjectField(outputValue, "value", AZStd::any_cast<void>(inputAnyPtr), AZStd::any_cast<void>(defaultAnyPtr), inputAnyPtr->type(), context));
return context.Report(result, result.GetProcessing() != JSR::Processing::Halted
? "ScriptUserDataSerializer Store finished saving RuntimeVariable"
: "ScriptUserDataSerializer Store failed to save RuntimeVariable");
? "RuntimeVariableSerializer Store finished saving RuntimeVariable"
: "RuntimeVariableSerializer Store failed to save RuntimeVariable");
}
}
@@ -0,0 +1,37 @@
/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <AzCore/Memory/Memory.h>
#include <AzCore/Serialization/Json/BaseJsonSerializer.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AZ
{
class RuntimeVariableSerializer
: public BaseJsonSerializer
{
public:
AZ_RTTI(RuntimeVariableSerializer, "{7E5FC193-8CDB-4251-A68B-F337027381DF}", BaseJsonSerializer);
AZ_CLASS_ALLOCATOR_DECL;
private:
JsonSerializationResult::Result Load
( void* outputValue
, const Uuid& outputValueTypeId
, const rapidjson::Value& inputValue
, JsonDeserializerContext& context) override;
JsonSerializationResult::Result Store
( rapidjson::Value& outputValue
, const void* inputValue
, const void* defaultValue
, const Uuid& valueTypeId, JsonSerializerContext& context) override;
};
}
@@ -23,7 +23,8 @@
#include <ScriptCanvas/Execution/ExecutionPerformanceTimer.h>
#include <ScriptCanvas/Execution/Interpreted/ExecutionInterpretedAPI.h>
#include <ScriptCanvas/Execution/RuntimeComponent.h>
#include <ScriptCanvas/Serialization/ScriptUserDataSerializer.h>
#include <ScriptCanvas/Serialization/RuntimeVariableSerializer.h>
#include <ScriptCanvas/Serialization/DatumSerializer.h>
#include <ScriptCanvas/SystemComponent.h>
#include <ScriptCanvas/Variable/GraphVariableManagerComponent.h>
@@ -87,8 +88,13 @@ namespace ScriptCanvas
if (AZ::JsonRegistrationContext* jsonContext = azrtti_cast<AZ::JsonRegistrationContext*>(context))
{
jsonContext->Serializer<AZ::ScriptUserDataSerializer>()
->HandlesType<RuntimeVariable>();
jsonContext->Serializer<AZ::RuntimeVariableSerializer>()
->HandlesType<RuntimeVariable>()
;
jsonContext->Serializer<AZ::DatumSerializer>()
->HandlesType<Datum>()
;
}
#if defined(SC_EXECUTION_TRACE_ENABLED)
@@ -539,8 +539,10 @@ set(FILES
Include/ScriptCanvas/Profiler/Aggregator.cpp
Include/ScriptCanvas/Profiler/DrillerEvents.h
Include/ScriptCanvas/Profiler/DrillerEvents.cpp
Include/ScriptCanvas/Serialization/ScriptUserDataSerializer.h
Include/ScriptCanvas/Serialization/ScriptUserDataSerializer.cpp
Include/ScriptCanvas/Serialization/DatumSerializer.h
Include/ScriptCanvas/Serialization/DatumSerializer.cpp
Include/ScriptCanvas/Serialization/RuntimeVariableSerializer.h
Include/ScriptCanvas/Serialization/RuntimeVariableSerializer.cpp
Include/ScriptCanvas/Data/DataTrait.cpp
Include/ScriptCanvas/Data/DataTrait.h
Include/ScriptCanvas/Data/PropertyTraits.cpp
@@ -89,7 +89,7 @@
"CONFIGURATION": "profile",
"SCRIPT_PATH": "scripts/build/TestImpactAnalysis/tiaf_driver.py",
"SCRIPT_PARAMETERS":
"--config=\"!OUTPUT_DIRECTORY!/bin/TestImpactFramework/profile/Persistent/tiaf.json\" --src-branch=!BRANCH_NAME! --dst-branch=!CHANGE_TARGET! --commit=!CHANGE_ID! --s3-bucket=!TEST_IMPACT_S3_BUCKET! --mars-index-prefix=jonawals --suite=main --test-failure-policy=continue"
"--config=\"!OUTPUT_DIRECTORY!/bin/TestImpactFramework/profile/Persistent/tiaf.json\" --src-branch=!BRANCH_NAME! --dst-branch=!CHANGE_TARGET! --commit=!CHANGE_ID! --s3-bucket=!TEST_IMPACT_S3_BUCKET! --mars-index-prefix=jonawals --s3-top-level-dir=!REPOSITORY_NAME! --build-number=!BUILD_NUMBER! --suite=main --test-failure-policy=continue"
}
},
"debug_vs2019": {
@@ -14,6 +14,7 @@ import pathlib
class Repo:
def __init__(self, repo_path: str):
self._repo = git.Repo(repo_path)
self._remote_url = self._repo.remotes[0].config_reader.get("url")
# Returns the current branch
@property
@@ -21,6 +22,11 @@ class Repo:
branch = self._repo.active_branch
return branch.name
# Returns the remote URL
@property
def remote_url(self):
return self._remote_url
def create_diff_file(self, src_commit_hash: str, dst_commit_hash: str, output_path: pathlib.Path, multi_branch: bool):
"""
Attempts to create a diff from the src and dst commits and write to the specified output file.
@@ -14,6 +14,7 @@ from tiaf_logger import get_logger
logger = get_logger(__file__)
MARS_JOB_KEY = "job"
BUILD_NUMBER_KEY = "build_number"
SRC_COMMIT_KEY = "src_commit"
DST_COMMIT_KEY = "dst_commit"
COMMIT_DISTANCE_KEY = "commit_distance"
@@ -175,12 +176,14 @@ def get_duration_in_seconds(duration_in_milliseconds: int):
return duration_in_milliseconds * 0.001
def generate_mars_job(tiaf_result, driver_args):
def generate_mars_job(tiaf_result, driver_args, build_number: int):
"""
Generates a MARS job document using the job meta-data used to drive the TIAF sequence.
@param tiaf_result: The result object generated by the TIAF script.
@param driver_args: The arguments specified to the driver script.
@param tiaf_result: The result object generated by the TIAF script.
@param driver_args: The arguments specified to the driver script.
@param driver_args: The arguments specified to the driver script.
@param build_number: The build number this job corresponds to.
@return: The MARS job document with the job meta-data.
"""
@@ -203,6 +206,7 @@ def generate_mars_job(tiaf_result, driver_args):
]}
mars_job[DRIVER_ARGS_KEY] = driver_args
mars_job[BUILD_NUMBER_KEY] = build_number
return mars_job
def generate_test_run_list(test_runs):
@@ -418,7 +422,7 @@ def generate_mars_test_targets(sequence_report: dict, mars_job: dict, t0_timesta
return mars_test_targets
def transmit_report_to_mars(mars_index_prefix: str, tiaf_result: dict, driver_args: list):
def transmit_report_to_mars(mars_index_prefix: str, tiaf_result: dict, driver_args: list, build_number: int):
"""
Transforms the TIAF result into the appropriate MARS documents and transmits them to MARS.
@@ -434,7 +438,7 @@ def transmit_report_to_mars(mars_index_prefix: str, tiaf_result: dict, driver_ar
t0_timestamp = datetime.datetime.now().timestamp()
# Generate and transmit the MARS job document
mars_job = generate_mars_job(tiaf_result, driver_args)
mars_job = generate_mars_job(tiaf_result, driver_args, build_number)
filebeat.send_event(mars_job, f"{mars_index_prefix}.tiaf.job")
if tiaf_result[REPORT_KEY]:
+12 -5
View File
@@ -161,7 +161,7 @@ class TestImpact:
result["change_list"] = self._change_list
return result
def run(self, commit: str, src_branch: str, dst_branch: str, s3_bucket: str, suite: str, test_failure_policy: str, safe_mode: bool, test_timeout: int, global_timeout: int):
def run(self, commit: str, src_branch: str, dst_branch: str, s3_bucket: str, s3_top_level_dir: str, suite: str, test_failure_policy: str, safe_mode: bool, test_timeout: int, global_timeout: int):
"""
Determins the type of sequence to run based on the commit, source branch and test branch before running the
sequence with the specified values.
@@ -170,6 +170,7 @@ class TestImpact:
@param src_branch: If not equal to dst_branch, the branch that is being built.
@param dst_branch: If not equal to src_branch, the destination branch for the PR being built.
@param s3_bucket: Location of S3 bucket to use for persistent storage, otherwise local disk storage will be used.
@param s3_top_level_dir: Top level directory to use in the S3 bucket.
@param suite: Test suite to run.
@param test_failure_policy: Test failure policy for regular and test impact sequences (ignored when seeding).
@param safe_mode: Flag to run impact analysis tests in safe mode (ignored when seeding).
@@ -218,7 +219,7 @@ class TestImpact:
try:
# Persistent storage location
if s3_bucket:
persistent_storage = PersistentStorageS3(self._config, suite, s3_bucket, self._source_of_truth_branch)
persistent_storage = PersistentStorageS3(self._config, suite, s3_bucket, s3_top_level_dir, self._source_of_truth_branch)
else:
persistent_storage = PersistentStorageLocal(self._config, suite)
except SystemError as e:
@@ -226,14 +227,20 @@ class TestImpact:
persistent_storage = None
if persistent_storage:
# Flag to signify whether or not this is a re-run (multiple runs of the same commit)
# Right now, we don't fully support re-runs but in the future we will have an extra subfolder for each commit hash with the
# last run hash that was used for the first run for the commit so we can retreive the same reference point for building the
# change list to ensure each subsequent run is using the same data but for the time being, just perform a regular run
is_rerun = False
if persistent_storage.has_historic_data:
logger.info("Historic data found.")
self._src_commit = persistent_storage.last_commit_hash
# Perform some basic sanity checks on the commit hashes to ensure confidence in the integrity of of the environment
# Perform some basic sanity checks on the commit hashes to ensure confidence in the integrity of the environment
if self._src_commit == self._dst_commit:
logger.error(f"Source commit '{self._src_commit}' and destination commit '{self._dst_commit}', implying the integrity of the historic data is compromised.")
logger.info(f"Source commit '{self._src_commit}' and destination commit '{self._dst_commit}', implying this is a re-run. A regular sequence will instead be performed.")
persistent_storage = None
is_rerun = True
else:
self._attempt_to_generate_change_list()
else:
@@ -261,7 +268,7 @@ class TestImpact:
args.append(f"--changelist={self._change_list_path}")
logger.info(f"Change list is set to '{self._change_list_path}'.")
else:
if self._is_source_of_truth_branch:
if self._is_source_of_truth_branch and not is_rerun:
# Use seed sequence (instrumented all tests) for coverage updating branches so we can generate the coverage bed for future sequences
sequence_type = "seed"
# We always continue after test failures when seeding to ensure we capture the coverage for all test targets
@@ -11,6 +11,7 @@ import mars_utils
import sys
import pathlib
import traceback
import re
from tiaf import TestImpact
from tiaf_logger import get_logger
@@ -66,13 +67,20 @@ def parse_args():
required=True
)
# S3 bucket
# S3 bucket name
parser.add_argument(
'--s3-bucket',
help="Location of S3 bucket to use for persistent storage, otherwise local disk storage will be used",
required=False
)
# S3 bucket top level directory
parser.add_argument(
'--s3-top-level-dir',
help="The top level directory to use in the S3 bucket",
required=False
)
# MARS index prefix
parser.add_argument(
'--mars-index-prefix',
@@ -80,6 +88,13 @@ def parse_args():
required=False
)
# Build number
parser.add_argument(
'--build-number',
help="The build number this run of TIAF corresponds to",
required=True
)
# Test suite
parser.add_argument(
'--suite',
@@ -127,12 +142,19 @@ if __name__ == "__main__":
try:
args = parse_args()
s3_top_level_dir = None
if args.s3_top_level_dir:
s3_top_level_dir = args.s3_top_level_dir
else:
s3_top_level_dir = "tiaf"
tiaf = TestImpact(args.config)
tiaf_result = tiaf.run(args.commit, args.src_branch, args.dst_branch, args.s3_bucket, args.suite, args.test_failure_policy, args.safe_mode, args.test_timeout, args.global_timeout)
tiaf_result = tiaf.run(args.commit, args.src_branch, args.dst_branch, args.s3_bucket, s3_top_level_dir, args.suite, args.test_failure_policy, args.safe_mode, args.test_timeout, args.global_timeout)
if args.mars_index_prefix:
logger.info("Transmitting report to MARS...")
mars_utils.transmit_report_to_mars(args.mars_index_prefix, tiaf_result, sys.argv)
mars_utils.transmit_report_to_mars(args.mars_index_prefix, tiaf_result, sys.argv, args.build_number)
logger.info("Complete!")
# Non-gating will be removed from this script and handled at the job level in SPEC-7413
@@ -106,7 +106,7 @@ class PersistentStorage(ABC):
historic_data_json = self._pack_historic_data(last_commit_hash)
if historic_data_json:
logger.info(f"Attempting to store historic data with new last commit hash '{self._last_commit_hash}'...")
logger.info(f"Attempting to store historic data with new last commit hash '{last_commit_hash}'...")
self._store_historic_data(historic_data_json)
logger.info("The historic data was successfully stored.")
@@ -18,7 +18,7 @@ logger = get_logger(__file__)
# Implementation of s3 bucket persistent storage
class PersistentStorageS3(PersistentStorage):
def __init__(self, config: dict, suite: str, s3_bucket: str, branch: str):
def __init__(self, config: dict, suite: str, s3_bucket: str, root_dir: str, branch: str):
"""
Initializes the persistent storage with the specified s3 bucket.
@@ -36,8 +36,8 @@ class PersistentStorageS3(PersistentStorage):
# historic_data.json.zip is the file containing the coverage and meta-data of the last TIAF sequence run
historic_data_file = f"historic_data.{object_extension}"
# The location of the data is in the form <branch>/<config> so the build config of each branch gets its own historic data
self._dir = f'{branch}/{config["meta"]["build_config"]}'
# The location of the data is in the form <root_dir>/<branch>/<config> so the build config of each branch gets its own historic data
self._dir = f'{root_dir}/{branch}/{config["meta"]["build_config"]}'
self._historic_data_key = f'{self._dir}/{historic_data_file}'
logger.info(f"Attempting to retrieve historic data for branch '{branch}' at location '{self._historic_data_key}' on bucket '{s3_bucket}'...")