- class TreeItemDataIterator
- {
- public:
- typedef T Type;
- typedef TreeItemIterator InternalIterator;
-
- //iterator traits, required by STL
- typedef ptrdiff_t difference_type;
- typedef Type* value_type;
- typedef Type** pointer;
- typedef Type*& reference;
- typedef std::forward_iterator_tag iterator_category;
-
- TreeItemDataIterator() {}
- TreeItemDataIterator(const TreeItemDataIterator& other)
- : iterator(other.iterator) {AdvanceToValidIterator(); }
- explicit TreeItemDataIterator(const InternalIterator& iterator)
- : iterator(iterator) {AdvanceToValidIterator(); }
-
- Type* operator*() {return reinterpret_cast(iterator.pCtrl->GetItemData(iterator.hItem)); }
- bool operator==(const TreeItemDataIterator& other) const {return iterator == other.iterator; }
- bool operator!=(const TreeItemDataIterator& other) const {return iterator != other.iterator; }
-
- HTREEITEM GetTreeItem() {return iterator.hItem; }
-
- TreeItemDataIterator& operator++()
- {
- ++iterator;
- AdvanceToValidIterator();
- return *this;
- }
-
- TreeItemDataIterator operator++(int) {TreeItemDataIterator old = *this; ++(*this); return old; }
-
- private:
- void AdvanceToValidIterator()
- {
- while (iterator.pCtrl && iterator.hItem && !iterator.pCtrl->GetItemData(iterator.hItem))
- {
- ++iterator;
- }
- }
-
- InternalIterator iterator;
- };
-
- template
- class RecursiveItemDataIteratorType
- {
- public: typedef TreeItemDataIterator type;
- };
- template
- inline TreeItemDataIterator BeginTreeItemDataRecursive(CTreeCtrl* pCtrl, HTREEITEM hItem = 0)
- {
- return TreeItemDataIterator(BeginTreeItemsRecursive(pCtrl, hItem));
- }
-
- template
- inline TreeItemDataIterator EndTreeItemDataRecursive(CTreeCtrl* pCtrl, HTREEITEM hItem = 0)
- {
- return TreeItemDataIterator(EndTreeItemsRecursive(pCtrl, hItem));
- }
-
- template
- class NonRecursiveItemDataIteratorType
- {
- typedef TreeItemDataIterator type;
- };
- template
- inline TreeItemDataIterator BeginTreeItemDataNonRecursive(CTreeCtrl* pCtrl, HTREEITEM hItem = 0)
- {
- return TreeItemDataIterator(BeginTreeItemsNonRecursive(pCtrl, hItem));
- }
-
- template
- inline TreeItemDataIterator EndTreeItemDataNonRecursive(CTreeCtrl* pCtrl, HTREEITEM hItem = 0)
- {
- return TreeItemDataIterator(EndTreeItemsNonRecursive(pCtrl, hItem));
- }
-
- class SelectedTreeItemIterator
- {
- public:
- SelectedTreeItemIterator()
- : pCtrl(0)
- , hItem(0) {}
- SelectedTreeItemIterator(const SelectedTreeItemIterator& other)
- : pCtrl(other.pCtrl)
- , hItem(other.hItem) {}
- SelectedTreeItemIterator(CXTTreeCtrl* pCtrl, HTREEITEM hItem)
- : pCtrl(pCtrl)
- , hItem(hItem) {}
-
- HTREEITEM operator*() {return hItem; }
- bool operator==(const SelectedTreeItemIterator& other) const {return pCtrl == other.pCtrl && hItem == other.hItem; }
- bool operator!=(const SelectedTreeItemIterator& other) const {return pCtrl != other.pCtrl || hItem != other.hItem; }
-
- SelectedTreeItemIterator& operator++()
- {
- hItem = (pCtrl ? pCtrl->GetNextSelectedItem(hItem) : 0);
-
- return *this;
- }
-
- SelectedTreeItemIterator operator++(int) {SelectedTreeItemIterator old = *this; ++(*this); return old; }
-
- CXTTreeCtrl* pCtrl;
- HTREEITEM hItem;
- };
-
- SelectedTreeItemIterator BeginSelectedTreeItems(CXTTreeCtrl* pCtrl)
- {
- return SelectedTreeItemIterator(pCtrl, (pCtrl ? pCtrl->GetFirstSelectedItem() : 0));
- }
-
- SelectedTreeItemIterator EndSelectedTreeItems(CXTTreeCtrl* pCtrl)
- {
- return SelectedTreeItemIterator(pCtrl, 0);
- }
-
- template
- class SelectedTreeItemDataIterator
- {
- public:
- typedef T Type;
- typedef SelectedTreeItemIterator InternalIterator;
-
- SelectedTreeItemDataIterator() {}
- SelectedTreeItemDataIterator(const SelectedTreeItemDataIterator& other)
- : iterator(other.iterator) {AdvanceToValidIterator(); }
- explicit SelectedTreeItemDataIterator(const InternalIterator& iterator)
- : iterator(iterator) {AdvanceToValidIterator(); }
-
- Type* operator*() {return reinterpret_cast(iterator.pCtrl->GetItemData(iterator.hItem)); }
- bool operator==(const SelectedTreeItemDataIterator& other) const {return iterator == other.iterator; }
- bool operator!=(const SelectedTreeItemDataIterator& other) const {return iterator != other.iterator; }
-
- HTREEITEM GetTreeItem() {return iterator.hItem; }
-
- SelectedTreeItemDataIterator& operator++()
- {
- ++iterator;
- AdvanceToValidIterator();
- return *this;
- }
-
- SelectedTreeItemDataIterator operator++(int) {SelectedTreeItemDataIterator old = *this; ++(*this); return old; }
-
- private:
- void AdvanceToValidIterator()
- {
- while (iterator.pCtrl && iterator.hItem && !iterator.pCtrl->GetItemData(iterator.hItem))
- {
- ++iterator;
- }
- }
-
- InternalIterator iterator;
- };
-
- template
- SelectedTreeItemDataIterator BeginSelectedTreeItemData(CXTTreeCtrl* pCtrl)
- {
- return SelectedTreeItemDataIterator(BeginSelectedTreeItems(pCtrl));
- }
-
- template
- SelectedTreeItemDataIterator EndSelectedTreeItemData(CXTTreeCtrl* pCtrl)
- {
- return SelectedTreeItemDataIterator(EndSelectedTreeItems(pCtrl));
- }
-}
-
-#endif // CRYINCLUDE_EDITOR_CONTROLS_TREECTRLUTILS_H
diff --git a/Code/Editor/Core/LevelEditorMenuHandler.cpp b/Code/Editor/Core/LevelEditorMenuHandler.cpp
index a90b0a597a..05f06c87aa 100644
--- a/Code/Editor/Core/LevelEditorMenuHandler.cpp
+++ b/Code/Editor/Core/LevelEditorMenuHandler.cpp
@@ -104,6 +104,11 @@ namespace
}
}
+ // Currently (December 13, 2021), this function is only used by slice editor code.
+ // When the slice editor is not enabled, there are no references to the
+ // HideActionWhileEntitiesDeselected function, causing a compiler warning and
+ // subsequently a build error.
+#ifdef ENABLE_SLICE_EDITOR
void HideActionWhileEntitiesDeselected(QAction* action, EEditorNotifyEvent editorNotifyEvent)
{
if (action == nullptr)
@@ -127,6 +132,7 @@ namespace
break;
}
}
+#endif
void DisableActionWhileInSimMode(QAction* action, EEditorNotifyEvent editorNotifyEvent)
{
@@ -374,7 +380,6 @@ QMenu* LevelEditorMenuHandler::CreateFileMenu()
{
DisableActionWhileLevelChanges(fileOpenSlice, e);
}));
-#endif
// Save Selected Slice
auto saveSelectedSlice = fileMenu.AddAction(ID_FILE_SAVE_SELECTED_SLICE);
@@ -391,7 +396,7 @@ QMenu* LevelEditorMenuHandler::CreateFileMenu()
{
HideActionWhileEntitiesDeselected(saveSliceToRoot, e);
}));
-
+#endif
// Open Recent
m_mostRecentLevelsMenu = fileMenu.AddMenu(tr("Open Recent"));
connect(m_mostRecentLevelsMenu, &QMenu::aboutToShow, this, &LevelEditorMenuHandler::UpdateMRUFiles);
@@ -439,9 +444,10 @@ QMenu* LevelEditorMenuHandler::CreateFileMenu()
// Show Log File
fileMenu.AddAction(ID_FILE_EDITLOGFILE);
+#ifdef ENABLE_SLICE_EDITOR
fileMenu.AddSeparator();
-
fileMenu.AddAction(ID_FILE_RESAVESLICES);
+#endif
fileMenu.AddSeparator();
diff --git a/Code/Editor/CryEdit.cpp b/Code/Editor/CryEdit.cpp
index 4415308730..77099761c1 100644
--- a/Code/Editor/CryEdit.cpp
+++ b/Code/Editor/CryEdit.cpp
@@ -380,13 +380,13 @@ void CCryEditApp::RegisterActionHandlers()
ON_COMMAND(ID_IMPORT_ASSET, OnOpenAssetImporter)
ON_COMMAND(ID_EDIT_LEVELDATA, OnEditLevelData)
ON_COMMAND(ID_FILE_EDITLOGFILE, OnFileEditLogFile)
- ON_COMMAND(ID_FILE_RESAVESLICES, OnFileResaveSlices)
ON_COMMAND(ID_FILE_EDITEDITORINI, OnFileEditEditorini)
ON_COMMAND(ID_PREFERENCES, OnPreferences)
ON_COMMAND(ID_REDO, OnRedo)
ON_COMMAND(ID_TOOLBAR_WIDGET_REDO, OnRedo)
ON_COMMAND(ID_FILE_OPEN_LEVEL, OnOpenLevel)
#ifdef ENABLE_SLICE_EDITOR
+ ON_COMMAND(ID_FILE_RESAVESLICES, OnFileResaveSlices)
ON_COMMAND(ID_FILE_NEW_SLICE, OnCreateSlice)
ON_COMMAND(ID_FILE_OPEN_SLICE, OnOpenSlice)
#endif
@@ -2629,6 +2629,7 @@ void CCryEditApp::OnFileEditLogFile()
CFileUtil::EditTextFile(CLogFile::GetLogFileName(), 0, IFileUtil::FILE_TYPE_SCRIPT);
}
+#ifdef ENABLE_SLICE_EDITOR
void CCryEditApp::OnFileResaveSlices()
{
AZStd::vector sliceAssetInfos;
@@ -2759,6 +2760,7 @@ void CCryEditApp::OnFileResaveSlices()
}
}
+#endif
//////////////////////////////////////////////////////////////////////////
void CCryEditApp::OnFileEditEditorini()
diff --git a/Code/Editor/EditorPanelUtils.cpp b/Code/Editor/EditorPanelUtils.cpp
deleted file mode 100644
index a270de5978..0000000000
--- a/Code/Editor/EditorPanelUtils.cpp
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-
-
-#include "EditorDefs.h"
-
-#include "EditorPanelUtils.h"
-
-#include
-
-// Qt
-#include
-#include
-#include
-
-// Editor
-#include "IEditorPanelUtils.h"
-#include "Objects/EntityObject.h"
-#include "CryEditDoc.h"
-#include "ViewManager.h"
-#include "Controls/QToolTipWidget.h"
-#include "Objects/SelectionGroup.h"
-
-
-
-#ifndef PI
-#define PI 3.14159265358979323f
-#endif
-
-
-struct ToolTip
-{
- bool isValid;
- QString title;
- QString content;
- QString specialContent;
- QString disabledContent;
-};
-
-// internal implementation for better compile times - should also never be used externally, use IParticleEditorUtils interface for that.
-class CEditorPanelUtils_Impl
- : public IEditorPanelUtils
-{
-public:
- void SetViewportDragOperation(void(* dropCallback)(CViewport* viewport, int dragPointX, int dragPointY, void* custom), void* custom) override
- {
- for (int i = 0; i < GetIEditor()->GetViewManager()->GetViewCount(); i++)
- {
- GetIEditor()->GetViewManager()->GetView(i)->SetGlobalDropCallback(dropCallback, custom);
- }
- }
-
-public:
-
- int PreviewWindow_GetDisplaySettingsDebugFlags(CDisplaySettings* settings) override
- {
- CRY_ASSERT(settings);
- return settings->GetDebugFlags();
- }
-
- void PreviewWindow_SetDisplaySettingsDebugFlags(CDisplaySettings* settings, int flags) override
- {
- CRY_ASSERT(settings);
- settings->SetDebugFlags(flags);
- }
-
-protected:
- QVector hotkeys;
- bool m_hotkeysAreEnabled;
-public:
-
- bool HotKey_Import() override
- {
- QVector > keys;
- QString filepath = QFileDialog::getOpenFileName(nullptr, "Select shortcut configuration to load",
- QString(), "HotKey Config Files (*.hkxml)");
- QFile file(filepath);
- if (!file.open(QIODevice::ReadOnly))
- {
- return false;
- }
- QXmlStreamReader stream(&file);
- bool result = true;
-
- while (!stream.isEndDocument())
- {
- if (stream.isStartElement())
- {
- if (stream.name() == "HotKey")
- {
- QPair key;
- QXmlStreamAttributes att = stream.attributes();
- for (QXmlStreamAttribute attr : att)
- {
- if (attr.name().compare(QLatin1String("path"), Qt::CaseInsensitive) == 0)
- {
- key.first = attr.value().toString();
- }
- if (attr.name().compare(QLatin1String("sequence"), Qt::CaseInsensitive) == 0)
- {
- key.second = attr.value().toString();
- }
- }
- if (!key.first.isEmpty())
- {
- keys.push_back(key); // we allow blank key sequences for unassigned shortcuts
- }
- else
- {
- result = false; //but not blank paths!
- }
- }
- }
- stream.readNext();
- }
- file.close();
-
- if (result)
- {
- HotKey_BuildDefaults();
- for (QPair key : keys)
- {
- for (int j = 0; j < hotkeys.count(); j++)
- {
- if (hotkeys[j].path.compare(key.first, Qt::CaseInsensitive) == 0)
- {
- hotkeys[j].SetPath(key.first.toStdString().c_str());
- hotkeys[j].SetSequenceFromString(key.second.toStdString().c_str());
- }
- }
- }
- }
- return result;
- }
-
- void HotKey_Export() override
- {
- auto settingDir = AZ::IO::FixedMaxPath(AZ::Utils::GetEnginePath()) / "Editor" / "Plugins" / "ParticleEditorPlugin" / "settings";
- QString filepath = QFileDialog::getSaveFileName(nullptr, "Select shortcut configuration to load", settingDir.c_str(), "HotKey Config Files (*.hkxml)");
- QFile file(filepath);
- if (!file.open(QIODevice::WriteOnly))
- {
- return;
- }
-
- QXmlStreamWriter stream(&file);
- stream.setAutoFormatting(true);
- stream.writeStartDocument();
- stream.writeStartElement("HotKeys");
-
- for (HotKey key : hotkeys)
- {
- stream.writeStartElement("HotKey");
- stream.writeAttribute("path", key.path);
- stream.writeAttribute("sequence", key.sequence.toString());
- stream.writeEndElement();
- }
- stream.writeEndElement();
- stream.writeEndDocument();
- file.close();
- }
-
- QKeySequence HotKey_GetShortcut(const char* path) override
- {
- for (HotKey combo : hotkeys)
- {
- if (combo.IsMatch(path))
- {
- return combo.sequence;
- }
- }
- return QKeySequence();
- }
-
- bool HotKey_IsPressed(const QKeyEvent* event, const char* path) override
- {
- if (!m_hotkeysAreEnabled)
- {
- return false;
- }
- unsigned int keyInt = 0;
- //Capture any modifiers
- Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
- if (modifiers & Qt::ShiftModifier)
- {
- keyInt += Qt::SHIFT;
- }
- if (modifiers & Qt::ControlModifier)
- {
- keyInt += Qt::CTRL;
- }
- if (modifiers & Qt::AltModifier)
- {
- keyInt += Qt::ALT;
- }
- if (modifiers & Qt::MetaModifier)
- {
- keyInt += Qt::META;
- }
- //Capture any key
- keyInt += event->key();
-
- QString t0 = QKeySequence(keyInt).toString();
- QString t1 = HotKey_GetShortcut(path).toString();
-
- //if strings match then shortcut is pressed
- if (t1.compare(t0, Qt::CaseInsensitive) == 0)
- {
- return true;
- }
- return false;
- }
-
- bool HotKey_IsPressed(const QShortcutEvent* event, const char* path) override
- {
- if (!m_hotkeysAreEnabled)
- {
- return false;
- }
-
- QString t0 = event->key().toString();
- QString t1 = HotKey_GetShortcut(path).toString();
-
- //if strings match then shortcut is pressed
- if (t1.compare(t0, Qt::CaseInsensitive) == 0)
- {
- return true;
- }
- return false;
- }
-
- bool HotKey_LoadExisting() override
- {
- QSettings settings("O3DE", "O3DE");
- QString group = "Hotkeys/";
-
- HotKey_BuildDefaults();
-
- int size = settings.beginReadArray(group);
-
- for (int i = 0; i < size; i++)
- {
- settings.setArrayIndex(i);
- QPair hotkey;
- hotkey.first = settings.value("name").toString();
- hotkey.second = settings.value("keySequence").toString();
- if (!hotkey.first.isEmpty())
- {
- for (int j = 0; j < hotkeys.count(); j++)
- {
- if (hotkeys[j].path.compare(hotkey.first, Qt::CaseInsensitive) == 0)
- {
- hotkeys[j].SetPath(hotkey.first.toStdString().c_str());
- hotkeys[j].SetSequenceFromString(hotkey.second.toStdString().c_str());
- }
- }
- }
- }
-
- settings.endArray();
- if (hotkeys.isEmpty())
- {
- return false;
- }
- return true;
- }
-
- void HotKey_SaveCurrent() override
- {
- QSettings settings("O3DE", "O3DE");
- QString group = "Hotkeys/";
- settings.remove("Hotkeys/");
- settings.sync();
- settings.beginWriteArray(group);
- int saveIndex = 0;
- for (HotKey key : hotkeys)
- {
- if (!key.path.isEmpty())
- {
- settings.setArrayIndex(saveIndex++);
- settings.setValue("name", key.path);
- settings.setValue("keySequence", key.sequence.toString());
- }
- }
- settings.endArray();
- settings.sync();
- }
-
- void HotKey_BuildDefaults() override
- {
- m_hotkeysAreEnabled = true;
- QVector > keys;
- while (hotkeys.count() > 0)
- {
- hotkeys.takeAt(0);
- }
-
- //MENU SELECTION SHORTCUTS////////////////////////////////////////////////
- keys.push_back(QPair("Menus.File Menu", "Alt+F"));
- keys.push_back(QPair("Menus.Edit Menu", "Alt+E"));
- keys.push_back(QPair("Menus.View Menu", "Alt+V"));
- //FILE MENU SHORTCUTS/////////////////////////////////////////////////////
- keys.push_back(QPair("File Menu.Create new emitter", "Ctrl+N"));
- keys.push_back(QPair("File Menu.Create new library", "Ctrl+Shift+N"));
- keys.push_back(QPair("File Menu.Create new folder", ""));
- keys.push_back(QPair("File Menu.Import", "Ctrl+I"));
- keys.push_back(QPair("File Menu.Import level library", "Ctrl+Shift+I"));
- keys.push_back(QPair("File Menu.Save", "Ctrl+S"));
- keys.push_back(QPair("File Menu.Close", "Ctrl+Q"));
- //EDIT MENU SHORTCUTS/////////////////////////////////////////////////////
- keys.push_back(QPair("Edit Menu.Copy", "Ctrl+C"));
- keys.push_back(QPair("Edit Menu.Paste", "Ctrl+V"));
- keys.push_back(QPair("Edit Menu.Duplicate", "Ctrl+D"));
- keys.push_back(QPair("Edit Menu.Undo", "Ctrl+Z"));
- keys.push_back(QPair("Edit Menu.Redo", "Ctrl+Shift+Z"));
- keys.push_back(QPair("Edit Menu.Group", "Ctrl+G"));
- keys.push_back(QPair("Edit Menu.Ungroup", "Ctrl+Shift+G"));
- keys.push_back(QPair("Edit Menu.Rename", "Ctrl+R"));
- keys.push_back(QPair("Edit Menu.Reset", ""));
- keys.push_back(QPair("Edit Menu.Edit Hotkeys", ""));
- keys.push_back(QPair("Edit Menu.Assign to selected", "Ctrl+Space"));
- keys.push_back(QPair("Edit Menu.Insert Comment", "Ctrl+Alt+M"));
- keys.push_back(QPair("Edit Menu.Enable/Disable Emitter", "Ctrl+E"));
- keys.push_back(QPair("File Menu.Enable All", ""));
- keys.push_back(QPair("File Menu.Disable All", ""));
- keys.push_back(QPair("Edit Menu.Delete", "Del"));
- //VIEW MENU SHORTCUTS/////////////////////////////////////////////////////
- keys.push_back(QPair("View Menu.Reset Layout", ""));
- //PLAYBACK CONTROL////////////////////////////////////////////////////////
- keys.push_back(QPair("Previewer.Play/Pause Toggle", "Space"));
- keys.push_back(QPair("Previewer.Step forward through time", "c"));
- keys.push_back(QPair("Previewer.Loop Toggle", "z"));
- keys.push_back(QPair("Previewer.Reset Playback", "x"));
- keys.push_back(QPair("Previewer.Focus", "Ctrl+F"));
- keys.push_back(QPair("Previewer.Zoom In", "w"));
- keys.push_back(QPair("Previewer.Zoom Out", "s"));
- keys.push_back(QPair("Previewer.Pan Left", "a"));
- keys.push_back(QPair("Previewer.Pan Right", "d"));
-
- for (QPair key : keys)
- {
- unsigned int index = hotkeys.count();
- hotkeys.push_back(HotKey());
- hotkeys[index].SetPath(key.first.toStdString().c_str());
- hotkeys[index].SetSequenceFromString(key.second.toStdString().c_str());
- }
- }
-
- void HotKey_SetKeys(QVector keys) override
- {
- hotkeys = keys;
- }
-
- QVector HotKey_GetKeys() override
- {
- return hotkeys;
- }
-
- QString HotKey_GetPressedHotkey(const QKeyEvent* event) override
- {
- if (!m_hotkeysAreEnabled)
- {
- return "";
- }
- for (HotKey key : hotkeys)
- {
- if (HotKey_IsPressed(event, key.path.toUtf8()))
- {
- return key.path;
- }
- }
- return "";
- }
- QString HotKey_GetPressedHotkey(const QShortcutEvent* event) override
- {
- if (!m_hotkeysAreEnabled)
- {
- return "";
- }
- for (HotKey key : hotkeys)
- {
- if (HotKey_IsPressed(event, key.path.toUtf8()))
- {
- return key.path;
- }
- }
- return "";
- }
- //building the default hotkey list re-enables hotkeys
- //do not use this when rebuilding the default list is a possibility.
- void HotKey_SetEnabled(bool val) override
- {
- m_hotkeysAreEnabled = val;
- }
-
- bool HotKey_IsEnabled() const override
- {
- return m_hotkeysAreEnabled;
- }
-
-protected:
- QMap m_tooltips;
-
- void ToolTip_ParseNode(XmlNodeRef node)
- {
- if (QString(node->getTag()).compare("tooltip", Qt::CaseInsensitive) != 0)
- {
- unsigned int childCount = node->getChildCount();
-
- for (unsigned int i = 0; i < childCount; i++)
- {
- ToolTip_ParseNode(node->getChild(i));
- }
- }
-
- QString title = node->getAttr("title");
- QString content = node->getAttr("content");
- QString specialContent = node->getAttr("special_content");
- QString disabledContent = node->getAttr("disabled_content");
-
- QMap::iterator itr = m_tooltips.insert(node->getAttr("path"), ToolTip());
- itr->isValid = true;
- itr->title = title;
- itr->content = content;
- itr->specialContent = specialContent;
- itr->disabledContent = disabledContent;
-
- unsigned int childCount = node->getChildCount();
-
- for (unsigned int i = 0; i < childCount; i++)
- {
- ToolTip_ParseNode(node->getChild(i));
- }
- }
-
- ToolTip GetToolTip(QString path)
- {
- if (m_tooltips.contains(path))
- {
- return m_tooltips[path];
- }
- ToolTip temp;
- temp.isValid = false;
- return temp;
- }
-
-public:
- void ToolTip_LoadConfigXML(QString filepath) override
- {
- XmlNodeRef node = GetIEditor()->GetSystem()->LoadXmlFromFile(filepath.toStdString().c_str());
- ToolTip_ParseNode(node);
- }
-
- void ToolTip_BuildFromConfig(IQToolTip* tooltip, QString path, QString option, QString optionalData = "", bool isEnabled = true) override
- {
- AZ_Assert(tooltip, "tooltip cannot be null");
-
- QString title = ToolTip_GetTitle(path, option);
- QString content = ToolTip_GetContent(path, option);
- QString specialContent = ToolTip_GetSpecialContentType(path, option);
- QString disabledContent = ToolTip_GetDisabledContent(path, option);
-
- // Even if these items are empty, we set them anyway to clear out any data that was left over from when the tooltip was used for a different object.
- tooltip->SetTitle(title);
- tooltip->SetContent(content);
-
- //this only handles simple creation...if you need complex call this then add specials separate
- if (!specialContent.contains("::"))
- {
- tooltip->AddSpecialContent(specialContent, optionalData);
- }
-
- if (!isEnabled) // If disabled, add disabled value
- {
- tooltip->AppendContent(disabledContent);
- }
- }
-
- QString ToolTip_GetTitle(QString path, QString option) override
- {
- if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
- {
- return GetToolTip(path + "." + option).title;
- }
- if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
- {
- return GetToolTip("Options." + option).title;
- }
- return GetToolTip(path).title;
- }
-
- QString ToolTip_GetContent(QString path, QString option) override
- {
- if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
- {
- return GetToolTip(path + "." + option).content;
- }
- if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
- {
- return GetToolTip("Options." + option).content;
- }
- return GetToolTip(path).content;
- }
-
- QString ToolTip_GetSpecialContentType(QString path, QString option) override
- {
- if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
- {
- return GetToolTip(path + "." + option).specialContent;
- }
- if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
- {
- return GetToolTip("Options." + option).specialContent;
- }
- return GetToolTip(path).specialContent;
- }
-
- QString ToolTip_GetDisabledContent(QString path, QString option) override
- {
- if (!option.isEmpty() && GetToolTip(path + "." + option).isValid)
- {
- return GetToolTip(path + "." + option).disabledContent;
- }
- if (!option.isEmpty() && GetToolTip("Options." + option).isValid)
- {
- return GetToolTip("Options." + option).disabledContent;
- }
- return GetToolTip(path).disabledContent;
- }
-};
-
-IEditorPanelUtils* CreateEditorPanelUtils()
-{
- return new CEditorPanelUtils_Impl();
-}
-
diff --git a/Code/Editor/EditorPanelUtils.h b/Code/Editor/EditorPanelUtils.h
deleted file mode 100644
index 6ac15ebfc9..0000000000
--- a/Code/Editor/EditorPanelUtils.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-// Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
-#ifndef CRYINCLUDE_CRYEDITOR_EDITORPANELUTILS_H
-#define CRYINCLUDE_CRYEDITOR_EDITORPANELUTILS_H
-#pragma once
-
-struct IEditorPanelUtils;
-IEditorPanelUtils* CreateEditorPanelUtils();
-
-#endif
diff --git a/Code/Editor/IEditor.h b/Code/Editor/IEditor.h
index c6f72a7dbc..d2d4998187 100644
--- a/Code/Editor/IEditor.h
+++ b/Code/Editor/IEditor.h
@@ -69,7 +69,6 @@ class CSelectionTreeManager;
struct SEditorSettings;
class CGameExporter;
class IAWSResourceManager;
-struct IEditorPanelUtils;
namespace WinWidget
{
@@ -526,8 +525,6 @@ struct IEditor
virtual IEditorMaterialManager* GetIEditorMaterialManager() = 0; // Vladimir@Conffx
//! Returns IconManager.
virtual IIconManager* GetIconManager() = 0;
- //! Get Panel Editor Utilities
- virtual IEditorPanelUtils* GetEditorPanelUtils() = 0;
//! Get Music Manager.
virtual CMusicManager* GetMusicManager() = 0;
virtual float GetTerrainElevation(float x, float y) = 0;
diff --git a/Code/Editor/IEditorImpl.cpp b/Code/Editor/IEditorImpl.cpp
index e5df6be58e..0846cf8a9e 100644
--- a/Code/Editor/IEditorImpl.cpp
+++ b/Code/Editor/IEditorImpl.cpp
@@ -81,9 +81,6 @@ AZ_POP_DISABLE_WARNING
// AWSNativeSDK
#include
-#include "IEditorPanelUtils.h"
-#include "EditorPanelUtils.h"
-
#include "Core/QtEditorApplication.h" // for Editor::EditorQtApplication
static CCryEditDoc * theDocument;
@@ -143,7 +140,6 @@ CEditorImpl::CEditorImpl()
, m_QtApplication(static_cast(qApp))
, m_pImageUtil(nullptr)
, m_pLogFile(nullptr)
- , m_panelEditorUtils(nullptr)
{
// note that this is a call into EditorCore.dll, which stores the g_pEditorPointer for all shared modules that share EditorCore.dll
// this means that they don't need to do SetIEditor(...) themselves and its available immediately
@@ -167,8 +163,6 @@ CEditorImpl::CEditorImpl()
m_pDisplaySettings->LoadRegistry();
m_pPluginManager = new CPluginManager;
- m_panelEditorUtils = CreateEditorPanelUtils();
-
m_pObjectManager = new CObjectManager;
m_pViewManager = new CViewManager;
m_pIconManager = new CIconManager;
@@ -301,8 +295,6 @@ CEditorImpl::~CEditorImpl()
SAFE_DELETE(m_pViewManager)
SAFE_DELETE(m_pObjectManager) // relies on prefab manager
- SAFE_DELETE(m_panelEditorUtils);
-
// some plugins may be exporter - this must be above plugin manager delete.
SAFE_DELETE(m_pExportManager);
@@ -1445,7 +1437,7 @@ ISourceControl* CEditorImpl::GetSourceControl()
{
IClassDesc* pClass = classes[i];
ISourceControl* pSCM = nullptr;
- HRESULT hRes = pClass->QueryInterface(__uuidof(ISourceControl), (void**)&pSCM);
+ HRESULT hRes = pClass->QueryInterface(__az_uuidof(ISourceControl), (void**)&pSCM);
if (!FAILED(hRes) && pSCM)
{
m_pSourceControl = pSCM;
@@ -1658,8 +1650,3 @@ void CEditorImpl::DestroyQMimeData(QMimeData* data) const
{
delete data;
}
-
-IEditorPanelUtils* CEditorImpl::GetEditorPanelUtils()
-{
- return m_panelEditorUtils;
-}
diff --git a/Code/Editor/IEditorImpl.h b/Code/Editor/IEditorImpl.h
index 4976c0c1ca..d99b8ae802 100644
--- a/Code/Editor/IEditorImpl.h
+++ b/Code/Editor/IEditorImpl.h
@@ -298,7 +298,6 @@ public:
IEditorMaterialManager* GetIEditorMaterialManager() override; // Vladimir@Conffx
IImageUtil* GetImageUtil() override; // Vladimir@conffx
SEditorSettings* GetEditorSettings() override;
- IEditorPanelUtils* GetEditorPanelUtils() override;
ILogFile* GetLogFile() override { return m_pLogFile; }
void UnloadPlugins() override;
@@ -356,7 +355,6 @@ protected:
CErrorsDlg* m_pErrorsDlg;
//! Source control interface.
ISourceControl* m_pSourceControl;
- IEditorPanelUtils* m_panelEditorUtils;
CSelectionTreeManager* m_pSelectionTreeManager;
diff --git a/Code/Editor/IEditorPanelUtils.h b/Code/Editor/IEditorPanelUtils.h
deleted file mode 100644
index 4649213ae7..0000000000
--- a/Code/Editor/IEditorPanelUtils.h
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- */
-
-#ifndef CRYINCLUDE_CRYEDITOR_IPANELEDITORUTILS_H
-#define CRYINCLUDE_CRYEDITOR_IPANELEDITORUTILS_H
-#pragma once
-
-#include "Cry_Vector3.h"
-
-#include "DisplaySettings.h"
-#include "Include/IDisplayViewport.h"
-#include "Include/IIconManager.h"
-#include
-#include
-#include
-#include
-
-class CBaseObject;
-class CViewport;
-class IQToolTip;
-
-struct HotKey
-{
- HotKey()
- : path("")
- , sequence(QKeySequence())
- {
- }
- void CopyFrom(const HotKey& other)
- {
- path = other.path;
- sequence = other.sequence;
- }
- void SetPath(const char* _path)
- {
- path = QString(_path);
- }
- void SetSequenceFromString(const char* _sequence)
- {
- sequence = QKeySequence::fromString(_sequence);
- }
- void SetSequence(const QKeySequence& other)
- {
- sequence = other;
- }
- bool IsMatch(QString _path)
- {
- return path.compare(_path, Qt::CaseInsensitive) == 0;
- }
- bool IsMatch(QKeySequence _sequence)
- {
- return sequence.matches(_sequence);
- }
- bool operator < (const HotKey& other) const
- {
- //split the paths into lists compare per level
- QStringList m_categories = path.split('.');
- QStringList o_categories = other.path.split('.');
- int m_catSize = m_categories.size();
- int o_catSize = o_categories.size();
- int size = (m_catSize < o_catSize) ? m_catSize : o_catSize;
-
- //sort categories to keep them together
- for (int i = 0; i < size; i++)
- {
- if (m_categories[i] < o_categories[i])
- {
- return true;
- }
- if (m_categories[i] > o_categories[i])
- {
- return false;
- }
- }
- //if comparing a category and a item in that category the category is < item
- return m_catSize > o_catSize;
- }
- QKeySequence sequence;
- QString path;
-};
-
-struct IEditorPanelUtils
-{
- virtual ~IEditorPanelUtils() {}
- virtual void SetViewportDragOperation(void(*)(CViewport* viewport, int dragPointX, int dragPointY, void* custom), void* custom) = 0;
-
- //PREVIEW WINDOW UTILS////////////////////////////////////////////////////
- virtual int PreviewWindow_GetDisplaySettingsDebugFlags(CDisplaySettings* settings) = 0;
- virtual void PreviewWindow_SetDisplaySettingsDebugFlags(CDisplaySettings* settings, int flags) = 0;
-
- //HOTKEY UTILS////////////////////////////////////////////////////////////
- virtual bool HotKey_Import() = 0;
- virtual void HotKey_Export() = 0;
- virtual QKeySequence HotKey_GetShortcut(const char* path) = 0;
- virtual bool HotKey_IsPressed(const QKeyEvent* event, const char* path) = 0;
- virtual bool HotKey_IsPressed(const QShortcutEvent* event, const char* path) = 0;
- virtual bool HotKey_LoadExisting() = 0;
- virtual void HotKey_SaveCurrent() = 0;
- virtual void HotKey_BuildDefaults() = 0;
- virtual void HotKey_SetKeys(QVector keys) = 0;
- virtual QVector HotKey_GetKeys() = 0;
- virtual QString HotKey_GetPressedHotkey(const QKeyEvent* event) = 0;
- virtual QString HotKey_GetPressedHotkey(const QShortcutEvent* event) = 0;
- virtual void HotKey_SetEnabled(bool val) = 0;
- virtual bool HotKey_IsEnabled() const = 0;
-
- //TOOLTIP UTILS///////////////////////////////////////////////////////////
-
- //! Loads a table of tooltip configuration data from an xml file.
- virtual void ToolTip_LoadConfigXML(QString filepath) = 0;
-
- //! Initializes a QToolTipWidget from loaded configuration data (see ToolTip_LoadConfigXML())
- //! \param tooltip Will be initialized using loaded configuration data
- //! \param path Variable serialization path. Will be used as the key for looking up data in the configuration table. (ex: "Rotation.Rotation_Rate_X")
- //! \param option Name of a sub-option of the variable specified by "path". (ex: "Emitter_Strength" will look up the tooltip data for "Rotation.Rotation_Rate_X.Emitter_Strength")
- //! \param optionalData The argument to be used with "special_content" feature. See ToolTip_GetSpecialContentType() and QToolTipWidget::AddSpecialContent().
- //! \param isEnabled If false, the tooltip will indicate the reason why the widget is disabled.
- virtual void ToolTip_BuildFromConfig(IQToolTip* tooltip, QString path, QString option, QString optionalData = "", bool isEnabled = true) = 0;
-
- virtual QString ToolTip_GetTitle(QString path, QString option = "") = 0;
- virtual QString ToolTip_GetContent(QString path, QString option = "") = 0;
- virtual QString ToolTip_GetSpecialContentType(QString path, QString option = "") = 0;
- virtual QString ToolTip_GetDisabledContent(QString path, QString option = "") = 0;
-};
-
-
-#endif
diff --git a/Code/Editor/Include/IEditorClassFactory.h b/Code/Editor/Include/IEditorClassFactory.h
index dd47f803e2..6c85192436 100644
--- a/Code/Editor/Include/IEditorClassFactory.h
+++ b/Code/Editor/Include/IEditorClassFactory.h
@@ -31,10 +31,7 @@ struct IUnknown
};
#endif
-#ifdef __uuidof
-#undef __uuidof
-#endif
-#define __uuidof(T) T::uuid()
+#define __az_uuidof(T) T::uuid()
#if defined(AZ_PLATFORM_LINUX) || defined(AZ_PLATFORM_MAC)
@@ -107,7 +104,7 @@ struct IClassDesc
template
HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp)
{
- return QueryInterface(__uuidof(Q), (void**)pp);
+ return QueryInterface(__az_uuidof(Q), (void**)pp);
}
//////////////////////////////////////////////////////////////////////////
diff --git a/Code/Editor/Include/IViewPane.h b/Code/Editor/Include/IViewPane.h
index b4a25a87a9..f2425fb954 100644
--- a/Code/Editor/Include/IViewPane.h
+++ b/Code/Editor/Include/IViewPane.h
@@ -60,7 +60,7 @@ struct IViewPaneClass
//////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObj)
{
- if (riid == __uuidof(IViewPaneClass))
+ if (riid == __az_uuidof(IViewPaneClass))
{
*ppvObj = this;
return S_OK;
diff --git a/Code/Editor/Lib/Tests/IEditorMock.h b/Code/Editor/Lib/Tests/IEditorMock.h
index 390ffebe79..590f98e6d7 100644
--- a/Code/Editor/Lib/Tests/IEditorMock.h
+++ b/Code/Editor/Lib/Tests/IEditorMock.h
@@ -187,6 +187,5 @@ public:
MOCK_METHOD0(UnloadPlugins, void());
MOCK_METHOD0(LoadPlugins, void());
MOCK_METHOD1(GetSearchPath, QString(EEditorPathName));
- MOCK_METHOD0(GetEditorPanelUtils, IEditorPanelUtils* ());
};
diff --git a/Code/Editor/Lib/Tests/test_ClickableLabel.cpp b/Code/Editor/Lib/Tests/test_ClickableLabel.cpp
deleted file mode 100644
index a676714992..0000000000
--- a/Code/Editor/Lib/Tests/test_ClickableLabel.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include "EditorDefs.h"
-#include
-#include
-#include
-
-#include
-
-using namespace AZ;
-using namespace ::testing;
-
-namespace UnitTest
-{
- class TestingClickableLabel
- : public ScopedAllocatorSetupFixture
- {
- public:
- ClickableLabel m_clickableLabel;
- };
-
- TEST_F(TestingClickableLabel, CursorDoesNotUpdateWhileDisabled)
- {
- m_clickableLabel.setEnabled(false);
-
- QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
- QEnterEvent enterEvent{ QPointF(), QPointF(), QPointF() };
- QApplication::sendEvent(&m_clickableLabel, &enterEvent);
-
- const Qt::CursorShape cursorShape = QApplication::overrideCursor()->shape();
- EXPECT_THAT(cursorShape, Ne(Qt::PointingHandCursor));
- EXPECT_THAT(cursorShape, Eq(Qt::BlankCursor));
- }
-
- TEST_F(TestingClickableLabel, DoesNotRespondToDblClickWhileDisabled)
- {
- m_clickableLabel.setEnabled(false);
-
- bool linkActivated = false;
- QObject::connect(&m_clickableLabel, &QLabel::linkActivated, [&linkActivated]()
- {
- linkActivated = true;
- });
-
- QMouseEvent mouseEvent {
- QEvent::MouseButtonDblClick, QPointF(),
- Qt::LeftButton, Qt::LeftButton, Qt::NoModifier };
- QApplication::sendEvent(&m_clickableLabel, &mouseEvent);
-
- EXPECT_THAT(linkActivated, Eq(false));
- }
-} // namespace UnitTest
diff --git a/Code/Editor/MainWindow.cpp b/Code/Editor/MainWindow.cpp
index f92e39f285..bbebac96a3 100644
--- a/Code/Editor/MainWindow.cpp
+++ b/Code/Editor/MainWindow.cpp
@@ -643,11 +643,11 @@ void MainWindow::InitActions()
.SetStatusTip(tr("Create a new slice"));
am->AddAction(ID_FILE_OPEN_SLICE, tr("Open Slice..."))
.SetStatusTip(tr("Open an existing slice"));
-#endif
am->AddAction(ID_FILE_SAVE_SELECTED_SLICE, tr("Save selected slice")).SetShortcut(tr("Alt+S"))
.SetStatusTip(tr("Save the selected slice to the first level root"));
am->AddAction(ID_FILE_SAVE_SLICE_TO_ROOT, tr("Save Slice to root")).SetShortcut(tr("Ctrl+Alt+S"))
.SetStatusTip(tr("Save the selected slice to the top level root"));
+#endif
am->AddAction(ID_FILE_SAVE_LEVEL, tr("&Save"))
.SetShortcut(tr("Ctrl+S"))
.SetReserved()
@@ -677,7 +677,9 @@ void MainWindow::InitActions()
.RegisterUpdateCallback(cryEdit, &CCryEditApp::OnUpdateSelected);
am->AddAction(ID_FILE_EXPORTOCCLUSIONMESH, tr("Export Occlusion Mesh"));
am->AddAction(ID_FILE_EDITLOGFILE, tr("Show Log File"));
+#ifdef ENABLE_SLICE_EDITOR
am->AddAction(ID_FILE_RESAVESLICES, tr("Resave All Slices"));
+#endif
am->AddAction(ID_FILE_PROJECT_MANAGER_SETTINGS, tr("Edit Project Settings..."));
am->AddAction(ID_FILE_PROJECT_MANAGER_NEW, tr("New Project..."));
am->AddAction(ID_FILE_PROJECT_MANAGER_OPEN, tr("Open Project..."));
diff --git a/Code/Editor/Plugin.cpp b/Code/Editor/Plugin.cpp
index 68f8d8833b..16c386e31c 100644
--- a/Code/Editor/Plugin.cpp
+++ b/Code/Editor/Plugin.cpp
@@ -155,7 +155,7 @@ IViewPaneClass* CClassFactory::FindViewPaneClassByTitle(const char* pPaneTitle)
{
IViewPaneClass* viewPane = nullptr;
IClassDesc* desc = m_classes[i];
- if (SUCCEEDED(desc->QueryInterface(__uuidof(IViewPaneClass), (void**)&viewPane)))
+ if (SUCCEEDED(desc->QueryInterface(__az_uuidof(IViewPaneClass), (void**)&viewPane)))
{
if (QString::compare(viewPane->GetPaneTitle(), pPaneTitle) == 0)
{
diff --git a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.h b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.h
index ec06fdc82a..794dca0f86 100644
--- a/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.h
+++ b/Code/Editor/Plugins/PerforcePlugin/PerforceSourceControl.h
@@ -49,7 +49,7 @@ public:
// from IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(const IID& riid, void** ppvObj)
{
- if (riid == __uuidof(ISourceControl) /* && m_pIntegrator*/)
+ if (riid == __az_uuidof(ISourceControl) /* && m_pIntegrator*/)
{
*ppvObj = this;
return S_OK;
diff --git a/Code/Editor/PreferencesStdPages.cpp b/Code/Editor/PreferencesStdPages.cpp
index 1dd40702a7..77b912a44e 100644
--- a/Code/Editor/PreferencesStdPages.cpp
+++ b/Code/Editor/PreferencesStdPages.cpp
@@ -50,7 +50,7 @@ CStdPreferencesClassDesc::CStdPreferencesClassDesc()
HRESULT CStdPreferencesClassDesc::QueryInterface(const IID& riid, void** ppvObj)
{
- if (riid == __uuidof(IPreferencesPageCreator))
+ if (riid == __az_uuidof(IPreferencesPageCreator))
{
*ppvObj = (IPreferencesPageCreator*)this;
return S_OK;
diff --git a/Code/Editor/QtUI/ClickableLabel.cpp b/Code/Editor/QtUI/ClickableLabel.cpp
deleted file mode 100644
index b0694e5f18..0000000000
--- a/Code/Editor/QtUI/ClickableLabel.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-#include "EditorDefs.h"
-
-#include "ClickableLabel.h"
-
-
-ClickableLabel::ClickableLabel(const QString& text, QWidget* parent)
- : QLabel(parent)
- , m_text(text)
- , m_showDecoration(false)
-{
- setTextFormat(Qt::RichText);
- setTextInteractionFlags(Qt::TextBrowserInteraction);
-}
-
-ClickableLabel::ClickableLabel(QWidget* parent)
- : QLabel(parent)
- , m_showDecoration(false)
-{
- setTextFormat(Qt::RichText);
- setTextInteractionFlags(Qt::TextBrowserInteraction);
-}
-
-void ClickableLabel::showEvent([[maybe_unused]] QShowEvent* event)
-{
- updateFormatting(false);
-}
-
-void ClickableLabel::enterEvent(QEvent* ev)
-{
- if (!isEnabled())
- {
- return;
- }
-
- updateFormatting(true);
- QApplication::setOverrideCursor(QCursor(Qt::PointingHandCursor));
- QLabel::enterEvent(ev);
-}
-
-void ClickableLabel::leaveEvent(QEvent* ev)
-{
- if (!isEnabled())
- {
- return;
- }
-
- updateFormatting(false);
- QApplication::restoreOverrideCursor();
- QLabel::leaveEvent(ev);
-}
-
-void ClickableLabel::setText(const QString& text)
-{
- m_text = text;
- QLabel::setText(text);
- updateFormatting(false);
-}
-
-void ClickableLabel::setShowDecoration(bool b)
-{
- m_showDecoration = b;
- updateFormatting(false);
-}
-
-void ClickableLabel::updateFormatting(bool mouseOver)
-{
- //FIXME: this should be done differently. Using a style sheet would be easiest.
-
- QColor c = palette().color(QPalette::WindowText);
- if (mouseOver || m_showDecoration)
- {
- QLabel::setText(QString(R"(%2)").arg(c.name(), m_text));
- }
- else
- {
- QLabel::setText(m_text);
- }
-}
-
-bool ClickableLabel::event(QEvent* e)
-{
- if (isEnabled())
- {
- if (e->type() == QEvent::MouseButtonDblClick)
- {
- emit linkActivated(QString());
- return true; //ignore
- }
- }
-
- return QLabel::event(e);
-}
-
-#include
diff --git a/Code/Editor/QtUI/ClickableLabel.h b/Code/Editor/QtUI/ClickableLabel.h
deleted file mode 100644
index 2b14676eae..0000000000
--- a/Code/Editor/QtUI/ClickableLabel.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-#pragma once
-#ifndef CRYINCLUDE_EDITORCOMMON_CLICKABLELABEL_H
-#define CRYINCLUDE_EDITORCOMMON_CLICKABLELABEL_H
-
-#if !defined(Q_MOC_RUN)
-#include
-#endif
-
-class SANDBOX_API ClickableLabel
- : public QLabel
-{
- Q_OBJECT
-public:
- explicit ClickableLabel(const QString& text, QWidget* parent = nullptr);
- explicit ClickableLabel(QWidget* parent = nullptr);
- bool event(QEvent* e) override;
-
- void setText(const QString& text);
- void setShowDecoration(bool b);
-
-protected:
- void showEvent(QShowEvent* event) override;
- void enterEvent(QEvent* ev) override;
- void leaveEvent(QEvent* ev) override;
-
-private:
- void updateFormatting(bool mouseOver);
- QString m_text;
- bool m_showDecoration;
-};
-
-#endif
diff --git a/Code/Editor/Util/FileUtil.cpp b/Code/Editor/Util/FileUtil.cpp
index 9f96d45381..182a122ea8 100644
--- a/Code/Editor/Util/FileUtil.cpp
+++ b/Code/Editor/Util/FileUtil.cpp
@@ -251,7 +251,7 @@ bool CFileUtil::ExtractDccFilenameFromAssetDatabase(const QString& assetFilename
for (size_t i = 0; i < assetDatabasePlugins.size(); ++i)
{
- if (assetDatabasePlugins[i]->QueryInterface(__uuidof(IAssetItemDatabase), (void**)&pCurrentDatabaseInterface) == S_OK)
+ if (assetDatabasePlugins[i]->QueryInterface(__az_uuidof(IAssetItemDatabase), (void**)&pCurrentDatabaseInterface) == S_OK)
{
if (!pCurrentDatabaseInterface)
{
diff --git a/Code/Editor/editor_lib_files.cmake b/Code/Editor/editor_lib_files.cmake
index fa627176d8..a018333925 100644
--- a/Code/Editor/editor_lib_files.cmake
+++ b/Code/Editor/editor_lib_files.cmake
@@ -297,8 +297,6 @@ set(FILES
Util/AffineParts.cpp
Objects/BaseObject.cpp
Objects/BaseObject.h
- Animation/AnimationBipedBoneNames.cpp
- Animation/AnimationBipedBoneNames.h
AnimationContext.cpp
AnimationContext.h
AzAssetBrowser/AzAssetBrowserRequestHandler.cpp
@@ -336,23 +334,12 @@ set(FILES
Controls/ConsoleSCB.qrc
Controls/FolderTreeCtrl.cpp
Controls/FolderTreeCtrl.h
- Controls/HotTrackingTreeCtrl.cpp
- Controls/HotTrackingTreeCtrl.h
Controls/ImageHistogramCtrl.cpp
Controls/ImageHistogramCtrl.h
- Controls/ImageListCtrl.cpp
- Controls/ImageListCtrl.h
- Controls/MultiMonHelper.cpp
- Controls/MultiMonHelper.h
- Controls/NumberCtrl.cpp
- Controls/NumberCtrl.h
- Controls/NumberCtrl.h
Controls/SplineCtrl.cpp
Controls/SplineCtrl.h
Controls/SplineCtrlEx.cpp
Controls/SplineCtrlEx.h
- Controls/TextEditorCtrl.cpp
- Controls/TextEditorCtrl.h
Controls/TimelineCtrl.cpp
Controls/TimelineCtrl.h
Controls/WndGridHelper.h
@@ -526,8 +513,6 @@ set(FILES
PythonEditorFuncs.h
QtUI/QCollapsibleGroupBox.h
QtUI/QCollapsibleGroupBox.cpp
- QtUI/ClickableLabel.h
- QtUI/ClickableLabel.cpp
QtUI/PixmapLabelPreview.h
QtUI/PixmapLabelPreview.cpp
QtUI/WaitCursor.h
@@ -800,9 +785,6 @@ set(FILES
ViewportTitleDlg.h
EditorEnvironment.cpp
EditorEnvironment.h
- IEditorPanelUtils.h
- EditorPanelUtils.h
- EditorPanelUtils.cpp
)
diff --git a/Code/Editor/editor_lib_test_files.cmake b/Code/Editor/editor_lib_test_files.cmake
index 17f36228db..5b66357c41 100644
--- a/Code/Editor/editor_lib_test_files.cmake
+++ b/Code/Editor/editor_lib_test_files.cmake
@@ -8,7 +8,6 @@
set(FILES
Lib/Tests/IEditorMock.h
- Lib/Tests/test_ClickableLabel.cpp
Lib/Tests/test_CryEditPythonBindings.cpp
Lib/Tests/test_CryEditDocPythonBindings.cpp
Lib/Tests/test_EditorPythonBindings.cpp
diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.h b/Code/Framework/AzCore/AzCore/IO/Path/Path.h
index 094dee16f2..7f89809294 100644
--- a/Code/Framework/AzCore/AzCore/IO/Path/Path.h
+++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.h
@@ -484,6 +484,7 @@ namespace AZ::IO
// as_posix
//! Replicates the behavior of the Python pathlib as_posix method
//! by replacing the Windows Path Separator with the Posix Path Seperator
+ constexpr string_type AsPosix() const;
AZStd::string StringAsPosix() const;
constexpr AZStd::fixed_string FixedMaxPathStringAsPosix() const noexcept;
diff --git a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl
index 5ac15fc728..0dc1799528 100644
--- a/Code/Framework/AzCore/AzCore/IO/Path/Path.inl
+++ b/Code/Framework/AzCore/AzCore/IO/Path/Path.inl
@@ -1043,6 +1043,13 @@ namespace AZ::IO
// as_posix
// Returns a copy of the path with the path separators converted to PosixPathSeparator
template
+ constexpr auto BasicPath::AsPosix() const -> string_type
+ {
+ string_type resultPath(m_path.begin(), m_path.end());
+ AZStd::replace(resultPath.begin(), resultPath.end(), WindowsPathSeparator, PosixPathSeparator);
+ return resultPath;
+ }
+ template
AZStd::string BasicPath::StringAsPosix() const
{
AZStd::string resultPath(m_path.begin(), m_path.end());
diff --git a/Code/Framework/AzCore/AzCore/IO/Path/PathReflect.cpp b/Code/Framework/AzCore/AzCore/IO/Path/PathReflect.cpp
index 55a991f19f..1d0cdba66c 100644
--- a/Code/Framework/AzCore/AzCore/IO/Path/PathReflect.cpp
+++ b/Code/Framework/AzCore/AzCore/IO/Path/PathReflect.cpp
@@ -7,6 +7,8 @@
*/
#include
+#include
+#include
#include
#include
@@ -35,10 +37,8 @@ namespace AZ::IO
size_t Save(const void* classPtr, IO::GenericStream& stream, bool) override
{
/// Save paths out using the PosixPathSeparator
- PathType path(reinterpret_cast(classPtr)->Native(), AZ::IO::PosixPathSeparator);
- path.MakePreferred();
-
- return static_cast(stream.Write(path.Native().size(), path.c_str()));
+ auto posixPathString{ reinterpret_cast(classPtr)->AsPosix() };
+ return static_cast(stream.Write(posixPathString.size(), posixPathString.c_str()));
}
bool Load(void* classPtr, IO::GenericStream& stream, unsigned int, bool) override
@@ -73,5 +73,11 @@ namespace AZ::IO
AZ::SerializeContext::IDataSerializer::CreateDefaultDeleteDeleter() })
;
}
+ else if (auto jsonContext = azrtti_cast(context))
+ {
+ jsonContext->Serializer()
+ ->HandlesType()
+ ->HandlesType();
+ }
}
}
diff --git a/Code/Framework/AzCore/AzCore/Interface/Interface.h b/Code/Framework/AzCore/AzCore/Interface/Interface.h
index 8664e2905f..8f72cfa109 100644
--- a/Code/Framework/AzCore/AzCore/Interface/Interface.h
+++ b/Code/Framework/AzCore/AzCore/Interface/Interface.h
@@ -109,6 +109,7 @@ namespace AZ
*/
static EnvironmentVariable s_instance;
static AZStd::shared_mutex s_mutex;
+ static bool s_instanceAssigned;
};
template
@@ -117,6 +118,9 @@ namespace AZ
template
AZStd::shared_mutex Interface::s_mutex;
+ template
+ bool Interface::s_instanceAssigned;
+
template
void Interface::Register(T* type)
{
@@ -135,18 +139,19 @@ namespace AZ
AZStd::unique_lock lock(s_mutex);
s_instance = Environment::CreateVariable(GetVariableName());
s_instance.Get() = type;
+ s_instanceAssigned = true;
}
template
void Interface::Unregister(T* type)
{
- if (!s_instance || !s_instance.Get())
+ if (!s_instanceAssigned)
{
AZ_Assert(false, "Interface '%s' not registered on this module!", AzTypeInfo::Name());
return;
}
- if (s_instance.Get() != type)
+ if (s_instance && s_instance.Get() != type)
{
AZ_Assert(false, "Interface '%s' is not the same instance that was registered! [Expected '%p', Found '%p']", AzTypeInfo::Name(), type, s_instance.Get());
return;
@@ -156,6 +161,7 @@ namespace AZ
AZStd::unique_lock lock(s_mutex);
*s_instance = nullptr;
s_instance.Reset();
+ s_instanceAssigned = false;
}
template
@@ -165,9 +171,9 @@ namespace AZ
// This is the fast path which won't block.
{
AZStd::shared_lock lock(s_mutex);
- if (s_instance)
+ if (s_instanceAssigned)
{
- return s_instance.Get();
+ return s_instance ? s_instance.Get() : nullptr;
}
}
@@ -175,6 +181,7 @@ namespace AZ
// take the full lock and request it.
AZStd::unique_lock lock(s_mutex);
s_instance = Environment::FindVariable(GetVariableName());
+ s_instanceAssigned = true;
return s_instance ? s_instance.Get() : nullptr;
}
diff --git a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp
index 5d13acc34c..4f143cde53 100644
--- a/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp
+++ b/Code/Framework/AzCore/AzCore/Math/IntersectSegment.cpp
@@ -8,778 +8,936 @@
#include
-using namespace AZ;
-using namespace Intersect;
-
-//=========================================================================
-// IntersectSegmentTriangleCCW
-// [10/21/2009]
-//=========================================================================
-bool Intersect::IntersectSegmentTriangleCCW(
- const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c,
- /*float &u, float &v, float &w,*/ Vector3& normal, float& t)
+namespace AZ
{
- float v, w; // comment this and enable input params if we need the barycentric coordinates
-
- Vector3 ab = b - a;
- Vector3 ac = c - a;
- Vector3 qp = p - q;
-
- // Compute triangle normal. Can be pre-calculated/cached if
- // intersecting multiple segments against the same triangle
- normal = ab.Cross(ac); // Right hand CCW
-
- // Compute denominator d. If d <= 0, segment is parallel to or points
- // away from triangle, so exit early
- float d = qp.Dot(normal);
- if (d <= 0.0f)
+ //=========================================================================
+ // IntersectSegmentTriangleCCW
+ // [10/21/2009]
+ //=========================================================================
+ bool Intersect::IntersectSegmentTriangleCCW(
+ const Vector3& p,
+ const Vector3& q,
+ const Vector3& a,
+ const Vector3& b,
+ const Vector3& c,
+ /*float &u, float &v, float &w,*/ Vector3& normal,
+ float& t)
{
- return false;
- }
+ float v, w; // comment this and enable input params if we need the barycentric coordinates
- // Compute intersection t value of pq with plane of triangle. A ray
- // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
- // dividing by d until intersection has been found to pierce triangle
- Vector3 ap = p - a;
- t = ap.Dot(normal);
+ Vector3 ab = b - a;
+ Vector3 ac = c - a;
+ Vector3 qp = p - q;
- // range segment check t[0,1] (it this case [0,d])
- if (t < 0.0f || t > d)
- {
- return false;
- }
+ // Compute triangle normal. Can be pre-calculated/cached if
+ // intersecting multiple segments against the same triangle
+ normal = ab.Cross(ac); // Right hand CCW
- // Compute barycentric coordinate components and test if within bounds
- Vector3 e = qp.Cross(ap);
- v = ac.Dot(e);
- if (v < 0.0f || v > d)
- {
- return false;
- }
- w = -ab.Dot(e);
- if (w < 0.0f || v + w > d)
- {
- return false;
- }
-
- // Segment/ray intersects triangle. Perform delayed division and
- // compute the last barycentric coordinate component
- float ood = 1.0f / d;
- t *= ood;
- /*v *= ood;
- w *= ood;
- u = 1.0f - v - w;*/
-
- normal.Normalize();
-
- return true;
-}
-
-//=========================================================================
-// IntersectSegmentTriangle
-// [10/21/2009]
-//=========================================================================
-bool
-Intersect::IntersectSegmentTriangle(
- const Vector3& p, const Vector3& q, const Vector3& a, const Vector3& b, const Vector3& c,
- /*float &u, float &v, float &w,*/ Vector3& normal, float& t)
-{
- float v, w; // comment this and enable input params if we need the barycentric coordinates
-
- Vector3 ab = b - a;
- Vector3 ac = c - a;
- Vector3 qp = p - q;
- Vector3 ap = p - a;
-
- // Compute triangle normal. Can be pre-calculated or cached if
- // intersecting multiple segments against the same triangle
- normal = ab.Cross(ac); // Right hand CCW
-
- // Compute denominator d. If d <= 0, segment is parallel to or points
- // away from triangle, so exit early
- float d = qp.Dot(normal);
- Vector3 e;
- if (d > Constants::FloatEpsilon)
- {
- // the normal is on the right side
- e = qp.Cross(ap);
- }
- else
- {
- normal = -normal;
-
- // so either have a parallel ray or our normal is flipped
- if (d >= -Constants::FloatEpsilon)
+ // Compute denominator d. If d <= 0, segment is parallel to or points
+ // away from triangle, so exit early
+ float d = qp.Dot(normal);
+ if (d <= 0.0f)
{
- return false; // parallel
- }
- d = -d;
- e = ap.Cross(qp);
- }
-
- // Compute intersection t value of pq with plane of triangle. A ray
- // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
- // dividing by d until intersection has been found to pierce triangle
- t = ap.Dot(normal);
-
- // range segment check t[0,1] (it this case [0,d])
- if (t < 0.0f || t > d)
- {
- return false;
- }
-
- // Compute barycentric coordinate components and test if within bounds
- v = ac.Dot(e);
- if (v < 0.0f || v > d)
- {
- return false;
- }
- w = -ab.Dot(e);
- if (w < 0.0f || v + w > d)
- {
- return false;
- }
-
- // Segment/ray intersects the triangle. Perform delayed division and
- // compute the last barycentric coordinate component
- float ood = 1.0f / d;
- t *= ood;
- //v *= ood;
- //w *= ood;
- //u = 1.0f - v - w;
-
- normal.Normalize();
-
- return true;
-}
-
-//=========================================================================
-// TestSegmentAABBOrigin
-// [10/21/2009]
-//=========================================================================
-bool
-AZ::Intersect::TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends)
-{
- const Vector3 EPSILON(0.001f); // \todo this is slow load move to a const
- Vector3 absHalfVector = halfVector.GetAbs();
- Vector3 absMidpoint = midPoint.GetAbs();
- Vector3 absHalfMidpoint = absHalfVector + aabbExtends;
-
- // Try world coordinate axes as separating axes
- if (!absMidpoint.IsLessEqualThan(absHalfMidpoint))
- {
- return false;
- }
-
- // Add in an epsilon term to counteract arithmetic errors when segment is
- // (near) parallel to a coordinate axis (see text for detail)
- absHalfVector += EPSILON;
-
- // Try cross products of segment direction vector with coordinate axes
- Vector3 absMDCross = midPoint.Cross(halfVector).GetAbs();
- //Vector3 eaDCross = absHalfVector.Cross(aabbExtends);
- float ex = aabbExtends.GetX();
- float ey = aabbExtends.GetY();
- float ez = aabbExtends.GetZ();
- float adx = absHalfVector.GetX();
- float ady = absHalfVector.GetY();
- float adz = absHalfVector.GetZ();
-
- Vector3 ead(ey * adz + ez * ady, ex * adz + ez * adx, ex * ady + ey * adx);
- if (!absMDCross.IsLessEqualThan(ead))
- {
- return false;
- }
-
- // No separating axis found; segment must be overlapping AABB
- return true;
-}
-
-
-//=========================================================================
-// IntersectRayAABB
-// [10/21/2009]
-//=========================================================================
-RayAABBIsectTypes
-AZ::Intersect::IntersectRayAABB(
- const Vector3& rayStart, const Vector3& dir, const Vector3& dirRCP, const Aabb& aabb,
- float& tStart, float& tEnd, Vector3& startNormal /*, Vector3& inter*/)
-{
- // we don't need to test with all 6 normals (just 3)
-
- const float eps = 0.0001f; // \todo move to constant
- float tmin = 0.0f; // set to -RR_FLT_MAX to get first hit on line
- float tmax = std::numeric_limits::max(); // set to max distance ray can travel (for segment)
-
- const Vector3& aabbMin = aabb.GetMin();
- const Vector3& aabbMax = aabb.GetMax();
-
- // we unroll manually because there is no way to get in efficient way vectors for
- // each axis while getting it as a index
- Vector3 time1 = (aabbMin - rayStart) * dirRCP;
- Vector3 time2 = (aabbMax - rayStart) * dirRCP;
-
- // X
- if (std::fabs(dir.GetX()) < eps)
- {
- // Ray is parallel to slab. No hit if origin not within slab
- if (rayStart.GetX() < aabbMin.GetX() || rayStart.GetX() > aabbMax.GetX())
- {
- return ISECT_RAY_AABB_NONE;
- }
- }
- else
- {
- // Compute intersection t value of ray with near and far plane of slab
- float t1 = time1.GetX();
- float t2 = time2.GetX();
- float nSign = -1.0f;
-
- // Make t1 be intersection with near plane, t2 with far plane
- if (t1 > t2)
- {
- AZStd::swap(t1, t2);
- nSign = 1.0f;
+ return false;
}
- // Compute the intersection of slab intersections intervals
- if (tmin < t1)
- {
- tmin = t1;
+ // Compute intersection t value of pq with plane of triangle. A ray
+ // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
+ // dividing by d until intersection has been found to pierce triangle
+ Vector3 ap = p - a;
+ t = ap.Dot(normal);
- startNormal.Set(nSign, 0.0f, 0.0f);
+ // range segment check t[0,1] (it this case [0,d])
+ if (t < 0.0f || t > d)
+ {
+ return false;
}
- tmax = AZ::GetMin(tmax, t2);
-
- // Exit with no collision as soon as slab intersection becomes empty
- if (tmin > tmax)
+ // Compute barycentric coordinate components and test if within bounds
+ Vector3 e = qp.Cross(ap);
+ v = ac.Dot(e);
+ if (v < 0.0f || v > d)
{
- return ISECT_RAY_AABB_NONE;
+ return false;
}
- }
-
- // Y
- if (std::fabs(dir.GetY()) < eps)
- {
- // Ray is parallel to slab. No hit if origin not within slab
- if (rayStart.GetY() < aabbMin.GetY() || rayStart.GetY() > aabbMax.GetY())
+ w = -ab.Dot(e);
+ if (w < 0.0f || v + w > d)
{
- return ISECT_RAY_AABB_NONE;
- }
- }
- else
- {
- // Compute intersection t value of ray with near and far plane of slab
- float t1 = time1.GetY();
- float t2 = time2.GetY();
- float nSign = -1.0f;
-
- // Make t1 be intersection with near plane, t2 with far plane
- if (t1 > t2)
- {
- AZStd::swap(t1, t2);
- nSign = 1.0f;
+ return false;
}
- // Compute the intersection of slab intersections intervals
- if (tmin < t1)
- {
- tmin = t1;
+ // Segment/ray intersects triangle. Perform delayed division and
+ // compute the last barycentric coordinate component
+ float ood = 1.0f / d;
+ t *= ood;
+ /*v *= ood;
+ w *= ood;
+ u = 1.0f - v - w;*/
- startNormal.Set(0.0f, nSign, 0.0f);
+ normal.Normalize();
+
+ return true;
+ }
+
+ //=========================================================================
+ // IntersectSegmentTriangle
+ // [10/21/2009]
+ //=========================================================================
+ bool Intersect::IntersectSegmentTriangle(
+ const Vector3& p,
+ const Vector3& q,
+ const Vector3& a,
+ const Vector3& b,
+ const Vector3& c,
+ /*float &u, float &v, float &w,*/ Vector3& normal,
+ float& t)
+ {
+ float v, w; // comment this and enable input params if we need the barycentric coordinates
+
+ Vector3 ab = b - a;
+ Vector3 ac = c - a;
+ Vector3 qp = p - q;
+ Vector3 ap = p - a;
+
+ // Compute triangle normal. Can be pre-calculated or cached if
+ // intersecting multiple segments against the same triangle
+ normal = ab.Cross(ac); // Right hand CCW
+
+ // Compute denominator d. If d <= 0, segment is parallel to or points
+ // away from triangle, so exit early
+ float d = qp.Dot(normal);
+ Vector3 e;
+ if (d > Constants::FloatEpsilon)
+ {
+ // the normal is on the right side
+ e = qp.Cross(ap);
}
-
- tmax = AZ::GetMin(tmax, t2);
-
- // Exit with no collision as soon as slab intersection becomes empty
- if (tmin > tmax)
+ else
{
- return ISECT_RAY_AABB_NONE;
- }
- }
+ normal = -normal;
- // Z
- if (std::fabs(dir.GetZ()) < eps)
- {
- // Ray is parallel to slab. No hit if origin not within slab
- if (rayStart.GetZ() < aabbMin.GetZ() || rayStart.GetZ() > aabbMax.GetZ())
- {
- return ISECT_RAY_AABB_NONE;
- }
- }
- else
- {
- // Compute intersection t value of ray with near and far plane of slab
- float t1 = time1.GetZ();
- float t2 = time2.GetZ();
- float nSign = -1.0f;
-
- // Make t1 be intersection with near plane, t2 with far plane
- if (t1 > t2)
- {
- AZStd::swap(t1, t2);
- nSign = 1.0f;
- }
-
- // Compute the intersection of slab intersections intervals
- if (tmin < t1)
- {
- tmin = t1;
-
- startNormal.Set(0.0f, 0.0f, nSign);
- }
-
- tmax = AZ::GetMin(tmax, t2);
-
- // Exit with no collision as soon as slab intersection becomes empty
- if (tmin > tmax)
- {
- return ISECT_RAY_AABB_NONE;
- }
- }
-
- tStart = tmin;
- tEnd = tmax;
-
- if (tmin == 0.0f) // no intersect if the segments starts inside or coincident the aabb
- {
- return ISECT_RAY_AABB_SA_INSIDE;
- }
-
- // Ray intersects all 3 slabs. Return point (q) and intersection t value (tmin)
- //inter = rayStart + dir * tmin;
- return ISECT_RAY_AABB_ISECT;
-}
-
-//=========================================================================
-// IntersectRayAABB2
-// [2/18/2011]
-//=========================================================================
-RayAABBIsectTypes
-AZ::Intersect::IntersectRayAABB2(const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, float& start, float& end)
-{
- float tmin, tmax, tymin, tymax, tzmin, tzmax;
- Vector3 vZero = Vector3::CreateZero();
-
- Vector3 min = (Vector3::CreateSelectCmpGreaterEqual(dirRCP, vZero, aabb.GetMin(), aabb.GetMax()) - rayStart) * dirRCP;
- Vector3 max = (Vector3::CreateSelectCmpGreaterEqual(dirRCP, vZero, aabb.GetMax(), aabb.GetMin()) - rayStart) * dirRCP;
-
- tmin = min.GetX();
- tmax = max.GetX();
- tymin = min.GetY();
- tymax = max.GetY();
-
- if (tmin > tymax || tymin > tmax)
- {
- return ISECT_RAY_AABB_NONE;
- }
-
- if (tymin > tmin)
- {
- tmin = tymin;
- }
-
- if (tymax < tmax)
- {
- tmax = tymax;
- }
-
- tzmin = min.GetZ();
- tzmax = max.GetZ();
-
- if (tmin > tzmax || tzmin > tmax)
- {
- return ISECT_RAY_AABB_NONE;
- }
-
- if (tzmin > tmin)
- {
- tmin = tzmin;
- }
- if (tzmax < tmax)
- {
- tmax = tzmax;
- }
-
- start = tmin;
- end = tmax;
-
- return ISECT_RAY_AABB_ISECT;
-}
-
-bool AZ::Intersect::IntersectRayDisk(
- const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& diskCenter, const float diskRadius, const Vector3& diskNormal, float& t)
-{
- // First intersect with the plane of the disk
- float planeIntersectionDistance;
- int intersectionCount = IntersectRayPlane(rayOrigin, rayDir, diskCenter, diskNormal, planeIntersectionDistance);
- if (intersectionCount == 1)
- {
- // If the plane intersection point is inside the disk radius, then it intersected the disk.
- Vector3 pointOnPlane = rayOrigin + rayDir * planeIntersectionDistance;
- if (pointOnPlane.GetDistance(diskCenter) < diskRadius)
- {
- t = planeIntersectionDistance;
- return true;
- }
- }
- return false;
-}
-
-// Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder, and the book's errata.
-int AZ::Intersect::IntersectRayCappedCylinder(
- const Vector3& rayOrigin, const Vector3& rayDir,
- const Vector3& cylinderEnd1, const Vector3& cylinderDir,
- float cylinderHeight, float cylinderRadius, float &t1, float &t2)
-{
- // dr = rayDir
- // dc = cylinderDir
- // r = cylinderRadius
- // Vector3 cylinderEnd2 = cylinderEnd1 + cylinderHeight * cylinderDir;
- Vector3 m = rayOrigin - cylinderEnd1; // vector from cylinderEnd1 to rayOrigin
- float dcm = cylinderDir.Dot(m); // projection of m on cylinderDir
- float dcdr = cylinderDir.Dot(rayDir); // projection of rayDir on cylinderDir
- float drm = rayDir.Dot(m); // projection of m on rayDir
- float r2 = cylinderRadius * cylinderRadius;
-
- if (dcm < 0.0f && dcdr <= 0.0f)
- {
- return 0; // rayOrigin is outside cylinderEnd1 and rayDir is pointing away from cylinderEnd1
- }
- if (dcm > cylinderHeight && dcdr >= 0.0f)
- {
- return 0; // rayOrigin is outside cylinderEnd2 and rayDir is pointing away from cylinderEnd2
- }
-
- // point RP on the ray: RP(t) = rayOrigin + t * rayDir
- // point CP on the cylinder surface: |(CP - cylinderEnd1) - cylinderDir.Dot(cp - cylinderEnd1) * cylinderDir|^2 = cylinderRadius^2
- // substitute RP(t) for CP: a*t^2 + 2b*t + c = 0, solving for t = [-2b +/- sqrt(4b^2 - 4ac)] / 2a
- float a = 1.0f - dcdr * dcdr; // always greater than or equal to 0
- float b = drm - dcm * dcdr;
- float c = m.Dot(m) - dcm * dcm - r2;
-
- const float EPSILON = 0.00001f;
-
- if (fabsf(a) < EPSILON) // the ray is parallel to the cylinder
- {
- if (c > EPSILON) // the ray is outside the cylinder
- {
- return 0;
- }
- else if (dcm < 0.0f) // the ray origin is on cylinderEnd1 side and ray is pointing to cylinderEnd2
- {
- t1 = -dcm;
- t2 = -dcm + cylinderHeight;
- return 2;
- }
- else if (dcm > cylinderHeight) // the ray origin is on cylinderEnd2 side and ray is pointing to cylinderEnd1
- {
- t1 = dcm - cylinderHeight;
- t2 = dcm;
- return 2;
- }
- else // (dcm > 0.0f && dcm < cylinderHeight) // the ray origin is inside the cylinder
- {
- if (dcdr > 0.0f) // the ray is pointing to cylinderEnd2
+ // so either have a parallel ray or our normal is flipped
+ if (d >= -Constants::FloatEpsilon)
{
- t1 = cylinderHeight - dcm;
- return 1;
+ return false; // parallel
}
- else if (dcdr < 0.0f) // the ray is pointing to cylinderEnd1
+ d = -d;
+ e = ap.Cross(qp);
+ }
+
+ // Compute intersection t value of pq with plane of triangle. A ray
+ // intersects iff 0 <= t. Segment intersects iff 0 <= t <= 1. Delay
+ // dividing by d until intersection has been found to pierce triangle
+ t = ap.Dot(normal);
+
+ // range segment check t[0,1] (it this case [0,d])
+ if (t < 0.0f || t > d)
+ {
+ return false;
+ }
+
+ // Compute barycentric coordinate components and test if within bounds
+ v = ac.Dot(e);
+ if (v < 0.0f || v > d)
+ {
+ return false;
+ }
+ w = -ab.Dot(e);
+ if (w < 0.0f || v + w > d)
+ {
+ return false;
+ }
+
+ // Segment/ray intersects the triangle. Perform delayed division and
+ // compute the last barycentric coordinate component
+ float ood = 1.0f / d;
+ t *= ood;
+ // v *= ood;
+ // w *= ood;
+ // u = 1.0f - v - w;
+
+ normal.Normalize();
+
+ return true;
+ }
+
+ //=========================================================================
+ // TestSegmentAABBOrigin
+ // [10/21/2009]
+ //=========================================================================
+ bool Intersect::TestSegmentAABBOrigin(const Vector3& midPoint, const Vector3& halfVector, const Vector3& aabbExtends)
+ {
+ const Vector3 EPSILON(0.001f); // \todo this is slow load move to a const
+ Vector3 absHalfVector = halfVector.GetAbs();
+ Vector3 absMidpoint = midPoint.GetAbs();
+ Vector3 absHalfMidpoint = absHalfVector + aabbExtends;
+
+ // Try world coordinate axes as separating axes
+ if (!absMidpoint.IsLessEqualThan(absHalfMidpoint))
+ {
+ return false;
+ }
+
+ // Add in an epsilon term to counteract arithmetic errors when segment is
+ // (near) parallel to a coordinate axis (see text for detail)
+ absHalfVector += EPSILON;
+
+ // Try cross products of segment direction vector with coordinate axes
+ Vector3 absMDCross = midPoint.Cross(halfVector).GetAbs();
+ // Vector3 eaDCross = absHalfVector.Cross(aabbExtends);
+ float ex = aabbExtends.GetX();
+ float ey = aabbExtends.GetY();
+ float ez = aabbExtends.GetZ();
+ float adx = absHalfVector.GetX();
+ float ady = absHalfVector.GetY();
+ float adz = absHalfVector.GetZ();
+
+ Vector3 ead(ey * adz + ez * ady, ex * adz + ez * adx, ex * ady + ey * adx);
+ if (!absMDCross.IsLessEqualThan(ead))
+ {
+ return false;
+ }
+
+ // No separating axis found; segment must be overlapping AABB
+ return true;
+ }
+
+ //=========================================================================
+ // IntersectRayAABB
+ // [10/21/2009]
+ //=========================================================================
+ Intersect::RayAABBIsectTypes Intersect::IntersectRayAABB(
+ const Vector3& rayStart,
+ const Vector3& dir,
+ const Vector3& dirRCP,
+ const Aabb& aabb,
+ float& tStart,
+ float& tEnd,
+ Vector3& startNormal /*, Vector3& inter*/)
+ {
+ // we don't need to test with all 6 normals (just 3)
+
+ const float eps = 0.0001f; // \todo move to constant
+ float tmin = 0.0f; // set to -RR_FLT_MAX to get first hit on line
+ float tmax = std::numeric_limits::max(); // set to max distance ray can travel (for segment)
+
+ const Vector3& aabbMin = aabb.GetMin();
+ const Vector3& aabbMax = aabb.GetMax();
+
+ // we unroll manually because there is no way to get in efficient way vectors for
+ // each axis while getting it as a index
+ Vector3 time1 = (aabbMin - rayStart) * dirRCP;
+ Vector3 time2 = (aabbMax - rayStart) * dirRCP;
+
+ // X
+ if (std::fabs(dir.GetX()) < eps)
+ {
+ // Ray is parallel to slab. No hit if origin not within slab
+ if (rayStart.GetX() < aabbMin.GetX() || rayStart.GetX() > aabbMax.GetX())
{
- t2 = dcm;
- return 1;
+ return ISECT_RAY_AABB_NONE;
}
- else // impossible in theory
+ }
+ else
+ {
+ // Compute intersection t value of ray with near and far plane of slab
+ float t1 = time1.GetX();
+ float t2 = time2.GetX();
+ float nSign = -1.0f;
+
+ // Make t1 be intersection with near plane, t2 with far plane
+ if (t1 > t2)
+ {
+ AZStd::swap(t1, t2);
+ nSign = 1.0f;
+ }
+
+ // Compute the intersection of slab intersections intervals
+ if (tmin < t1)
+ {
+ tmin = t1;
+
+ startNormal.Set(nSign, 0.0f, 0.0f);
+ }
+
+ tmax = AZ::GetMin(tmax, t2);
+
+ // Exit with no collision as soon as slab intersection becomes empty
+ if (tmin > tmax)
+ {
+ return ISECT_RAY_AABB_NONE;
+ }
+ }
+
+ // Y
+ if (std::fabs(dir.GetY()) < eps)
+ {
+ // Ray is parallel to slab. No hit if origin not within slab
+ if (rayStart.GetY() < aabbMin.GetY() || rayStart.GetY() > aabbMax.GetY())
+ {
+ return ISECT_RAY_AABB_NONE;
+ }
+ }
+ else
+ {
+ // Compute intersection t value of ray with near and far plane of slab
+ float t1 = time1.GetY();
+ float t2 = time2.GetY();
+ float nSign = -1.0f;
+
+ // Make t1 be intersection with near plane, t2 with far plane
+ if (t1 > t2)
+ {
+ AZStd::swap(t1, t2);
+ nSign = 1.0f;
+ }
+
+ // Compute the intersection of slab intersections intervals
+ if (tmin < t1)
+ {
+ tmin = t1;
+
+ startNormal.Set(0.0f, nSign, 0.0f);
+ }
+
+ tmax = AZ::GetMin(tmax, t2);
+
+ // Exit with no collision as soon as slab intersection becomes empty
+ if (tmin > tmax)
+ {
+ return ISECT_RAY_AABB_NONE;
+ }
+ }
+
+ // Z
+ if (std::fabs(dir.GetZ()) < eps)
+ {
+ // Ray is parallel to slab. No hit if origin not within slab
+ if (rayStart.GetZ() < aabbMin.GetZ() || rayStart.GetZ() > aabbMax.GetZ())
+ {
+ return ISECT_RAY_AABB_NONE;
+ }
+ }
+ else
+ {
+ // Compute intersection t value of ray with near and far plane of slab
+ float t1 = time1.GetZ();
+ float t2 = time2.GetZ();
+ float nSign = -1.0f;
+
+ // Make t1 be intersection with near plane, t2 with far plane
+ if (t1 > t2)
+ {
+ AZStd::swap(t1, t2);
+ nSign = 1.0f;
+ }
+
+ // Compute the intersection of slab intersections intervals
+ if (tmin < t1)
+ {
+ tmin = t1;
+
+ startNormal.Set(0.0f, 0.0f, nSign);
+ }
+
+ tmax = AZ::GetMin(tmax, t2);
+
+ // Exit with no collision as soon as slab intersection becomes empty
+ if (tmin > tmax)
+ {
+ return ISECT_RAY_AABB_NONE;
+ }
+ }
+
+ tStart = tmin;
+ tEnd = tmax;
+
+ if (tmin == 0.0f) // no intersect if the segments starts inside or coincident the aabb
+ {
+ return ISECT_RAY_AABB_SA_INSIDE;
+ }
+
+ // Ray intersects all 3 slabs. Return point (q) and intersection t value (tmin)
+ // inter = rayStart + dir * tmin;
+ return ISECT_RAY_AABB_ISECT;
+ }
+
+ //=========================================================================
+ // IntersectRayAABB2
+ // [2/18/2011]
+ //=========================================================================
+ Intersect::RayAABBIsectTypes Intersect::IntersectRayAABB2(
+ const Vector3& rayStart, const Vector3& dirRCP, const Aabb& aabb, float& start, float& end)
+ {
+ float tmin, tmax, tymin, tymax, tzmin, tzmax;
+ Vector3 vZero = Vector3::CreateZero();
+
+ Vector3 min = (Vector3::CreateSelectCmpGreaterEqual(dirRCP, vZero, aabb.GetMin(), aabb.GetMax()) - rayStart) * dirRCP;
+ Vector3 max = (Vector3::CreateSelectCmpGreaterEqual(dirRCP, vZero, aabb.GetMax(), aabb.GetMin()) - rayStart) * dirRCP;
+
+ tmin = min.GetX();
+ tmax = max.GetX();
+ tymin = min.GetY();
+ tymax = max.GetY();
+
+ if (tmin > tymax || tymin > tmax)
+ {
+ return ISECT_RAY_AABB_NONE;
+ }
+
+ if (tymin > tmin)
+ {
+ tmin = tymin;
+ }
+
+ if (tymax < tmax)
+ {
+ tmax = tymax;
+ }
+
+ tzmin = min.GetZ();
+ tzmax = max.GetZ();
+
+ if (tmin > tzmax || tzmin > tmax)
+ {
+ return ISECT_RAY_AABB_NONE;
+ }
+
+ if (tzmin > tmin)
+ {
+ tmin = tzmin;
+ }
+ if (tzmax < tmax)
+ {
+ tmax = tzmax;
+ }
+
+ start = tmin;
+ end = tmax;
+
+ return ISECT_RAY_AABB_ISECT;
+ }
+
+ bool Intersect::IntersectRayDisk(
+ const Vector3& rayOrigin,
+ const Vector3& rayDir,
+ const Vector3& diskCenter,
+ const float diskRadius,
+ const Vector3& diskNormal,
+ float& t)
+ {
+ // First intersect with the plane of the disk
+ float planeIntersectionDistance;
+ int intersectionCount = IntersectRayPlane(rayOrigin, rayDir, diskCenter, diskNormal, planeIntersectionDistance);
+ if (intersectionCount == 1)
+ {
+ // If the plane intersection point is inside the disk radius, then it intersected the disk.
+ Vector3 pointOnPlane = rayOrigin + rayDir * planeIntersectionDistance;
+ if (pointOnPlane.GetDistance(diskCenter) < diskRadius)
+ {
+ t = planeIntersectionDistance;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Reference: Real-Time Collision Detection - 5.3.7 Intersecting Ray or Segment Against Cylinder, and the book's errata.
+ int Intersect::IntersectRayCappedCylinder(
+ const Vector3& rayOrigin,
+ const Vector3& rayDir,
+ const Vector3& cylinderEnd1,
+ const Vector3& cylinderDir,
+ float cylinderHeight,
+ float cylinderRadius,
+ float& t1,
+ float& t2)
+ {
+ // dr = rayDir
+ // dc = cylinderDir
+ // r = cylinderRadius
+ // Vector3 cylinderEnd2 = cylinderEnd1 + cylinderHeight * cylinderDir;
+ Vector3 m = rayOrigin - cylinderEnd1; // vector from cylinderEnd1 to rayOrigin
+ float dcm = cylinderDir.Dot(m); // projection of m on cylinderDir
+ float dcdr = cylinderDir.Dot(rayDir); // projection of rayDir on cylinderDir
+ float drm = rayDir.Dot(m); // projection of m on rayDir
+ float r2 = cylinderRadius * cylinderRadius;
+
+ if (dcm < 0.0f && dcdr <= 0.0f)
+ {
+ return 0; // rayOrigin is outside cylinderEnd1 and rayDir is pointing away from cylinderEnd1
+ }
+ if (dcm > cylinderHeight && dcdr >= 0.0f)
+ {
+ return 0; // rayOrigin is outside cylinderEnd2 and rayDir is pointing away from cylinderEnd2
+ }
+
+ // point RP on the ray: RP(t) = rayOrigin + t * rayDir
+ // point CP on the cylinder surface: |(CP - cylinderEnd1) - cylinderDir.Dot(cp - cylinderEnd1) * cylinderDir|^2 = cylinderRadius^2
+ // substitute RP(t) for CP: a*t^2 + 2b*t + c = 0, solving for t = [-2b +/- sqrt(4b^2 - 4ac)] / 2a
+ float a = 1.0f - dcdr * dcdr; // always greater than or equal to 0
+ float b = drm - dcm * dcdr;
+ float c = m.Dot(m) - dcm * dcm - r2;
+
+ const float EPSILON = 0.00001f;
+
+ if (fabsf(a) < EPSILON) // the ray is parallel to the cylinder
+ {
+ if (c > EPSILON) // the ray is outside the cylinder
{
return 0;
}
+ else if (dcm < 0.0f) // the ray origin is on cylinderEnd1 side and ray is pointing to cylinderEnd2
+ {
+ t1 = -dcm;
+ t2 = -dcm + cylinderHeight;
+ return 2;
+ }
+ else if (dcm > cylinderHeight) // the ray origin is on cylinderEnd2 side and ray is pointing to cylinderEnd1
+ {
+ t1 = dcm - cylinderHeight;
+ t2 = dcm;
+ return 2;
+ }
+ else // (dcm > 0.0f && dcm < cylinderHeight) // the ray origin is inside the cylinder
+ {
+ if (dcdr > 0.0f) // the ray is pointing to cylinderEnd2
+ {
+ t1 = cylinderHeight - dcm;
+ return 1;
+ }
+ else if (dcdr < 0.0f) // the ray is pointing to cylinderEnd1
+ {
+ t2 = dcm;
+ return 1;
+ }
+ else // impossible in theory
+ {
+ return 0;
+ }
+ }
}
- }
- float discr = b * b - a * c;
- if (discr < 0.0f)
- {
- return 0;
- }
-
- float sqrt_discr = sqrt(discr);
- float tt1 = (-b - sqrt_discr) / a;
- float tt2 = (-b + sqrt_discr) / a;
-
- if (tt2 < 0.0f) // both intersections are behind the ray origin
- {
- return 0;
- }
-
- // Vector3 AP2 = (rayOrigin + tt2 * rayDir) - cylinderEnd1; // vector from cylinderEnd1 to the intersecting point of parameter tt2
- // float s2 = cylinderDir.Dot(AP2);
- float s2 = dcm + tt2 * dcdr;
-
- if (discr < EPSILON) // tt1 == tt2
- {
- if (s2 >= 0.0f && s2 <= cylinderHeight)
- {
- t1 = tt1;
- return 1;
- }
- }
-
- // Vector3 AP1 = (rayOrigin + tt1 * rayDir) - cylinderEnd1; // vector from cylinderEnd1 to the intersecting point of parameter tt1
- // float s1 = cylinderDir.Dot(AP1);
- float s1 = dcm + tt1 * dcdr;
-
- if (s1 < 0.0f) // intersecting point of parameter tt1 is outside on cylinderEnd1 side
- {
- if (s2 < 0.0f) // intersecting point of parameter tt2 is outside on cylinderEnd1 side
+ float discr = b * b - a * c;
+ if (discr < 0.0f)
{
return 0;
}
- else if (s2 == 0.0f) // ray touching the brim of the cylinderEnd1
+
+ float sqrt_discr = sqrt(discr);
+ float tt1 = (-b - sqrt_discr) / a;
+ float tt2 = (-b + sqrt_discr) / a;
+
+ if (tt2 < 0.0f) // both intersections are behind the ray origin
{
- t1 = tt2;
- return 1;
+ return 0;
}
- else
+
+ // Vector3 AP2 = (rayOrigin + tt2 * rayDir) - cylinderEnd1; // vector from cylinderEnd1 to the intersecting point of parameter tt2
+ // float s2 = cylinderDir.Dot(AP2);
+ float s2 = dcm + tt2 * dcdr;
+
+ if (discr < EPSILON) // tt1 == tt2
{
- if (s2 > cylinderHeight) // intersecting point of parameter tt2 is outside on cylinderEnd2 side
+ if (s2 >= 0.0f && s2 <= cylinderHeight)
{
- // t2 can be computed from the equation: dot(rayOrigin + t2 * rayDir - cylinderEnd1, cylinderDir) = cylinderHeight
- t2 = (cylinderHeight - dcm) / dcdr;
+ t1 = tt1;
+ return 1;
}
- else
+ }
+
+ // Vector3 AP1 = (rayOrigin + tt1 * rayDir) - cylinderEnd1; // vector from cylinderEnd1 to the intersecting point of parameter tt1
+ // float s1 = cylinderDir.Dot(AP1);
+ float s1 = dcm + tt1 * dcdr;
+
+ if (s1 < 0.0f) // intersecting point of parameter tt1 is outside on cylinderEnd1 side
+ {
+ if (s2 < 0.0f) // intersecting point of parameter tt2 is outside on cylinderEnd1 side
{
- t2 = tt2;
+ return 0;
}
- if (dcm > 0.0f) // ray origin inside cylinder
+ else if (s2 == 0.0f) // ray touching the brim of the cylinderEnd1
{
- t1 = t2;
+ t1 = tt2;
return 1;
}
else
{
- // t1 can be computed from the equation: dot(rayOrigin + t1 * rayDir - cylinderEnd1, cylinderDir) = 0
- t1 = -dcm / dcdr;
- return 2;
+ if (s2 > cylinderHeight) // intersecting point of parameter tt2 is outside on cylinderEnd2 side
+ {
+ // t2 can be computed from the equation: dot(rayOrigin + t2 * rayDir - cylinderEnd1, cylinderDir) = cylinderHeight
+ t2 = (cylinderHeight - dcm) / dcdr;
+ }
+ else
+ {
+ t2 = tt2;
+ }
+ if (dcm > 0.0f) // ray origin inside cylinder
+ {
+ t1 = t2;
+ return 1;
+ }
+ else
+ {
+ // t1 can be computed from the equation: dot(rayOrigin + t1 * rayDir - cylinderEnd1, cylinderDir) = 0
+ t1 = -dcm / dcdr;
+ return 2;
+ }
}
}
- }
- else if (s1 > cylinderHeight) // intersecting point of parameter tt1 is outside on cylinderEnd2 side
- {
- if (s2 > cylinderHeight) // intersecting point of parameter tt2 is outside on cylinderEnd2 side
+ else if (s1 > cylinderHeight) // intersecting point of parameter tt1 is outside on cylinderEnd2 side
{
- return 0;
+ if (s2 > cylinderHeight) // intersecting point of parameter tt2 is outside on cylinderEnd2 side
+ {
+ return 0;
+ }
+ else if (s2 == cylinderHeight)
+ {
+ t1 = tt2;
+ return 1;
+ }
+ else
+ {
+ if (s2 < 0.0f)
+ {
+ t2 = -dcm / dcdr;
+ }
+ else
+ {
+ t2 = tt2;
+ }
+ if (dcm < cylinderHeight)
+ {
+ t1 = t2;
+ return 1;
+ }
+ else
+ {
+ t1 = (cylinderHeight - dcm) / dcdr;
+ return 2;
+ }
+ }
}
- else if (s2 == cylinderHeight)
- {
- t1 = tt2;
- return 1;
- }
- else
+ else // intersecting point of parameter tt1 is in between two cylinder ends
{
if (s2 < 0.0f)
{
t2 = -dcm / dcdr;
}
+ else if (s2 > cylinderHeight)
+ {
+ t2 = (cylinderHeight - dcm) / dcdr;
+ }
else
{
t2 = tt2;
}
- if (dcm < cylinderHeight)
+ if (tt1 > 0.0f)
+ {
+ t1 = tt1;
+ return 2;
+ }
+ else
{
t1 = t2;
return 1;
}
- else
- {
- t1 = (cylinderHeight - dcm) / dcdr;
- return 2;
- }
}
}
- else // intersecting point of parameter tt1 is in between two cylinder ends
+
+ int Intersect::IntersectRayCone(
+ const Vector3& rayOrigin,
+ const Vector3& rayDir,
+ const Vector3& coneApex,
+ const Vector3& coneDir,
+ float coneHeight,
+ float coneBaseRadius,
+ float& t1,
+ float& t2)
{
- if (s2 < 0.0f)
+ // Q = rayOrgin, A = coneApex
+ Vector3 AQ = rayOrigin - coneApex;
+ float m = coneDir.Dot(AQ); // projection of m on cylinderDir
+ float k = coneDir.Dot(rayDir); // projection of rayDir on cylinderDir
+
+ if (m < 0.0f && k <= 0.0f)
{
- t2 = -dcm / dcdr;
+ // rayOrigin is outside the cone on coneApex side and rayDir is pointing away
+ return 0;
}
- else if (s2 > cylinderHeight)
- {
- t2 = (cylinderHeight - dcm) / dcdr;
- }
- else
- {
- t2 = tt2;
- }
- if (tt1 > 0.0f)
- {
- t1 = tt1;
- return 2;
- }
- else
- {
- t1 = t2;
- return 1;
- }
- }
-}
-
-int AZ::Intersect::IntersectRayCone(
- const Vector3& rayOrigin, const Vector3& rayDir,
- const Vector3& coneApex, const Vector3& coneDir, float coneHeight,
- float coneBaseRadius, float& t1, float& t2)
-{
- // Q = rayOrgin, A = coneApex
- Vector3 AQ = rayOrigin - coneApex;
- float m = coneDir.Dot(AQ); // projection of m on cylinderDir
- float k = coneDir.Dot(rayDir); // projection of rayDir on cylinderDir
-
- if (m < 0.0f && k <= 0.0f)
- {
- // rayOrigin is outside the cone on coneApex side and rayDir is pointing away
- return 0;
- }
- if (m > coneHeight && k >= 0.0f)
- {
- // rayOrigin is outside the cone on coneBase side and rayDir is pointing away
- return 0;
- }
-
- float r2 = coneBaseRadius * coneBaseRadius;
- float h2 = coneHeight * coneHeight;
-
- float m2 = m * m;
- float k2 = k * k;
- float q2 = AQ.Dot(AQ);
-
- float n = rayDir.Dot(AQ);
-
- const float EPSILON = 0.00001f;
-
- // point RP on the ray: RP(t) = rayOrigin + t * rayDir
- // point CP on the cone surface: similar triangle property
- // |dot(CP - A, coneDir) * coneDir| / coneHeight = |(CP - A) - (dot(CP - A, coneDir) * coneDir)| coneRadius
- // substitute RP(t) for CP: a*t^2 + 2b*t + c = 0, solving for t
- float a = (r2 + h2) * k2 - h2;
- float b = (r2 + h2) * m * k - h2 * n;
- float c = (r2 + h2) * m2 - h2 * q2;
-
- float discriminant = b * b - a * c;
- if (discriminant < -EPSILON)
- {
- return 0;
- }
- discriminant = AZ::GetMax(discriminant, 0.0f);
-
- if (fabsf(a) < EPSILON) // the ray is parallel to the cone surface's tangent line
- {
- if (b < EPSILON && fabsf(c) < EPSILON) // ray overlapping with cone surface
- {
- t1 = rayDir.Dot(coneApex - rayOrigin);
- }
- else // ray has only one intersecting point with the cone
- {
- t1 = -c / (2 * b);
- }
-
- t2 = (coneHeight - m) / k; // t2 can be computed from the equation: dot(Q + t2 * rayDir - A, coneDir) = coneHeight
-
- if (t1 < 0.0f && t2 < 0.0f)
+ if (m > coneHeight && k >= 0.0f)
{
+ // rayOrigin is outside the cone on coneBase side and rayDir is pointing away
return 0;
}
- if (fabsf(t1 - t2) < EPSILON) // the ray intersects the brim of the circumference of the cone base
- {
- return 1;
- }
+ float r2 = coneBaseRadius * coneBaseRadius;
+ float h2 = coneHeight * coneHeight;
- float s1 = m + t1 * k; // coneDir.Dot(rayOrigin + t1 * rayDir - coneApex);
- if (s1 < 0.0f || s1 > coneHeight)
+ float m2 = m * m;
+ float k2 = k * k;
+ float q2 = AQ.Dot(AQ);
+
+ float n = rayDir.Dot(AQ);
+
+ const float EPSILON = 0.00001f;
+
+ // point RP on the ray: RP(t) = rayOrigin + t * rayDir
+ // point CP on the cone surface: similar triangle property
+ // |dot(CP - A, coneDir) * coneDir| / coneHeight = |(CP - A) - (dot(CP - A, coneDir) * coneDir)| coneRadius
+ // substitute RP(t) for CP: a*t^2 + 2b*t + c = 0, solving for t
+ float a = (r2 + h2) * k2 - h2;
+ float b = (r2 + h2) * m * k - h2 * n;
+ float c = (r2 + h2) * m2 - h2 * q2;
+
+ float discriminant = b * b - a * c;
+ if (discriminant < -EPSILON)
{
return 0;
}
- else
+ discriminant = AZ::GetMax(discriminant, 0.0f);
+
+ if (fabsf(a) < EPSILON) // the ray is parallel to the cone surface's tangent line
{
- if (k < 0.0f) // ray shooting from base to apex
+ if (b < EPSILON && fabsf(c) < EPSILON) // ray overlapping with cone surface
{
- if (m >= coneHeight) // ray origin outside cone
- {
- float temp = t1;
- t1 = t2;
- t2 = temp;
- return 2;
- }
- else if (t1 >= 0.0f) // ray origin inside cone
- {
- t1 = t2;
- return 1;
- }
- else
- {
- return 0;
- }
+ t1 = rayDir.Dot(coneApex - rayOrigin);
+ }
+ else // ray has only one intersecting point with the cone
+ {
+ t1 = -c / (2 * b);
+ }
+
+ t2 = (coneHeight - m) / k; // t2 can be computed from the equation: dot(Q + t2 * rayDir - A, coneDir) = coneHeight
+
+ if (t1 < 0.0f && t2 < 0.0f)
+ {
+ return 0;
+ }
+
+ if (fabsf(t1 - t2) < EPSILON) // the ray intersects the brim of the circumference of the cone base
+ {
+ return 1;
+ }
+
+ float s1 = m + t1 * k; // coneDir.Dot(rayOrigin + t1 * rayDir - coneApex);
+ if (s1 < 0.0f || s1 > coneHeight)
+ {
+ return 0;
}
else
{
- if (m > coneHeight)
+ if (k < 0.0f) // ray shooting from base to apex
{
- return 0;
- }
- if (t1 >= 0.0f) // ray origin outside cone
- {
- return 2;
- }
- else
- {
- t1 = t2;
- return 1;
- }
- }
- }
- }
-
- if (discriminant < EPSILON) // two intersecting points coincide
- {
- if (fabsf(n * n - q2) < EPSILON) // the ray is through the apex
- {
- float cosineA2 = h2 / (r2 + h2);
- float cosineAQ2 = cosineA2 * q2;
-
- if (m2 > cosineAQ2) // the ray origin is inside the cone or its mirroring counterpart
- {
- if (m <= 0.0f) // the ray origin outside the cone on the apex side, shooting towards the base
- {
- t1 = -b / a;
- t2 = (coneHeight - m) / k;
- return 2;
- }
- else if (m >= coneHeight) // the ray origin is outside the cone on the base side, shooting towards towards the apex
- {
- t1 = (coneHeight - m) / k;
- t2 = -b / a;
- return 2;
- }
- else
- {
- if (k > 0.0f) // the ray origin is inside the cone, shooting towards the base
+ if (m >= coneHeight) // ray origin outside cone
{
- t1 = (coneHeight - m) / k;
+ float temp = t1;
+ t1 = t2;
+ t2 = temp;
+ return 2;
+ }
+ else if (t1 >= 0.0f) // ray origin inside cone
+ {
+ t1 = t2;
return 1;
}
- else // the ray origin is inside the cone, shooting towards the apex
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ if (m > coneHeight)
+ {
+ return 0;
+ }
+ if (t1 >= 0.0f) // ray origin outside cone
+ {
+ return 2;
+ }
+ else
+ {
+ t1 = t2;
+ return 1;
+ }
+ }
+ }
+ }
+
+ if (discriminant < EPSILON) // two intersecting points coincide
+ {
+ if (fabsf(n * n - q2) < EPSILON) // the ray is through the apex
+ {
+ float cosineA2 = h2 / (r2 + h2);
+ float cosineAQ2 = cosineA2 * q2;
+
+ if (m2 > cosineAQ2) // the ray origin is inside the cone or its mirroring counterpart
+ {
+ if (m <= 0.0f) // the ray origin outside the cone on the apex side, shooting towards the base
{
t1 = -b / a;
+ t2 = (coneHeight - m) / k;
+ return 2;
+ }
+ else if (m >= coneHeight) // the ray origin is outside the cone on the base side, shooting towards towards the apex
+ {
+ t1 = (coneHeight - m) / k;
+ t2 = -b / a;
+ return 2;
+ }
+ else
+ {
+ if (k > 0.0f) // the ray origin is inside the cone, shooting towards the base
+ {
+ t1 = (coneHeight - m) / k;
+ return 1;
+ }
+ else // the ray origin is inside the cone, shooting towards the apex
+ {
+ t1 = -b / a;
+ return 1;
+ }
+ }
+ }
+ else // the ray origin is outside the cone
+ {
+ t1 = -b / a;
+ if (t1 > 0.0f)
+ {
return 1;
}
+ else
+ {
+ return 0;
+ }
}
}
- else // the ray origin is outside the cone
+ else // the ray is touching the cone surface but not through the apex
{
t1 = -b / a;
if (t1 > 0.0f)
{
+ float s1 = m + t1 * k; // projection length of the line segment from the apex to intersection_t1 onto the coneDir
+ if (s1 >= 0.0f && s1 <= coneHeight)
+ {
+ return 1;
+ }
+ }
+ return 0;
+ }
+ }
+
+ float sqrtDiscr = sqrt(discriminant);
+ float tt1 = (-b - sqrtDiscr) / a;
+ float tt2 = (-b + sqrtDiscr) / a;
+
+ /* Test s1 and s2 to see the positions of the intersecting points relative to the cylinder's two ends. */
+
+ // s1 = coneDir.Dot(rayOrigin + tt1 * rayDir - coneApex), which expands into the following
+ float s1 = m + tt1 * k;
+ // s2 = coneDir.Dot(rayOrigin + tt2 * rayDir - coneApex), which expands into the following
+ float s2 = m + tt2 * k;
+
+ if (s1 < 0.0f)
+ {
+ if (s2 < 0.0f || s2 > coneHeight)
+ {
+ return 0;
+ }
+ else
+ {
+ if (tt2 >= 0.0f) // ray origin outside cone
+ {
+ t1 = tt2;
+ t2 = (coneHeight - m) / k;
+ return 2;
+ }
+ else if (m > coneHeight) // ray origin outside cone on the base side, the
+ {
+ return 0;
+ }
+ else
+ {
+ t1 = (coneHeight - m) / k;
+ return 1;
+ }
+ }
+ }
+ else if (s1 > coneHeight)
+ {
+ if (s2 < 0.0f || s2 > coneHeight)
+ {
+ return 0;
+ }
+ else
+ {
+ if (tt2 < 0.0f)
+ {
+ return 0;
+ }
+ else if (m >= coneHeight)
+ {
+ t1 = (coneHeight - m) / k;
+ t2 = tt2;
+ return 2;
+ }
+ else // ray origin inside cone
+ {
+ t1 = tt2;
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ if (s2 < 0.0f)
+ {
+ if (m >= coneHeight)
+ {
+ t1 = (coneHeight - m) / k;
+ t2 = tt1;
+ return 2;
+ }
+ else if (tt1 >= 0.0f) // ray origin inside cone
+ {
+ t1 = tt1;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else if (s2 > coneHeight)
+ {
+ if (tt1 >= 0.0f)
+ {
+ t1 = tt1;
+ t2 = (coneHeight - m) / k;
+ return 2;
+ }
+ else if (m <= coneHeight)
+ {
+ t1 = (coneHeight - m) / k;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ else
+ {
+ if (tt1 >= 0.0f)
+ {
+ t1 = tt1;
+ t2 = tt2;
+ return 2;
+ }
+ else if (tt2 >= 0.0f)
+ {
+ t1 = tt2;
return 1;
}
else
@@ -788,778 +946,670 @@ int AZ::Intersect::IntersectRayCone(
}
}
}
- else // the ray is touching the cone surface but not through the apex
+ }
+
+ int Intersect::IntersectRayPlane(
+ const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& planePos, const Vector3& planeNormal, float& t)
+ {
+ // (rayOrigin + t * rayDir - planePos).dot(planeNormal) = 0
+
+ const float EPSILON = 0.00001f;
+
+ float n = rayDir.Dot(planeNormal);
+ if (fabsf(n) < EPSILON)
{
- t1 = -b / a;
- if (t1 > 0.0f)
- {
- float s1 = m + t1 * k; // projection length of the line segment from the apex to intersection_t1 onto the coneDir
- if (s1 >= 0.0f && s1 <= coneHeight)
- {
- return 1;
- }
- }
return 0;
}
- }
-
- float sqrtDiscr = sqrt(discriminant);
- float tt1 = (-b - sqrtDiscr) / a;
- float tt2 = (-b + sqrtDiscr) / a;
- /* Test s1 and s2 to see the positions of the intersecting points relative to the cylinder's two ends. */
-
- // s1 = coneDir.Dot(rayOrigin + tt1 * rayDir - coneApex), which expands into the following
- float s1 = m + tt1 * k;
- // s2 = coneDir.Dot(rayOrigin + tt2 * rayDir - coneApex), which expands into the following
- float s2 = m + tt2 * k;
-
- if (s1 < 0.0f)
- {
- if (s2 < 0.0f || s2 > coneHeight)
+ t = planeNormal.Dot(planePos - rayOrigin) / n;
+ if (t < 0.0f)
{
return 0;
}
else
{
- if (tt2 >= 0.0f) // ray origin outside cone
- {
- t1 = tt2;
- t2 = (coneHeight - m) / k;
- return 2;
- }
- else if (m > coneHeight) // ray origin outside cone on the base side, the
- {
- return 0;
- }
- else
- {
- t1 = (coneHeight - m) / k;
- return 1;
- }
+ return 1;
}
}
- else if (s1 > coneHeight)
+
+ int Intersect::IntersectRayQuad(
+ const Vector3& rayOrigin,
+ const Vector3& rayDir,
+ const Vector3& vertexA,
+ const Vector3& vertexB,
+ const Vector3& vertexC,
+ const Vector3& vertexD,
+ float& t)
{
- if (s2 < 0.0f || s2 > coneHeight )
+ const float EPSILON = 0.0001f;
+
+ Vector3 AC = vertexC - vertexA;
+ Vector3 AB = vertexB - vertexA;
+ Vector3 QA = vertexA - rayOrigin;
+
+ Vector3 triN = AB.Cross(AC); // the normal of the triangle ABC
+ float dn = rayDir.Dot(triN);
+
+ // Early-out if ray is facing away from ABC triangle
+ if (dn * triN.Dot(QA) < 0)
{
return 0;
}
- else
+
+ Vector3 E = rayDir.Cross(QA);
+ float dnAbs = 0.0f;
+
+ if (dn < -EPSILON) // vertices have counter-clock wise winding when looking at the quad from rayOrigin
{
- if (tt2 < 0.0f)
- {
- return 0;
- }
- else if (m >= coneHeight)
- {
- t1 = (coneHeight - m) / k;
- t2 = tt2;
- return 2;
- }
- else // ray origin inside cone
- {
- t1 = tt2;
- return 1;
- }
+ dnAbs = -dn;
}
- }
- else
- {
- if (s2 < 0.0f)
+ else if (dn > EPSILON)
{
- if (m >= coneHeight)
- {
- t1 = (coneHeight - m) / k;
- t2 = tt1;
- return 2;
- }
- else if (tt1 >= 0.0f) // ray origin inside cone
- {
- t1 = tt1;
- return 1;
- }
- else
+ E = -E;
+ dnAbs = dn;
+ }
+ else // the ray is parallel to the quad plane
+ {
+ return 0;
+ }
+
+ // compute barycentric coordinates
+ float v = E.Dot(AC);
+
+ if (v >= 0.0f && v < dnAbs)
+ {
+ float w = -E.Dot(AB);
+ if (w < 0.0f || v + w > dnAbs)
{
return 0;
}
}
- else if (s2 > coneHeight)
+ else if (v < 0.0f && v > -dnAbs)
{
- if (tt1 >= 0.0f)
- {
- t1 = tt1;
- t2 = (coneHeight - m) / k;
- return 2;
- }
- else if (m <= coneHeight)
- {
- t1 = (coneHeight - m) / k;
- return 1;
- }
- else
+ Vector3 DA = vertexA - vertexD;
+ float w = E.Dot(DA);
+ if (w > 0.0f || v + w < -dnAbs) // v, w are negative
{
return 0;
}
}
else
{
- if (tt1 >= 0.0f)
- {
- t1 = tt1;
- t2 = tt2;
- return 2;
- }
- else if (tt2 >= 0.0f)
- {
- t1 = tt2;
- return 1;
- }
- else
- {
- return 0;
- }
+ return 0;
}
- }
-}
-int AZ::Intersect::IntersectRayPlane(const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& planePos, const Vector3& planeNormal, float& t)
-{
- // (rayOrigin + t * rayDir - planePos).dot(planeNormal) = 0
-
- const float EPSILON = 0.00001f;
-
- float n = rayDir.Dot(planeNormal);
- if (fabsf(n) < EPSILON)
- {
- return 0;
- }
-
- t = planeNormal.Dot(planePos - rayOrigin) / n;
- if (t < 0.0f)
- {
- return 0;
- }
- else
- {
+ t = triN.Dot(QA) / dn;
return 1;
}
-}
-int AZ::Intersect::IntersectRayQuad(
- const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& vertexA,
- const Vector3& vertexB, const Vector3& vertexC, const Vector3& vertexD, float& t)
-{
- const float EPSILON = 0.0001f;
-
- Vector3 AC = vertexC - vertexA;
- Vector3 AB = vertexB - vertexA;
- Vector3 QA = vertexA - rayOrigin;
-
- Vector3 triN = AB.Cross(AC); // the normal of the triangle ABC
- float dn = rayDir.Dot(triN);
-
- // Early-out if ray is facing away from ABC triangle
- if (dn * triN.Dot(QA) < 0)
+ // reference: Real-Time Collision Detection, 5.3.3 Intersecting Ray or Segment Against Box
+ bool Intersect::IntersectRayBox(
+ const Vector3& rayOrigin,
+ const Vector3& rayDir,
+ const Vector3& boxCenter,
+ const Vector3& boxAxis1,
+ const Vector3& boxAxis2,
+ const Vector3& boxAxis3,
+ float boxHalfExtent1,
+ float boxHalfExtent2,
+ float boxHalfExtent3,
+ float& t)
{
- return 0;
- }
+ const float EPSILON = 0.00001f;
- Vector3 E = rayDir.Cross(QA);
- float dnAbs = 0.0f;
+ float tmin = 0.0f; // the nearest to the ray origin
+ float tmax = AZ::Constants::FloatMax; // the farthest from the ray origin
- if (dn < -EPSILON) // vertices have counter-clock wise winding when looking at the quad from rayOrigin
- {
- dnAbs = -dn;
- }
- else if (dn > EPSILON)
- {
- E = -E;
- dnAbs = dn;
- }
- else // the ray is parallel to the quad plane
- {
- return 0;
- }
+ Vector3 P = boxCenter - rayOrigin; // precomputed variable for calculating the vector from rayOrigin to a point on each box facet
+ Vector3 QAp; // vector from rayOrigin to the center of the facet of boxAxis
+ Vector3 QAn; // vector from rayOrigin to the center of the facet of -boxAxis
+ float tp = 0.0f;
+ float tn = 0.0f;
+ bool isRayOriginInsideBox = true;
- // compute barycentric coordinates
- float v = E.Dot(AC);
+ /* Test the slab_1 formed by the planes with normals boxAxis1 and -boxAxis1. */
- if (v >= 0.0f && v < dnAbs)
- {
- float w = -E.Dot(AB);
- if (w < 0.0f || v + w > dnAbs)
+ Vector3 axis1 = boxHalfExtent1 * boxAxis1;
+
+ QAp = P + axis1;
+ tp = QAp.Dot(boxAxis1);
+
+ QAn = P - axis1;
+ tn = -QAn.Dot(boxAxis1);
+
+ float n = rayDir.Dot(boxAxis1);
+ if (fabsf(n) < EPSILON)
{
- return 0;
- }
- }
- else if (v < 0.0f && v > -dnAbs)
- {
- Vector3 DA = vertexA - vertexD;
- float w = E.Dot(DA);
- if (w > 0.0f || v + w < -dnAbs) // v, w are negative
- {
- return 0;
- }
- }
- else
- {
- return 0;
- }
-
- t = triN.Dot(QA) / dn;
- return 1;
-}
-
-// reference: Real-Time Collision Detection, 5.3.3 Intersecting Ray or Segment Against Box
-bool AZ::Intersect::IntersectRayBox(
- const Vector3& rayOrigin, const Vector3& rayDir, const Vector3& boxCenter, const Vector3& boxAxis1,
- const Vector3& boxAxis2, const Vector3& boxAxis3, float boxHalfExtent1, float boxHalfExtent2, float boxHalfExtent3, float& t)
-{
- const float EPSILON = 0.00001f;
-
- float tmin = 0.0f; // the nearest to the ray origin
- float tmax = AZ::Constants::FloatMax; // the farthest from the ray origin
-
- Vector3 P = boxCenter - rayOrigin; // precomputed variable for calculating the vector from rayOrigin to a point on each box facet
- Vector3 QAp; // vector from rayOrigin to the center of the facet of boxAxis
- Vector3 QAn; // vector from rayOrigin to the center of the facet of -boxAxis
- float tp = 0.0f;
- float tn = 0.0f;
- bool isRayOriginInsideBox = true;
-
- /* Test the slab_1 formed by the planes with normals boxAxis1 and -boxAxis1. */
-
- Vector3 axis1 = boxHalfExtent1 * boxAxis1;
-
- QAp = P + axis1;
- tp = QAp.Dot(boxAxis1);
-
- QAn = P - axis1;
- tn = -QAn.Dot(boxAxis1);
-
- float n = rayDir.Dot(boxAxis1);
- if (fabsf(n) < EPSILON)
- {
- // If the ray is parallel to the slab and the ray origin is outside, return no intersection.
- if (tp < 0.0f || tn < 0.0f)
- {
- return false;
- }
- }
- else
- {
- if (tp < 0.0f || tn < 0.0f)
- {
- isRayOriginInsideBox = false;
- }
-
- float div = 1.0f / n;
- float t1 = tp * div;
- float t2 = tn * (-div);
- if (t1 > t2)
- {
- AZStd::swap(t1, t2);
- }
- tmin = AZ::GetMax(tmin, t1);
- tmax = AZ::GetMin(tmax, t2);
- if (tmin > tmax)
- {
- return false;
- }
- }
-
- /* test the slab_2 formed by plane with normals boxAxis2 and -boxAxis2 */
-
- Vector3 axis2 = boxHalfExtent2 * boxAxis2;
-
- QAp = P + axis2;
- tp = QAp.Dot(boxAxis2);
-
- QAn = P - axis2;
- tn = -QAn.Dot(boxAxis2);
-
- n = rayDir.Dot(boxAxis2);
- if (fabsf(n) < EPSILON)
- {
- // If the ray is parallel to the slab and the ray origin is outside, return no intersection.
- if (tp < 0.0f || tn < 0.0f)
- {
- return false;
- }
- }
- else
- {
- if (tp < 0.0f || tn < 0.0f)
- {
- isRayOriginInsideBox = false;
- }
-
- float div = 1.0f / n;
- float t1 = tp * div;
- float t2 = tn * (-div);
- if (t1 > t2)
- {
- AZStd::swap(t1, t2);
- }
- tmin = AZ::GetMax(tmin, t1);
- tmax = AZ::GetMin(tmax, t2);
- if (tmin > tmax)
- {
- return false;
- }
- }
-
- /* test the slab_3 formed by plane with normals boxAxis3 and -boxAxis3 */
-
- Vector3 axis3 = boxHalfExtent3 * boxAxis3;
-
- QAp = P + axis3;
- tp = QAp.Dot(boxAxis3);
-
- QAn = P - axis3;
- tn = -QAn.Dot(boxAxis3);
-
- n = rayDir.Dot(boxAxis3);
- if (fabsf(n) < EPSILON)
- {
- // If the ray is parallel to the slab and the ray origin is outside, return no intersection.
- if (tp < 0.0f || tn < 0.0f)
- {
- return false;
- }
- }
- else
- {
- if (tp < 0.0f || tn < 0.0f)
- {
- isRayOriginInsideBox = false;
- }
-
- float div = 1.0f / n;
- float t1 = tp * div;
- float t2 = tn * (-div);
- if (t1 > t2)
- {
- AZStd::swap(t1, t2);
- }
- tmin = AZ::GetMax(tmin, t1);
- tmax = AZ::GetMin(tmax, t2);
- if (tmin > tmax)
- {
- return false;
- }
- }
-
- t = (isRayOriginInsideBox ? tmax : tmin);
- return true;
-}
-
-bool AZ::Intersect::IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t)
-{
- return AZ::Intersect::IntersectRayBox(rayOrigin, rayDir, obb.GetPosition(),
- obb.GetAxisX(), obb.GetAxisY(), obb.GetAxisZ(),
- obb.GetHalfLengthX(), obb.GetHalfLengthY(), obb.GetHalfLengthZ(), t);
-}
-
-//=========================================================================
-// IntersectSegmentCylinder
-// [10/21/2009]
-//=========================================================================
-CylinderIsectTypes
-AZ::Intersect::IntersectSegmentCylinder(
- const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t)
-{
- const float epsilon = 0.001f;
- Vector3 d = q - p; // can be cached
- Vector3 m = sa - p; // -"-
- Vector3 n = /*sb - sa*/ dir; // -"-
-
- float md = m.Dot(d);
- float nd = n.Dot(d);
- float dd = d.Dot(d);
-
- // Test if segment fully outside either endcap of cylinder
- if (md < 0.0f && md + nd < 0.0f)
- {
- return RR_ISECT_RAY_CYL_NONE; // Segment outside 'p' side of cylinder
- }
- if (md > dd && md + nd > dd)
- {
- return RR_ISECT_RAY_CYL_NONE; // Segment outside 'q' side of cylinder
- }
- float nn = n.Dot(n);
- float mn = m.Dot(n);
- float a = dd * nn - nd * nd;
- float k = m.Dot(m) - r * r;
- float c = dd * k - md * md;
- if (std::fabs(a) < epsilon)
- {
- // Segment runs parallel to cylinder axis
- if (c > 0.0f)
- {
- return RR_ISECT_RAY_CYL_NONE; // 'a' and thus the segment lie outside cylinder
- }
- // Now known that segment intersects cylinder; figure out how it intersects
- if (md < 0.0f)
- {
- t = -mn / nn; // Intersect segment against 'p' endcap
- return RR_ISECT_RAY_CYL_P_SIDE;
- }
- else if (md > dd)
- {
- t = (nd - mn) / nn; // Intersect segment against 'q' endcap
- return RR_ISECT_RAY_CYL_Q_SIDE;
+ // If the ray is parallel to the slab and the ray origin is outside, return no intersection.
+ if (tp < 0.0f || tn < 0.0f)
+ {
+ return false;
+ }
}
else
{
- // 'a' lies inside cylinder
- t = 0.0f;
- return RR_ISECT_RAY_CYL_SA_INSIDE;
- }
- }
- float b = dd * mn - nd * md;
- float discr = b * b - a * c;
- if (discr < 0.0f)
- {
- return RR_ISECT_RAY_CYL_NONE; // No real roots; no intersection
- }
- t = (-b - Sqrt(discr)) / a;
- CylinderIsectTypes result = RR_ISECT_RAY_CYL_PQ; // default along the PQ segment
+ if (tp < 0.0f || tn < 0.0f)
+ {
+ isRayOriginInsideBox = false;
+ }
- if (md + t * nd < 0.0f)
- {
- // Intersection outside cylinder on 'p' side
- if (nd <= 0.0f)
- {
- return RR_ISECT_RAY_CYL_NONE; // Segment pointing away from endcap
+ float div = 1.0f / n;
+ float t1 = tp * div;
+ float t2 = tn * (-div);
+ if (t1 > t2)
+ {
+ AZStd::swap(t1, t2);
+ }
+ tmin = AZ::GetMax(tmin, t1);
+ tmax = AZ::GetMin(tmax, t2);
+ if (tmin > tmax)
+ {
+ return false;
+ }
}
- float t0 = -md / nd;
- // Keep intersection if Dot(S(t) - p, S(t) - p) <= r^2
- if (k + t0 * (2.0f * mn + t0 * nn) <= 0.0f)
+
+ /* test the slab_2 formed by plane with normals boxAxis2 and -boxAxis2 */
+
+ Vector3 axis2 = boxHalfExtent2 * boxAxis2;
+
+ QAp = P + axis2;
+ tp = QAp.Dot(boxAxis2);
+
+ QAn = P - axis2;
+ tn = -QAn.Dot(boxAxis2);
+
+ n = rayDir.Dot(boxAxis2);
+ if (fabsf(n) < EPSILON)
{
- // if( t0 < 0.0f ) t0 = 0.0f; // it's inside the cylinder
- t = t0;
- result = RR_ISECT_RAY_CYL_P_SIDE;
+ // If the ray is parallel to the slab and the ray origin is outside, return no intersection.
+ if (tp < 0.0f || tn < 0.0f)
+ {
+ return false;
+ }
}
else
{
- return RR_ISECT_RAY_CYL_NONE;
+ if (tp < 0.0f || tn < 0.0f)
+ {
+ isRayOriginInsideBox = false;
+ }
+
+ float div = 1.0f / n;
+ float t1 = tp * div;
+ float t2 = tn * (-div);
+ if (t1 > t2)
+ {
+ AZStd::swap(t1, t2);
+ }
+ tmin = AZ::GetMax(tmin, t1);
+ tmax = AZ::GetMin(tmax, t2);
+ if (tmin > tmax)
+ {
+ return false;
+ }
}
- }
- else if (md + t * nd > dd)
- {
- // Intersection outside cylinder on 'q' side
- if (nd >= 0.0f)
+
+ /* test the slab_3 formed by plane with normals boxAxis3 and -boxAxis3 */
+
+ Vector3 axis3 = boxHalfExtent3 * boxAxis3;
+
+ QAp = P + axis3;
+ tp = QAp.Dot(boxAxis3);
+
+ QAn = P - axis3;
+ tn = -QAn.Dot(boxAxis3);
+
+ n = rayDir.Dot(boxAxis3);
+ if (fabsf(n) < EPSILON)
{
- return RR_ISECT_RAY_CYL_NONE; // Segment pointing away from endcap
- }
- float t0 = (dd - md) / nd;
- // Keep intersection if Dot(S(t) - q, S(t) - q) <= r^2
- if (k + dd - 2.0f * md + t0 * (2.0f * (mn - nd) + t0 * nn) <= 0.0f)
- {
- // if( t0 < 0.0f ) t0 = 0.0f; // it's inside the cylinder
- t = t0;
- result = RR_ISECT_RAY_CYL_Q_SIDE;
+ // If the ray is parallel to the slab and the ray origin is outside, return no intersection.
+ if (tp < 0.0f || tn < 0.0f)
+ {
+ return false;
+ }
}
else
{
- return RR_ISECT_RAY_CYL_NONE;
+ if (tp < 0.0f || tn < 0.0f)
+ {
+ isRayOriginInsideBox = false;
+ }
+
+ float div = 1.0f / n;
+ float t1 = tp * div;
+ float t2 = tn * (-div);
+ if (t1 > t2)
+ {
+ AZStd::swap(t1, t2);
+ }
+ tmin = AZ::GetMax(tmin, t1);
+ tmax = AZ::GetMin(tmax, t2);
+ if (tmin > tmax)
+ {
+ return false;
+ }
}
+
+ t = (isRayOriginInsideBox ? tmax : tmin);
+ return true;
}
- // Segment intersects cylinder between the end-caps; t is correct
- if (t > 1.0f)
+ bool Intersect::IntersectRayObb(const Vector3& rayOrigin, const Vector3& rayDir, const Obb& obb, float& t)
{
- return RR_ISECT_RAY_CYL_NONE; // Intersection lies outside segment
+ return Intersect::IntersectRayBox(
+ rayOrigin, rayDir, obb.GetPosition(), obb.GetAxisX(), obb.GetAxisY(), obb.GetAxisZ(), obb.GetHalfLengthX(),
+ obb.GetHalfLengthY(), obb.GetHalfLengthZ(), t);
}
- else if (t < 0.0f)
+
+ //=========================================================================
+ // IntersectSegmentCylinder
+ // [10/21/2009]
+ //=========================================================================
+ Intersect::CylinderIsectTypes Intersect::IntersectSegmentCylinder(
+ const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t)
{
- if (c <= 0.0f)
+ const float epsilon = 0.001f;
+ Vector3 d = q - p; // can be cached
+ Vector3 m = sa - p; // -"-
+ Vector3 n = /*sb - sa*/ dir; // -"-
+
+ float md = m.Dot(d);
+ float nd = n.Dot(d);
+ float dd = d.Dot(d);
+
+ // Test if segment fully outside either endcap of cylinder
+ if (md < 0.0f && md + nd < 0.0f)
{
- t = 0.0f;
- return RR_ISECT_RAY_CYL_SA_INSIDE; // Segment starts inside
+ return RR_ISECT_RAY_CYL_NONE; // Segment outside 'p' side of cylinder
}
- else
+ if (md > dd && md + nd > dd)
+ {
+ return RR_ISECT_RAY_CYL_NONE; // Segment outside 'q' side of cylinder
+ }
+ float nn = n.Dot(n);
+ float mn = m.Dot(n);
+ float a = dd * nn - nd * nd;
+ float k = m.Dot(m) - r * r;
+ float c = dd * k - md * md;
+ if (std::fabs(a) < epsilon)
+ {
+ // Segment runs parallel to cylinder axis
+ if (c > 0.0f)
+ {
+ return RR_ISECT_RAY_CYL_NONE; // 'a' and thus the segment lie outside cylinder
+ }
+ // Now known that segment intersects cylinder; figure out how it intersects
+ if (md < 0.0f)
+ {
+ t = -mn / nn; // Intersect segment against 'p' endcap
+ return RR_ISECT_RAY_CYL_P_SIDE;
+ }
+ else if (md > dd)
+ {
+ t = (nd - mn) / nn; // Intersect segment against 'q' endcap
+ return RR_ISECT_RAY_CYL_Q_SIDE;
+ }
+ else
+ {
+ // 'a' lies inside cylinder
+ t = 0.0f;
+ return RR_ISECT_RAY_CYL_SA_INSIDE;
+ }
+ }
+ float b = dd * mn - nd * md;
+ float discr = b * b - a * c;
+ if (discr < 0.0f)
+ {
+ return RR_ISECT_RAY_CYL_NONE; // No real roots; no intersection
+ }
+ t = (-b - Sqrt(discr)) / a;
+ CylinderIsectTypes result = RR_ISECT_RAY_CYL_PQ; // default along the PQ segment
+
+ if (md + t * nd < 0.0f)
+ {
+ // Intersection outside cylinder on 'p' side
+ if (nd <= 0.0f)
+ {
+ return RR_ISECT_RAY_CYL_NONE; // Segment pointing away from endcap
+ }
+ float t0 = -md / nd;
+ // Keep intersection if Dot(S(t) - p, S(t) - p) <= r^2
+ if (k + t0 * (2.0f * mn + t0 * nn) <= 0.0f)
+ {
+ // if( t0 < 0.0f ) t0 = 0.0f; // it's inside the cylinder
+ t = t0;
+ result = RR_ISECT_RAY_CYL_P_SIDE;
+ }
+ else
+ {
+ return RR_ISECT_RAY_CYL_NONE;
+ }
+ }
+ else if (md + t * nd > dd)
+ {
+ // Intersection outside cylinder on 'q' side
+ if (nd >= 0.0f)
+ {
+ return RR_ISECT_RAY_CYL_NONE; // Segment pointing away from endcap
+ }
+ float t0 = (dd - md) / nd;
+ // Keep intersection if Dot(S(t) - q, S(t) - q) <= r^2
+ if (k + dd - 2.0f * md + t0 * (2.0f * (mn - nd) + t0 * nn) <= 0.0f)
+ {
+ // if( t0 < 0.0f ) t0 = 0.0f; // it's inside the cylinder
+ t = t0;
+ result = RR_ISECT_RAY_CYL_Q_SIDE;
+ }
+ else
+ {
+ return RR_ISECT_RAY_CYL_NONE;
+ }
+ }
+
+ // Segment intersects cylinder between the end-caps; t is correct
+ if (t > 1.0f)
{
return RR_ISECT_RAY_CYL_NONE; // Intersection lies outside segment
}
- }
- else
- {
- return result;
- }
-}
-//=========================================================================
-// IntersectSegmentCapsule
-// [10/21/2009]
-//=========================================================================
-CapsuleIsectTypes
-AZ::Intersect::IntersectSegmentCapsule(const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t)
-{
- int result = IntersectSegmentCylinder(sa, dir, p, q, r, t);
-
- if (result == RR_ISECT_RAY_CYL_SA_INSIDE)
- {
- return ISECT_RAY_CAPSULE_SA_INSIDE;
- }
-
- if (result == RR_ISECT_RAY_CYL_PQ)
- {
- return ISECT_RAY_CAPSULE_PQ;
- }
-
- Vector3 dirNorm = dir;
- float len = dirNorm.NormalizeWithLength();
-
- // check spheres
- float timeLenTop, timeLenBottom;
- int resultTop = IntersectRaySphere(sa, dirNorm, p, r, timeLenTop);
- if (resultTop == ISECT_RAY_SPHERE_SA_INSIDE)
- {
- return ISECT_RAY_CAPSULE_SA_INSIDE;
- }
- int resultBottom = IntersectRaySphere(sa, dirNorm, q, r, timeLenBottom);
- if (resultBottom == ISECT_RAY_SPHERE_SA_INSIDE)
- {
- return ISECT_RAY_CAPSULE_SA_INSIDE;
- }
-
- if (resultTop == ISECT_RAY_SPHERE_ISECT)
- {
- if (resultBottom == ISECT_RAY_SPHERE_ISECT)
+ else if (t < 0.0f)
{
- // if we intersect both spheres pick the closest one
- if (timeLenTop < timeLenBottom)
+ if (c <= 0.0f)
+ {
+ t = 0.0f;
+ return RR_ISECT_RAY_CYL_SA_INSIDE; // Segment starts inside
+ }
+ else
+ {
+ return RR_ISECT_RAY_CYL_NONE; // Intersection lies outside segment
+ }
+ }
+ else
+ {
+ return result;
+ }
+ }
+ //=========================================================================
+ // IntersectSegmentCapsule
+ // [10/21/2009]
+ //=========================================================================
+ Intersect::CapsuleIsectTypes Intersect::IntersectSegmentCapsule(
+ const Vector3& sa, const Vector3& dir, const Vector3& p, const Vector3& q, const float r, float& t)
+ {
+ int result = IntersectSegmentCylinder(sa, dir, p, q, r, t);
+
+ if (result == RR_ISECT_RAY_CYL_SA_INSIDE)
+ {
+ return ISECT_RAY_CAPSULE_SA_INSIDE;
+ }
+
+ if (result == RR_ISECT_RAY_CYL_PQ)
+ {
+ return ISECT_RAY_CAPSULE_PQ;
+ }
+
+ Vector3 dirNorm = dir;
+ float len = dirNorm.NormalizeWithLength();
+
+ // check spheres
+ float timeLenTop, timeLenBottom;
+ int resultTop = IntersectRaySphere(sa, dirNorm, p, r, timeLenTop);
+ if (resultTop == ISECT_RAY_SPHERE_SA_INSIDE)
+ {
+ return ISECT_RAY_CAPSULE_SA_INSIDE;
+ }
+ int resultBottom = IntersectRaySphere(sa, dirNorm, q, r, timeLenBottom);
+ if (resultBottom == ISECT_RAY_SPHERE_SA_INSIDE)
+ {
+ return ISECT_RAY_CAPSULE_SA_INSIDE;
+ }
+
+ if (resultTop == ISECT_RAY_SPHERE_ISECT)
+ {
+ if (resultBottom == ISECT_RAY_SPHERE_ISECT)
+ {
+ // if we intersect both spheres pick the closest one
+ if (timeLenTop < timeLenBottom)
+ {
+ t = timeLenTop / len;
+ return ISECT_RAY_CAPSULE_P_SIDE;
+ }
+ else
+ {
+ t = timeLenBottom / len;
+ return ISECT_RAY_CAPSULE_Q_SIDE;
+ }
+ }
+ else
{
t = timeLenTop / len;
return ISECT_RAY_CAPSULE_P_SIDE;
}
- else
- {
- t = timeLenBottom / len;
- return ISECT_RAY_CAPSULE_Q_SIDE;
- }
}
- else
+
+ if (resultBottom == ISECT_RAY_SPHERE_ISECT)
{
- t = timeLenTop / len;
- return ISECT_RAY_CAPSULE_P_SIDE;
+ t = timeLenBottom / len;
+ return ISECT_RAY_CAPSULE_Q_SIDE;
}
+
+ return ISECT_RAY_CAPSULE_NONE;
}
- if (resultBottom == ISECT_RAY_SPHERE_ISECT)
+ //=========================================================================
+ // IntersectSegmentPolyhedron
+ // [10/21/2009]
+ //=========================================================================
+ bool Intersect::IntersectSegmentPolyhedron(
+ const Vector3& sa,
+ const Vector3& dir,
+ const Plane p[],
+ int numPlanes,
+ float& tfirst,
+ float& tlast,
+ int& iFirstPlane,
+ int& iLastPlane)
{
- t = timeLenBottom / len;
- return ISECT_RAY_CAPSULE_Q_SIDE;
- }
-
- return ISECT_RAY_CAPSULE_NONE;
-}
-
-//=========================================================================
-// IntersectSegmentPolyhedron
-// [10/21/2009]
-//=========================================================================
-bool
-AZ::Intersect::IntersectSegmentPolyhedron(
- const Vector3& sa, const Vector3& dir, const Plane p[], int numPlanes,
- float& tfirst, float& tlast, int& iFirstPlane, int& iLastPlane)
-{
- // Compute direction vector for the segment
- Vector3 d = /*b - a*/ dir;
- // Set initial interval to being the whole segment. For a ray, tlast should be
- // set to +RR_FLT_MAX. For a line, additionally tfirst should be set to -RR_FLT_MAX
- tfirst = 0.0f;
- tlast = 1.0f;
- iFirstPlane = -1;
- iLastPlane = -1;
- // Intersect segment against each plane
- for (int i = 0; i < numPlanes; i++)
- {
- const Vector4& plane = p[i].GetPlaneEquationCoefficients();
-
- float denom = plane.Dot3(d);
- // don't forget we store -D in the plane
- float dist = (-plane.GetW()) - plane.Dot3(sa);
- // Test if segment runs parallel to the plane
- if (denom == 0.0f)
+ // Compute direction vector for the segment
+ Vector3 d = /*b - a*/ dir;
+ // Set initial interval to being the whole segment. For a ray, tlast should be
+ // set to +RR_FLT_MAX. For a line, additionally tfirst should be set to -RR_FLT_MAX
+ tfirst = 0.0f;
+ tlast = 1.0f;
+ iFirstPlane = -1;
+ iLastPlane = -1;
+ // Intersect segment against each plane
+ for (int i = 0; i < numPlanes; i++)
{
- // If so, return "no intersection" if segment lies outside plane
- if (dist < 0.0f)
+ const Vector4& plane = p[i].GetPlaneEquationCoefficients();
+
+ float denom = plane.Dot3(d);
+ // don't forget we store -D in the plane
+ float dist = (-plane.GetW()) - plane.Dot3(sa);
+ // Test if segment runs parallel to the plane
+ if (denom == 0.0f)
{
- return false;
- }
- }
- else
- {
- // Compute parameterized t value for intersection with current plane
- float t = dist / denom;
- if (denom < 0.0f)
- {
- // When entering half space, update tfirst if t is larger
- if (t > tfirst)
+ // If so, return "no intersection" if segment lies outside plane
+ if (dist < 0.0f)
{
- tfirst = t;
- iFirstPlane = i;
+ return false;
}
}
else
{
- // When exiting half space, update tlast if t is smaller
- if (t < tlast)
+ // Compute parameterized t value for intersection with current plane
+ float t = dist / denom;
+ if (denom < 0.0f)
{
- tlast = t;
- iLastPlane = i;
+ // When entering half space, update tfirst if t is larger
+ if (t > tfirst)
+ {
+ tfirst = t;
+ iFirstPlane = i;
+ }
+ }
+ else
+ {
+ // When exiting half space, update tlast if t is smaller
+ if (t < tlast)
+ {
+ tlast = t;
+ iLastPlane = i;
+ }
+ }
+
+ // Exit with "no intersection" if intersection becomes empty
+ if (tfirst > tlast)
+ {
+ return false;
}
}
-
- // Exit with "no intersection" if intersection becomes empty
- if (tfirst > tlast)
- {
- return false;
- }
}
- }
- //DBG_Assert(iFirstPlane!=-1&&iLastPlane!=-1,("We have some bad border case to have only one plane, fix this function!"));
- if (iFirstPlane == -1 && iLastPlane == -1)
- {
- return false;
- }
-
- // A nonzero logical intersection, so the segment intersects the polyhedron
- return true;
-}
-
-//=========================================================================
-// ClosestSegmentSegment
-// [10/21/2009]
-//=========================================================================
-void
-AZ::Intersect::ClosestSegmentSegment(
- const Vector3& segment1Start, const Vector3& segment1End,
- const Vector3& segment2Start, const Vector3& segment2End,
- float& segment1Proportion, float& segment2Proportion,
- Vector3& closestPointSegment1, Vector3& closestPointSegment2,
- float epsilon)
-{
- const Vector3 segment1 = segment1End - segment1Start;
- const Vector3 segment2 = segment2End - segment2Start;
- const Vector3 segmentStartsVector = segment1Start - segment2Start;
- const float segment1LengthSquared = segment1.Dot(segment1);
- const float segment2LengthSquared = segment2.Dot(segment2);
-
- // Check if both segments degenerate into points
- if (segment1LengthSquared <= epsilon && segment2LengthSquared <= epsilon)
- {
- segment1Proportion = 0.0f;
- segment2Proportion = 0.0f;
- closestPointSegment1 = segment1Start;
- closestPointSegment2 = segment2Start;
- return;
- }
-
- float projSegment2SegmentStarts = segment2.Dot(segmentStartsVector);
-
- // Check if segment 1 degenerates into a point
- if (segment1LengthSquared <= epsilon)
- {
- segment1Proportion = 0.0f;
- segment2Proportion = AZ::GetClamp(projSegment2SegmentStarts / segment2LengthSquared, 0.0f, 1.0f);
- }
- else
- {
- float projSegment1SegmentStarts = segment1.Dot(segmentStartsVector);
- // Check if segment 2 degenerates into a point
- if (segment2LengthSquared <= epsilon)
+ // DBG_Assert(iFirstPlane!=-1&&iLastPlane!=-1,("We have some bad border case to have only one plane, fix this function!"));
+ if (iFirstPlane == -1 && iLastPlane == -1)
{
- segment1Proportion = AZ::GetClamp(-projSegment1SegmentStarts / segment1LengthSquared, 0.0f, 1.0f);
+ return false;
+ }
+
+ // A nonzero logical intersection, so the segment intersects the polyhedron
+ return true;
+ }
+
+ //=========================================================================
+ // ClosestSegmentSegment
+ // [10/21/2009]
+ //=========================================================================
+ void Intersect::ClosestSegmentSegment(
+ const Vector3& segment1Start,
+ const Vector3& segment1End,
+ const Vector3& segment2Start,
+ const Vector3& segment2End,
+ float& segment1Proportion,
+ float& segment2Proportion,
+ Vector3& closestPointSegment1,
+ Vector3& closestPointSegment2,
+ float epsilon)
+ {
+ const Vector3 segment1 = segment1End - segment1Start;
+ const Vector3 segment2 = segment2End - segment2Start;
+ const Vector3 segmentStartsVector = segment1Start - segment2Start;
+ const float segment1LengthSquared = segment1.Dot(segment1);
+ const float segment2LengthSquared = segment2.Dot(segment2);
+
+ // Check if both segments degenerate into points
+ if (segment1LengthSquared <= epsilon && segment2LengthSquared <= epsilon)
+ {
+ segment1Proportion = 0.0f;
segment2Proportion = 0.0f;
+ closestPointSegment1 = segment1Start;
+ closestPointSegment2 = segment2Start;
+ return;
+ }
+
+ float projSegment2SegmentStarts = segment2.Dot(segmentStartsVector);
+
+ // Check if segment 1 degenerates into a point
+ if (segment1LengthSquared <= epsilon)
+ {
+ segment1Proportion = 0.0f;
+ segment2Proportion = AZ::GetClamp(projSegment2SegmentStarts / segment2LengthSquared, 0.0f, 1.0f);
}
else
{
- // The general non-degenerate case starts here
- float projSegment1Segment2 = segment1.Dot(segment2);
- float denom = segment1LengthSquared * segment2LengthSquared - projSegment1Segment2 * projSegment1Segment2; // Always nonnegative
-
- // If segments not parallel, compute closest point on segment1 to segment2, and
- // clamp to segment1. Else pick arbitrary segment1Proportion (here 0)
- if (denom != 0.0f)
+ float projSegment1SegmentStarts = segment1.Dot(segmentStartsVector);
+ // Check if segment 2 degenerates into a point
+ if (segment2LengthSquared <= epsilon)
{
- segment1Proportion = AZ::GetClamp((projSegment1Segment2 * projSegment2SegmentStarts - projSegment1SegmentStarts * segment2LengthSquared) / denom, 0.0f, 1.0f);
+ segment1Proportion = AZ::GetClamp(-projSegment1SegmentStarts / segment1LengthSquared, 0.0f, 1.0f);
+ segment2Proportion = 0.0f;
}
else
{
- segment1Proportion = 0.0f;
- }
+ // The general non-degenerate case starts here
+ float projSegment1Segment2 = segment1.Dot(segment2);
+ float denom =
+ segment1LengthSquared * segment2LengthSquared - projSegment1Segment2 * projSegment1Segment2; // Always nonnegative
- // Compute point on segment2 closest to segment1 using
- segment2Proportion = (projSegment1Segment2 * segment1Proportion + projSegment2SegmentStarts) / segment2LengthSquared;
+ // If segments not parallel, compute closest point on segment1 to segment2, and
+ // clamp to segment1. Else pick arbitrary segment1Proportion (here 0)
+ if (denom != 0.0f)
+ {
+ segment1Proportion = AZ::GetClamp(
+ (projSegment1Segment2 * projSegment2SegmentStarts - projSegment1SegmentStarts * segment2LengthSquared) / denom,
+ 0.0f, 1.0f);
+ }
+ else
+ {
+ segment1Proportion = 0.0f;
+ }
- // If segment2Proportion in [0,1] done. Else clamp segment2Proportion, recompute segment1Proportion for the new value of segment2Proportion
- // and clamp segment1Proportion to [0, 1]
- if (segment2Proportion < 0.0f)
- {
- segment2Proportion = 0.0f;
- segment1Proportion = AZ::GetClamp(-projSegment1SegmentStarts / segment1LengthSquared, 0.0f, 1.0f);
- }
- else if (segment2Proportion > 1.0f)
- {
- segment2Proportion = 1.0f;
- segment1Proportion = AZ::GetClamp((projSegment1Segment2 - projSegment1SegmentStarts) / segment1LengthSquared, 0.0f, 1.0f);
+ // Compute point on segment2 closest to segment1 using
+ segment2Proportion = (projSegment1Segment2 * segment1Proportion + projSegment2SegmentStarts) / segment2LengthSquared;
+
+ // If segment2Proportion in [0,1] done. Else clamp segment2Proportion, recompute segment1Proportion for the new value of
+ // segment2Proportion and clamp segment1Proportion to [0, 1]
+ if (segment2Proportion < 0.0f)
+ {
+ segment2Proportion = 0.0f;
+ segment1Proportion = AZ::GetClamp(-projSegment1SegmentStarts / segment1LengthSquared, 0.0f, 1.0f);
+ }
+ else if (segment2Proportion > 1.0f)
+ {
+ segment2Proportion = 1.0f;
+ segment1Proportion =
+ AZ::GetClamp((projSegment1Segment2 - projSegment1SegmentStarts) / segment1LengthSquared, 0.0f, 1.0f);
+ }
}
}
+
+ closestPointSegment1 = segment1Start + segment1 * segment1Proportion;
+ closestPointSegment2 = segment2Start + segment2 * segment2Proportion;
}
- closestPointSegment1 = segment1Start + segment1 * segment1Proportion;
- closestPointSegment2 = segment2Start + segment2 * segment2Proportion;
-}
-
-void AZ::Intersect::ClosestSegmentSegment(
- const Vector3& segment1Start, const Vector3& segment1End,
- const Vector3& segment2Start, const Vector3& segment2End,
- Vector3& closestPointSegment1, Vector3& closestPointSegment2,
- float epsilon)
-{
- float proportion1, proportion2;
- AZ::Intersect::ClosestSegmentSegment(
- segment1Start, segment1End,
- segment2Start, segment2End,
- proportion1, proportion2,
- closestPointSegment1, closestPointSegment2, epsilon);
-}
-
-void AZ::Intersect::ClosestPointSegment(
- const Vector3& point, const Vector3& segmentStart, const Vector3& segmentEnd,
- float& proportion, Vector3& closestPointOnSegment)
-{
- Vector3 segment = segmentEnd - segmentStart;
- // Project point onto segment, but deferring divide by segment.Dot(segment)
- proportion = (point - segmentStart).Dot(segment);
- if (proportion <= 0.0f)
+ void Intersect::ClosestSegmentSegment(
+ const Vector3& segment1Start,
+ const Vector3& segment1End,
+ const Vector3& segment2Start,
+ const Vector3& segment2End,
+ Vector3& closestPointSegment1,
+ Vector3& closestPointSegment2,
+ float epsilon)
{
- // Point projects outside the [segmentStart, segmentEnd] interval, on the segmentStart side, clamp to segmentStart
- proportion = 0.0f;
- closestPointOnSegment = segmentStart;
+ float proportion1, proportion2;
+ Intersect::ClosestSegmentSegment(
+ segment1Start, segment1End, segment2Start, segment2End, proportion1, proportion2, closestPointSegment1, closestPointSegment2,
+ epsilon);
}
- else
+
+ void Intersect::ClosestPointSegment(
+ const Vector3& point, const Vector3& segmentStart, const Vector3& segmentEnd, float& proportion, Vector3& closestPointOnSegment)
{
- float segmentLengthSquared = segment.Dot(segment);
- if (proportion >= segmentLengthSquared)
+ Vector3 segment = segmentEnd - segmentStart;
+ // Project point onto segment, but deferring divide by segment.Dot(segment)
+ proportion = (point - segmentStart).Dot(segment);
+ if (proportion <= 0.0f)
{
- // Point projects outside the [segmentStart, segmentEnd] interval, on the segmentEnd side, clamp to segmentEnd
- proportion = 1.0f;
- closestPointOnSegment = segmentEnd;
+ // Point projects outside the [segmentStart, segmentEnd] interval, on the segmentStart side, clamp to segmentStart
+ proportion = 0.0f;
+ closestPointOnSegment = segmentStart;
}
else
{
- // Point projects inside the [segmentStart, segmentEnd] interval, must do deferred divide now
- proportion = proportion / segmentLengthSquared;
- closestPointOnSegment = segmentStart + (proportion * segment);
+ float segmentLengthSquared = segment.Dot(segment);
+ if (proportion >= segmentLengthSquared)
+ {
+ // Point projects outside the [segmentStart, segmentEnd] interval, on the segmentEnd side, clamp to segmentEnd
+ proportion = 1.0f;
+ closestPointOnSegment = segmentEnd;
+ }
+ else
+ {
+ // Point projects inside the [segmentStart, segmentEnd] interval, must do deferred divide now
+ proportion = proportion / segmentLengthSquared;
+ closestPointOnSegment = segmentStart + (proportion * segment);
+ }
}
}
-}
#if 0
//////////////////////////////////////////////////////////////////////////
@@ -2121,3 +2171,5 @@ namespace test
}
//////////////////////////////////////////////////////////////////////////
#endif
+
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Math/Plane.inl b/Code/Framework/AzCore/AzCore/Math/Plane.inl
index f33d356312..795ee8b4bc 100644
--- a/Code/Framework/AzCore/AzCore/Math/Plane.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Plane.inl
@@ -19,12 +19,14 @@ namespace AZ
AZ_MATH_INLINE Plane Plane::CreateFromNormalAndPoint(const Vector3& normal, const Vector3& point)
{
+ AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
return Plane(Simd::Vec4::ConstructPlane(normal.GetSimdValue(), point.GetSimdValue()));
}
AZ_MATH_INLINE Plane Plane::CreateFromNormalAndDistance(const Vector3& normal, float dist)
{
+ AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is not normalized");
Plane result;
result.Set(normal, dist);
return result;
@@ -33,6 +35,7 @@ namespace AZ
AZ_MATH_INLINE Plane Plane::CreateFromCoefficients(const float a, const float b, const float c, const float d)
{
+ AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
Plane result;
result.Set(a, b, c, d);
return result;
@@ -65,18 +68,21 @@ namespace AZ
AZ_MATH_INLINE void Plane::Set(const Vector3& normal, float d)
{
+ AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
m_plane.Set(normal, d);
}
AZ_MATH_INLINE void Plane::Set(float a, float b, float c, float d)
{
+ AZ_MATH_ASSERT(Vector3(a, b, c).IsNormalized(), "This normal is notormalized");
m_plane.Set(a, b, c, d);
}
AZ_MATH_INLINE void Plane::SetNormal(const Vector3& normal)
{
+ AZ_MATH_ASSERT(normal.IsNormalized(), "This normal is notormalized");
m_plane.SetX(normal.GetX());
m_plane.SetY(normal.GetY());
m_plane.SetZ(normal.GetZ());
diff --git a/Code/Framework/AzCore/AzCore/Math/Quaternion.cpp b/Code/Framework/AzCore/AzCore/Math/Quaternion.cpp
index e06cd184ad..fac70bd05a 100644
--- a/Code/Framework/AzCore/AzCore/Math/Quaternion.cpp
+++ b/Code/Framework/AzCore/AzCore/Math/Quaternion.cpp
@@ -254,13 +254,13 @@ namespace AZ
Method("CreateFromMatrix3x3", &Quaternion::CreateFromMatrix3x3)->
Method("CreateFromMatrix4x4", &Quaternion::CreateFromMatrix4x4)->
Method("CreateFromAxisAngle", &Quaternion::CreateFromAxisAngle)->
+ Method("CreateFromScaledAxisAngle", &Quaternion::CreateFromScaledAxisAngle)->
Method("CreateShortestArc", &Quaternion::CreateShortestArc)->
Method("CreateFromEulerAnglesDegrees", &Quaternion::CreateFromEulerAnglesDegrees)
;
}
}
-
Quaternion Quaternion::CreateFromMatrix3x3(const Matrix3x3& m)
{
return CreateFromBasis(m.GetBasisX(), m.GetBasisY(), m.GetBasisZ());
@@ -430,4 +430,24 @@ namespace AZ
outAngle = 0.0f;
}
}
+
+
+ Vector3 Quaternion::ConvertToScaledAxisAngle() const
+ {
+ // Take the log of the quaternion to convert it to the exponential map
+ // and multiply it by 2.0 to bring it into the scaled axis-angle representation.
+ const AZ::Vector3 imaginary = GetImaginary();
+ const float length = imaginary.GetLength();
+ if (length < AZ::Constants::FloatEpsilon)
+ {
+ return imaginary * 2.0f;
+ }
+ else
+ {
+ const float halfAngle = acosf(AZ::GetClamp(GetW(), -1.0f, 1.0f));
+
+ // Multiply by 2.0 to convert the half angle into the full one.
+ return halfAngle * 2.0f * (imaginary / length);
+ }
+ }
}
diff --git a/Code/Framework/AzCore/AzCore/Math/Quaternion.h b/Code/Framework/AzCore/AzCore/Math/Quaternion.h
index f2c266ed3e..ad454aab4f 100644
--- a/Code/Framework/AzCore/AzCore/Math/Quaternion.h
+++ b/Code/Framework/AzCore/AzCore/Math/Quaternion.h
@@ -54,11 +54,11 @@ namespace AZ
//! Sets components using a Vector3 for the imaginary part and a float for the real part.
static Quaternion CreateFromVector3AndValue(const Vector3& v, float w);
- //! Sets the quaternion to be a rotation around a specified axis.
+ //! Sets the quaternion to be a rotation around a specified axis in radians.
//! @{
- static Quaternion CreateRotationX(float angle);
- static Quaternion CreateRotationY(float angle);
- static Quaternion CreateRotationZ(float angle);
+ static Quaternion CreateRotationX(float angleInRadians);
+ static Quaternion CreateRotationY(float angleInRadians);
+ static Quaternion CreateRotationZ(float angleInRadians);
//! @}
//! Creates a quaternion from a Matrix3x3
@@ -77,6 +77,9 @@ namespace AZ
static Quaternion CreateFromAxisAngle(const Vector3& axis, float angle);
+ //! Create a quaternion from a scaled axis-angle representation.
+ static Quaternion CreateFromScaledAxisAngle(const Vector3& scaledAxisAngle);
+
static Quaternion CreateShortestArc(const Vector3& v1, const Vector3& v2);
//! Creates a quaternion using rotation in degrees about the axes. First rotated about the X axis, followed by the Y axis, then the Z axis.
@@ -165,6 +168,14 @@ namespace AZ
float NormalizeWithLengthEstimate();
//! @}
+ //! Get the shortest equivalent of the rotation.
+ //! In case the w component of the quaternion is negative the rotation is > 180° and taking the longer path.
+ //! The quaternion will be inverted in that case to take the shortest path of rotation.
+ //! @{
+ Quaternion GetShortestEquivalent() const;
+ void ShortestEquivalent();
+ //! @}
+
//! Linearly interpolate towards a destination quaternion.
//! @param[in] dest The quaternion to interpolate towards.
//! @param[in] t Normalized interpolation value where 0.0 represents the current and 1.0 the destination value.
@@ -231,6 +242,9 @@ namespace AZ
//! @param[out] outAngle A float rotation angle around the axis in radians.
void ConvertToAxisAngle(Vector3& outAxis, float& outAngle) const;
+ //! Convert the quaternion into scaled axis-angle representation.
+ Vector3 ConvertToScaledAxisAngle() const;
+
//! Returns the imaginary (X/Y/Z) portion of the quaternion.
Vector3 GetImaginary() const;
diff --git a/Code/Framework/AzCore/AzCore/Math/Quaternion.inl b/Code/Framework/AzCore/AzCore/Math/Quaternion.inl
index 82cd9078fa..bd51a90fca 100644
--- a/Code/Framework/AzCore/AzCore/Math/Quaternion.inl
+++ b/Code/Framework/AzCore/AzCore/Math/Quaternion.inl
@@ -73,27 +73,27 @@ namespace AZ
}
- AZ_MATH_INLINE Quaternion Quaternion::CreateRotationX(float angle)
+ AZ_MATH_INLINE Quaternion Quaternion::CreateRotationX(float angleInRadians)
{
- const float halfAngle = 0.5f * angle;
+ const float halfAngle = 0.5f * angleInRadians;
float sin, cos;
SinCos(halfAngle, sin, cos);
return Quaternion(sin, 0.0f, 0.0f, cos);
}
- AZ_MATH_INLINE Quaternion Quaternion::CreateRotationY(float angle)
+ AZ_MATH_INLINE Quaternion Quaternion::CreateRotationY(float angleInRadians)
{
- const float halfAngle = 0.5f * angle;
+ const float halfAngle = 0.5f * angleInRadians;
float sin, cos;
SinCos(halfAngle, sin, cos);
return Quaternion(0.0f, sin, 0.0f, cos);
}
- AZ_MATH_INLINE Quaternion Quaternion::CreateRotationZ(float angle)
+ AZ_MATH_INLINE Quaternion Quaternion::CreateRotationZ(float angleInRadians)
{
- const float halfAngle = 0.5f * angle;
+ const float halfAngle = 0.5f * angleInRadians;
float sin, cos;
SinCos(halfAngle, sin, cos);
return Quaternion(0.0f, 0.0f, sin, cos);
@@ -109,6 +109,24 @@ namespace AZ
}
+ AZ_MATH_INLINE Quaternion Quaternion::CreateFromScaledAxisAngle(const Vector3& scaledAxisAngle)
+ {
+ const AZ::Vector3 exponentialMap = scaledAxisAngle / 2.0f;
+ const float halfAngle = exponentialMap.GetLength();
+
+ if (halfAngle < AZ::Constants::FloatEpsilon)
+ {
+ return AZ::Quaternion::CreateFromVector3AndValue(exponentialMap, 1.0f).GetNormalized();
+ }
+ else
+ {
+ float sin, cos;
+ SinCos(halfAngle, sin, cos);
+ return AZ::Quaternion::CreateFromVector3AndValue((sin / halfAngle) * exponentialMap, cos);
+ }
+ }
+
+
AZ_MATH_INLINE void Quaternion::StoreToFloat4(float* values) const
{
Simd::Vec4::StoreUnaligned(values, m_value);
@@ -327,6 +345,23 @@ namespace AZ
}
+ AZ_MATH_INLINE Quaternion Quaternion::GetShortestEquivalent() const
+ {
+ if (GetW() < 0.0f)
+ {
+ return -(*this);
+ }
+
+ return *this;
+ }
+
+
+ AZ_MATH_INLINE void Quaternion::ShortestEquivalent()
+ {
+ *this = GetShortestEquivalent();
+ }
+
+
AZ_MATH_INLINE Quaternion Quaternion::Lerp(const Quaternion& dest, float t) const
{
if (Dot(dest) >= 0.0f)
diff --git a/Code/Framework/AzCore/AzCore/Math/Sfmt.cpp b/Code/Framework/AzCore/AzCore/Math/Sfmt.cpp
index 5f4dc9e5df..96c1a6a420 100644
--- a/Code/Framework/AzCore/AzCore/Math/Sfmt.cpp
+++ b/Code/Framework/AzCore/AzCore/Math/Sfmt.cpp
@@ -9,39 +9,38 @@
#include
#include
-#include
#include
+#include
#include // for memset
namespace AZ::SfmtInternal
{
- static const int N32 = N * 4;
- static const int N64 = N * 2;
- static const int POS1 = 122;
- static const int SL1 = 18;
- static const int SR1 = 11;
- static const int SL2 = 1;
- static const int SR2 = 1;
- static const unsigned int MSK1 = 0xdfffffefU;
- static const unsigned int MSK2 = 0xddfecb7fU;
- static const unsigned int MSK3 = 0xbffaffffU;
- static const unsigned int MSK4 = 0xbffffff6U;
- static const unsigned int PARITY1 = 0x00000001U;
- static const unsigned int PARITY2 = 0x00000000U;
- static const unsigned int PARITY3 = 0x00000000U;
- static const unsigned int PARITY4 = 0x13c9e684U;
+ static const int N32 = N * 4;
+ static const int N64 = N * 2;
+ static const int POS1 = 122;
+ static const int SL1 = 18;
+ static const int SR1 = 11;
+ static const int SL2 = 1;
+ static const int SR2 = 1;
+ static const unsigned int MSK1 = 0xdfffffefU;
+ static const unsigned int MSK2 = 0xddfecb7fU;
+ static const unsigned int MSK3 = 0xbffaffffU;
+ static const unsigned int MSK4 = 0xbffffff6U;
+ static const unsigned int PARITY1 = 0x00000001U;
+ static const unsigned int PARITY2 = 0x00000000U;
+ static const unsigned int PARITY3 = 0x00000000U;
+ static const unsigned int PARITY4 = 0x13c9e684U;
/** a parity check vector which certificate the period of 2^{MEXP} */
- static unsigned int parity[4] = {PARITY1, PARITY2, PARITY3, PARITY4};
+ static unsigned int parity[4] = { PARITY1, PARITY2, PARITY3, PARITY4 };
#ifdef ONLY64
-# define idxof(_i) (_i ^ 1)
+#define idxof(_i) (_i ^ 1)
#else
-# define idxof(_i) _i
+#define idxof(_i) _i
#endif // ONLY64
-
#if AZ_TRAIT_USE_PLATFORM_SIMD_SSE
/**
* This function represents the recursion formula.
@@ -52,7 +51,8 @@ namespace AZ::SfmtInternal
* @param mask 128-bit mask
* @return output
*/
- AZ_FORCE_INLINE static Simd::Vec4::Int32Type simd_recursion(Simd::Vec4::Int32Type* a, Simd::Vec4::Int32Type* b, Simd::Vec4::Int32Type c, Simd::Vec4::Int32Type d, Simd::Vec4::Int32Type mask)
+ AZ_FORCE_INLINE static Simd::Vec4::Int32Type simd_recursion(
+ Simd::Vec4::Int32Type* a, Simd::Vec4::Int32Type* b, Simd::Vec4::Int32Type c, Simd::Vec4::Int32Type d, Simd::Vec4::Int32Type mask)
{
Simd::Vec4::Int32Type v, x, y, z;
x = *a;
@@ -151,7 +151,7 @@ namespace AZ::SfmtInternal
inline void rshift128(w128_t* out, w128_t const* in, int shift)
{
AZ::u64 th, tl, oh, ol;
- #ifdef ONLY64
+#ifdef ONLY64
th = ((AZ::u64)in->u[2] << 32) | ((AZ::u64)in->u[3]);
tl = ((AZ::u64)in->u[0] << 32) | ((AZ::u64)in->u[1]);
@@ -204,7 +204,7 @@ namespace AZ::SfmtInternal
#endif
}
- inline void do_recursion(w128_t* r, w128_t* a, w128_t* b, w128_t* c, w128_t* d)
+ inline void do_recursion(w128_t* r, w128_t* a, w128_t* b, w128_t* c, w128_t* d)
{
w128_t x;
w128_t y;
@@ -229,7 +229,7 @@ namespace AZ::SfmtInternal
inline void gen_rand_all(Sfmt& g)
{
int i;
- w128_t* r1, * r2;
+ w128_t *r1, *r2;
r1 = &g.m_sfmt[N - 2];
r2 = &g.m_sfmt[N - 1];
@@ -257,7 +257,7 @@ namespace AZ::SfmtInternal
inline void gen_rand_array(Sfmt& g, w128_t* array, int size)
{
int i, j;
- w128_t* r1, * r2;
+ w128_t *r1, *r2;
r1 = &g.m_sfmt[N - 2];
r2 = &g.m_sfmt[N - 1];
@@ -295,82 +295,80 @@ namespace AZ::SfmtInternal
#endif
} // namespace AZ::SfmtInternal
-using namespace AZ;
-
//////////////////////////////////////////////////////////////////////////
// Statics
//////////////////////////////////////////////////////////////////////////
-
-static EnvironmentVariable s_sfmt;
-static const char* s_globalSfmtName = "GlobalSfmt";
-
-Sfmt& Sfmt::GetInstance()
+namespace AZ
{
- if (!s_sfmt)
+ static EnvironmentVariable s_sfmt;
+ static const char* s_globalSfmtName = "GlobalSfmt";
+
+ Sfmt& Sfmt::GetInstance()
{
- s_sfmt = AZ::Environment::FindVariable(s_globalSfmtName);
if (!s_sfmt)
{
- Sfmt::Create();
+ s_sfmt = AZ::Environment::FindVariable(s_globalSfmtName);
+ if (!s_sfmt)
+ {
+ Sfmt::Create();
+ }
+ }
+
+ return s_sfmt.Get();
+ }
+
+ void Sfmt::Create()
+ {
+ if (!s_sfmt)
+ {
+ s_sfmt = AZ::Environment::CreateVariable(s_globalSfmtName);
}
}
- return s_sfmt.Get();
-}
-
-void Sfmt::Create()
-{
- if (!s_sfmt)
+ void Sfmt::Destroy()
{
- s_sfmt = AZ::Environment::CreateVariable(s_globalSfmtName);
+ s_sfmt.Reset();
}
-}
-void Sfmt::Destroy()
-{
- s_sfmt.Reset();
-}
+ //=========================================================================
+ // Sfmt
+ // [4/10/2012]
+ //=========================================================================
+ Sfmt::Sfmt()
+ {
+ m_psfmt32 = &m_sfmt[0].u[0];
+ m_psfmt64 = reinterpret_cast(m_psfmt32);
-//=========================================================================
-// Sfmt
-// [4/10/2012]
-//=========================================================================
-Sfmt::Sfmt()
-{
- m_psfmt32 = &m_sfmt[0].u[0];
- m_psfmt64 = reinterpret_cast(m_psfmt32);
+ Seed();
+ }
- Seed();
-}
+ //=========================================================================
+ // Seed
+ // [4/10/2012]
+ //=========================================================================
+ Sfmt::Sfmt(AZ::u32* keys, int numKeys)
+ {
+ m_psfmt32 = &m_sfmt[0].u[0];
+ m_psfmt64 = reinterpret_cast(m_psfmt32);
-//=========================================================================
-// Seed
-// [4/10/2012]
-//=========================================================================
-Sfmt::Sfmt(AZ::u32* keys, int numKeys)
-{
- m_psfmt32 = &m_sfmt[0].u[0];
- m_psfmt64 = reinterpret_cast(m_psfmt32);
+ Seed(keys, numKeys);
+ }
- Seed(keys, numKeys);
-}
-
-//=========================================================================
-// Seed
-// [4/10/2012]
-//=========================================================================
-void
-Sfmt::Seed()
-{
- // buffer with random values
- AZ::u32 buffer[32];
- BetterPseudoRandom rnd;
- bool result = rnd.GetRandom(buffer, sizeof(buffer));
- (void)result;
- AZ_Warning("System", result, "Failed to seed properly the Smft generator!");
- Seed(buffer, AZ_ARRAY_SIZE(buffer));
-}
+ //=========================================================================
+ // Seed
+ // [4/10/2012]
+ //=========================================================================
+ void Sfmt::Seed()
+ {
+ // buffer with random values
+ AZ::u32 buffer[32];
+ BetterPseudoRandom rnd;
+ bool result = rnd.GetRandom(buffer, sizeof(buffer));
+ (void)result;
+ AZ_Warning("System", result, "Failed to seed properly the Smft generator!");
+ Seed(buffer, AZ_ARRAY_SIZE(buffer));
+ }
/**
* This function represents a function used in the initialization
@@ -388,226 +386,222 @@ Sfmt::Seed()
*/
#define azsfmt_func2(x) ((x ^ (x >> 27)) * (AZ::u32)1566083941UL)
-//=========================================================================
-// Seed
-// [4/10/2012]
-//=========================================================================
-void
-Sfmt::Seed(AZ::u32* keys, int numKeys)
-{
- using SfmtInternal::N;
- using SfmtInternal::N32;
- int i, j, count;
- AZ::u32 r;
- int lag;
- int mid;
- int size = N * 4;
+ //=========================================================================
+ // Seed
+ // [4/10/2012]
+ //=========================================================================
+ void Sfmt::Seed(AZ::u32* keys, int numKeys)
+ {
+ using SfmtInternal::N;
+ using SfmtInternal::N32;
+ int i, j, count;
+ AZ::u32 r;
+ int lag;
+ int mid;
+ int size = N * 4;
- if (size >= 623)
- {
- lag = 11;
- }
- else if (size >= 68)
- {
- lag = 7;
- }
- else if (size >= 39)
- {
- lag = 5;
- }
- else
- {
- lag = 3;
- }
- mid = (size - lag) / 2;
+ if (size >= 623)
+ {
+ lag = 11;
+ }
+ else if (size >= 68)
+ {
+ lag = 7;
+ }
+ else if (size >= 39)
+ {
+ lag = 5;
+ }
+ else
+ {
+ lag = 3;
+ }
+ mid = (size - lag) / 2;
- memset(m_sfmt, 0x8b, sizeof(m_sfmt));
- if (numKeys + 1 > SfmtInternal::N32)
- {
- count = numKeys + 1;
- }
- else
- {
- count = N32;
- }
- r = azsfmt_func1((m_psfmt32[idxof(0)] ^ m_psfmt32[idxof(mid)] ^ m_psfmt32[idxof(N32 - 1)]));
- m_psfmt32[idxof(mid)] += r;
- r += numKeys;
- m_psfmt32[idxof(mid + lag)] += r;
- m_psfmt32[idxof(0)] = r;
+ memset(m_sfmt, 0x8b, sizeof(m_sfmt));
+ if (numKeys + 1 > SfmtInternal::N32)
+ {
+ count = numKeys + 1;
+ }
+ else
+ {
+ count = N32;
+ }
+ r = azsfmt_func1((m_psfmt32[idxof(0)] ^ m_psfmt32[idxof(mid)] ^ m_psfmt32[idxof(N32 - 1)]));
+ m_psfmt32[idxof(mid)] += r;
+ r += numKeys;
+ m_psfmt32[idxof(mid + lag)] += r;
+ m_psfmt32[idxof(0)] = r;
- count--;
- for (i = 1, j = 0; (j < count) && (j < numKeys); j++)
- {
- r = azsfmt_func1((m_psfmt32[idxof(i)] ^ m_psfmt32[idxof((i + mid) % N32)] ^ m_psfmt32[idxof((i + N32 - 1) % N32)]));
- m_psfmt32[idxof((i + mid) % N32)] += r;
- r += keys[j] + i;
- m_psfmt32[idxof((i + mid + lag) % N32)] += r;
- m_psfmt32[idxof(i)] = r;
- i = (i + 1) % N32;
- }
- for (; j < count; j++)
- {
- r = azsfmt_func1((m_psfmt32[idxof(i)] ^ m_psfmt32[idxof((i + mid) % N32)] ^ m_psfmt32[idxof((i + N32 - 1) % N32)]));
- m_psfmt32[idxof((i + mid) % N32)] += r;
- r += i;
- m_psfmt32[idxof((i + mid + lag) % N32)] += r;
- m_psfmt32[idxof(i)] = r;
- i = (i + 1) % N32;
- }
- for (j = 0; j < N32; j++)
- {
- r = azsfmt_func2((m_psfmt32[idxof(i)] + m_psfmt32[idxof((i + mid) % N32)] + m_psfmt32[idxof((i + N32 - 1) % N32)]));
- m_psfmt32[idxof((i + mid) % N32)] ^= r;
- r -= i;
- m_psfmt32[idxof((i + mid + lag) % N32)] ^= r;
- m_psfmt32[idxof(i)] = r;
- i = (i + 1) % N32;
- }
+ count--;
+ for (i = 1, j = 0; (j < count) && (j < numKeys); j++)
+ {
+ r = azsfmt_func1((m_psfmt32[idxof(i)] ^ m_psfmt32[idxof((i + mid) % N32)] ^ m_psfmt32[idxof((i + N32 - 1) % N32)]));
+ m_psfmt32[idxof((i + mid) % N32)] += r;
+ r += keys[j] + i;
+ m_psfmt32[idxof((i + mid + lag) % N32)] += r;
+ m_psfmt32[idxof(i)] = r;
+ i = (i + 1) % N32;
+ }
+ for (; j < count; j++)
+ {
+ r = azsfmt_func1((m_psfmt32[idxof(i)] ^ m_psfmt32[idxof((i + mid) % N32)] ^ m_psfmt32[idxof((i + N32 - 1) % N32)]));
+ m_psfmt32[idxof((i + mid) % N32)] += r;
+ r += i;
+ m_psfmt32[idxof((i + mid + lag) % N32)] += r;
+ m_psfmt32[idxof(i)] = r;
+ i = (i + 1) % N32;
+ }
+ for (j = 0; j < N32; j++)
+ {
+ r = azsfmt_func2((m_psfmt32[idxof(i)] + m_psfmt32[idxof((i + mid) % N32)] + m_psfmt32[idxof((i + N32 - 1) % N32)]));
+ m_psfmt32[idxof((i + mid) % N32)] ^= r;
+ r -= i;
+ m_psfmt32[idxof((i + mid + lag) % N32)] ^= r;
+ m_psfmt32[idxof(i)] = r;
+ i = (i + 1) % N32;
+ }
- m_index = N32;
- PeriodCertification();
-}
+ m_index = N32;
+ PeriodCertification();
+ }
#undef azsfmt_func1
#undef azsfmt_func2
-//=========================================================================
-// PeriodCertification
-// [4/10/2012]
-//=========================================================================
-void
-Sfmt::PeriodCertification()
-{
- int inner = 0;
- int i, j;
- AZ::u32 work;
+ //=========================================================================
+ // PeriodCertification
+ // [4/10/2012]
+ //=========================================================================
+ void Sfmt::PeriodCertification()
+ {
+ int inner = 0;
+ int i, j;
+ AZ::u32 work;
- for (i = 0; i < 4; i++)
- {
- inner ^= m_psfmt32[idxof(i)] & SfmtInternal::parity[i];
- }
- for (i = 16; i > 0; i >>= 1)
- {
- inner ^= inner >> i;
- }
- inner &= 1;
- /* check OK */
- if (inner == 1)
- {
- return;
- }
- /* check NG, and modification */
- for (i = 0; i < 4; i++)
- {
- work = 1;
- for (j = 0; j < 32; j++)
+ for (i = 0; i < 4; i++)
{
- if ((work & SfmtInternal::parity[i]) != 0)
+ inner ^= m_psfmt32[idxof(i)] & SfmtInternal::parity[i];
+ }
+ for (i = 16; i > 0; i >>= 1)
+ {
+ inner ^= inner >> i;
+ }
+ inner &= 1;
+ /* check OK */
+ if (inner == 1)
+ {
+ return;
+ }
+ /* check NG, and modification */
+ for (i = 0; i < 4; i++)
+ {
+ work = 1;
+ for (j = 0; j < 32; j++)
{
- m_psfmt32[idxof(i)] ^= work;
- return;
+ if ((work & SfmtInternal::parity[i]) != 0)
+ {
+ m_psfmt32[idxof(i)] ^= work;
+ return;
+ }
+ work = work << 1;
}
- work = work << 1;
}
}
-}
-//=========================================================================
-// Rand32
-// [4/10/2012]
-//=========================================================================
-AZ::u32 Sfmt::Rand32()
-{
- int index = m_index.fetch_add(1);
- if (index >= SfmtInternal::N32)
+ //=========================================================================
+ // Rand32
+ // [4/10/2012]
+ //=========================================================================
+ AZ::u32 Sfmt::Rand32()
{
- AZStd::lock_guard lock(m_generationMutex);
- // if this thread is the one that sets m_index to 0, then this thread
- // does the generation
- index += 1; // compare against the result of fetch_add(1) above
- if (m_index.compare_exchange_strong(index, 0))
+ int index = m_index.fetch_add(1);
+ if (index >= SfmtInternal::N32)
{
- SfmtInternal::gen_rand_all(*this);
+ AZStd::lock_guard lock(m_generationMutex);
+ // if this thread is the one that sets m_index to 0, then this thread
+ // does the generation
+ index += 1; // compare against the result of fetch_add(1) above
+ if (m_index.compare_exchange_strong(index, 0))
+ {
+ SfmtInternal::gen_rand_all(*this);
+ }
+ // try again, with the new table
+ return Rand32();
}
- // try again, with the new table
- return Rand32();
+ return m_psfmt32[index];
}
- return m_psfmt32[index];
-}
-//=========================================================================
-// Rand64
-// [4/10/2012]
-//=========================================================================
-AZ::u64 Sfmt::Rand64()
-{
- int index = m_index.fetch_add(2);
- if (index >= (SfmtInternal::N32 - 1))
+ //=========================================================================
+ // Rand64
+ // [4/10/2012]
+ //=========================================================================
+ AZ::u64 Sfmt::Rand64()
{
- AZStd::lock_guard lock(m_generationMutex);
- // if this thread is the one that sets m_index to 0, then this thread
- // does the generation
- index += 2; // compare against the result of fetch_add(2) above
- if (m_index.compare_exchange_strong(index, 0))
+ int index = m_index.fetch_add(2);
+ if (index >= (SfmtInternal::N32 - 1))
{
- SfmtInternal::gen_rand_all(*this);
+ AZStd::lock_guard lock(m_generationMutex);
+ // if this thread is the one that sets m_index to 0, then this thread
+ // does the generation
+ index += 2; // compare against the result of fetch_add(2) above
+ if (m_index.compare_exchange_strong(index, 0))
+ {
+ SfmtInternal::gen_rand_all(*this);
+ }
+ // try again, with the new table
+ return Rand64();
}
- // try again, with the new table
- return Rand64();
+
+ AZ::u64 r;
+ r = m_psfmt64[index / 2];
+ return r;
}
- AZ::u64 r;
- r = m_psfmt64[index / 2];
- return r;
-}
+ //=========================================================================
+ // FillArray32
+ // [4/10/2012]
+ //=========================================================================
+ void Sfmt::FillArray32(AZ::u32* array, int size)
+ {
+ AZ_MATH_ASSERT(m_index == SfmtInternal::N32, "Invalid m_index! Reinitialize!");
+ AZ_MATH_ASSERT(size % 4 == 0, "Size must be multiple of 4!");
+ AZ_MATH_ASSERT(size >= SfmtInternal::N32, "Size must be bigger than %d GetMinArray32Size()!", SfmtInternal::N32);
-//=========================================================================
-// FillArray32
-// [4/10/2012]
-//=========================================================================
-void
-Sfmt::FillArray32(AZ::u32* array, int size)
-{
- AZ_MATH_ASSERT(m_index == SfmtInternal::N32, "Invalid m_index! Reinitialize!");
- AZ_MATH_ASSERT(size % 4 == 0, "Size must be multiple of 4!");
- AZ_MATH_ASSERT(size >= SfmtInternal::N32, "Size must be bigger than %d GetMinArray32Size()!", SfmtInternal::N32);
+ SfmtInternal::gen_rand_array(*this, (SfmtInternal::w128_t*)array, size / 4);
+ m_index = SfmtInternal::N32;
+ }
- SfmtInternal::gen_rand_array(*this, (SfmtInternal::w128_t*)array, size / 4);
- m_index = SfmtInternal::N32;
-}
+ //=========================================================================
+ // FillArray64
+ // [4/10/2012]
+ //=========================================================================
+ void Sfmt::FillArray64(AZ::u64* array, int size)
+ {
+ AZ_MATH_ASSERT(m_index == SfmtInternal::N32, "Invalid m_index! Reinitialize!");
+ AZ_MATH_ASSERT(size % 4 == 0, "Size must be multiple of 4!");
+ AZ_MATH_ASSERT(size >= SfmtInternal::N64, "Size must be bigger than %d GetMinArray64Size()!", SfmtInternal::N64);
-//=========================================================================
-// FillArray64
-// [4/10/2012]
-//=========================================================================
-void
-Sfmt::FillArray64(AZ::u64* array, int size)
-{
- AZ_MATH_ASSERT(m_index == SfmtInternal::N32, "Invalid m_index! Reinitialize!");
- AZ_MATH_ASSERT(size % 4 == 0, "Size must be multiple of 4!");
- AZ_MATH_ASSERT(size >= SfmtInternal::N64, "Size must be bigger than %d GetMinArray64Size()!", SfmtInternal::N64);
+ SfmtInternal::gen_rand_array(*this, (SfmtInternal::w128_t*)array, size / 2);
+ m_index = SfmtInternal::N32;
+ }
- SfmtInternal::gen_rand_array(*this, (SfmtInternal::w128_t*)array, size / 2);
- m_index = SfmtInternal::N32;
-}
+ //=========================================================================
+ // GetMinArray32Size
+ // [4/10/2012]
+ //=========================================================================
+ int Sfmt::GetMinArray32Size() const
+ {
+ return SfmtInternal::N32;
+ }
-//=========================================================================
-// GetMinArray32Size
-// [4/10/2012]
-//=========================================================================
-int
-Sfmt::GetMinArray32Size() const
-{
- return SfmtInternal::N32;
-}
+ //=========================================================================
+ // GetMinArray64Size
+ // [4/10/2012]
+ //=========================================================================
+ int Sfmt::GetMinArray64Size() const
+ {
+ return SfmtInternal::N64;
+ }
-//=========================================================================
-// GetMinArray64Size
-// [4/10/2012]
-//=========================================================================
-int
-Sfmt::GetMinArray64Size() const
-{
- return SfmtInternal::N64;
-}
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Memory/AllocationRecords.cpp b/Code/Framework/AzCore/AzCore/Memory/AllocationRecords.cpp
index 680d93501a..2b2f752b06 100644
--- a/Code/Framework/AzCore/AzCore/Memory/AllocationRecords.cpp
+++ b/Code/Framework/AzCore/AzCore/Memory/AllocationRecords.cpp
@@ -16,438 +16,421 @@
#include
-using namespace AZ;
-using namespace AZ::Debug;
+namespace AZ::Debug
+{
+ // Many PC tools break with alloc/free size mismatches when the memory guard is enabled. Disable for now
+ //#define ENABLE_MEMORY_GUARD
-// Many PC tools break with alloc/free size mismatches when the memory guard is enabled. Disable for now
-//#define ENABLE_MEMORY_GUARD
-
-//=========================================================================
-// AllocationRecords
-// [9/16/2009]
-//=========================================================================
-AllocationRecords::AllocationRecords(unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
- : m_mode(AllocatorManager::Instance().m_defaultTrackingRecordMode)
- , m_isAutoIntegrityCheck(false)
- , m_isMarkUnallocatedMemory(isMarkUnallocatedMemory)
- , m_saveNames(false)
- , m_decodeImmediately(false)
- , m_numStackLevels(stackRecordLevels)
+ //=========================================================================
+ // AllocationRecords
+ // [9/16/2009]
+ //=========================================================================
+ AllocationRecords::AllocationRecords(
+ unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, bool isMarkUnallocatedMemory, const char* allocatorName)
+ : m_mode(AllocatorManager::Instance().m_defaultTrackingRecordMode)
+ , m_isAutoIntegrityCheck(false)
+ , m_isMarkUnallocatedMemory(isMarkUnallocatedMemory)
+ , m_saveNames(false)
+ , m_decodeImmediately(false)
+ , m_numStackLevels(stackRecordLevels)
#if defined(ENABLE_MEMORY_GUARD)
- , m_memoryGuardSize(isMemoryGuard ? sizeof(Debug::GuardValue) : 0)
+ , m_memoryGuardSize(isMemoryGuard ? sizeof(Debug::GuardValue) : 0)
#else
- , m_memoryGuardSize(0)
+ , m_memoryGuardSize(0)
#endif
- , m_requestedAllocs(0)
- , m_requestedBytes(0)
- , m_requestedBytesPeak(0)
- , m_allocatorName(allocatorName)
-{
-
-}
-
-//=========================================================================
-// ~AllocationRecords
-// [9/16/2009]
-//=========================================================================
-AllocationRecords::~AllocationRecords()
-{
- if (!AllocatorManager::Instance().m_isAllocatorLeaking)
+ , m_requestedAllocs(0)
+ , m_requestedBytes(0)
+ , m_requestedBytesPeak(0)
+ , m_allocatorName(allocatorName)
{
- // dump all allocation (we should not have any at this point).
- bool includeNameAndFilename = (m_saveNames || m_mode == RECORD_FULL);
- EnumerateAllocations(PrintAllocationsCB(true, includeNameAndFilename));
- AZ_Error("Memory", m_records.empty(), "We still have %d allocations on record! They must be freed prior to destroy!", m_records.size());
- }
-}
-
-//=========================================================================
-// lock
-// [9/16/2009]
-//=========================================================================
-void
-AllocationRecords::lock()
-{
- m_recordsMutex.lock();
-}
-
-//=========================================================================
-// try_lock
-// [9/16/2009]
-//=========================================================================
-bool AllocationRecords::try_lock()
-{
- return m_recordsMutex.try_lock();
-}
-
-//=========================================================================
-// unlock
-// [9/16/2009]
-//=========================================================================
-void
-AllocationRecords::unlock()
-{
- m_recordsMutex.unlock();
-}
-
-//=========================================================================
-// RegisterAllocation
-// [9/11/2009]
-//=========================================================================
-const AllocationInfo*
-AllocationRecords::RegisterAllocation(void* address, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, unsigned int stackSuppressCount)
-{
- (void)stackSuppressCount;
- if (m_mode == RECORD_NO_RECORDS)
- {
- return nullptr;
- }
- if (address == nullptr)
- {
- return nullptr;
}
- // memory guard
- if (m_memoryGuardSize == sizeof(Debug::GuardValue))
+ //=========================================================================
+ // ~AllocationRecords
+ // [9/16/2009]
+ //=========================================================================
+ AllocationRecords::~AllocationRecords()
{
- if (m_isAutoIntegrityCheck)
+ if (!AllocatorManager::Instance().m_isAllocatorLeaking)
{
- IntegrityCheck();
+ // dump all allocation (we should not have any at this point).
+ bool includeNameAndFilename = (m_saveNames || m_mode == RECORD_FULL);
+ EnumerateAllocations(PrintAllocationsCB(true, includeNameAndFilename));
+ AZ_Error(
+ "Memory", m_records.empty(), "We still have %d allocations on record! They must be freed prior to destroy!",
+ m_records.size());
+ }
+ }
+
+ //=========================================================================
+ // lock
+ // [9/16/2009]
+ //=========================================================================
+ void AllocationRecords::lock()
+ {
+ m_recordsMutex.lock();
+ }
+
+ //=========================================================================
+ // try_lock
+ // [9/16/2009]
+ //=========================================================================
+ bool AllocationRecords::try_lock()
+ {
+ return m_recordsMutex.try_lock();
+ }
+
+ //=========================================================================
+ // unlock
+ // [9/16/2009]
+ //=========================================================================
+ void AllocationRecords::unlock()
+ {
+ m_recordsMutex.unlock();
+ }
+
+ //=========================================================================
+ // RegisterAllocation
+ // [9/11/2009]
+ //=========================================================================
+ const AllocationInfo* AllocationRecords::RegisterAllocation(
+ void* address,
+ size_t byteSize,
+ size_t alignment,
+ const char* name,
+ const char* fileName,
+ int lineNum,
+ unsigned int stackSuppressCount)
+ {
+ (void)stackSuppressCount;
+ if (m_mode == RECORD_NO_RECORDS)
+ {
+ return nullptr;
+ }
+ if (address == nullptr)
+ {
+ return nullptr;
}
- AZ_Assert(byteSize>sizeof(Debug::GuardValue), "Did you forget to add the extra MemoryGuardSize() bytes?");
- byteSize -= sizeof(Debug::GuardValue);
- new(reinterpret_cast(address)+byteSize) Debug::GuardValue();
- }
-
- Debug::AllocationRecordsType::pair_iter_bool iterBool;
- {
- AZStd::scoped_lock lock(m_recordsMutex);
- iterBool = m_records.insert_key(address);
- }
-
- if (!iterBool.second)
- {
- // If that memory address was already registered, print the stack trace of the previous registration
- PrintAllocationsCB(true, (m_saveNames || m_mode == RECORD_FULL))(address, iterBool.first->second, m_numStackLevels);
- AZ_Assert(iterBool.second, "Memory address 0x%p is already allocated and in the records!", address);
- }
-
- Debug::AllocationInfo& ai = iterBool.first->second;
- ai.m_byteSize = byteSize;
- ai.m_alignment = static_cast(alignment);
- if ((m_saveNames || m_mode == RECORD_FULL) && name && fileName)
- {
- // In RECORD_FULL mode or when specifically enabled in app descriptor with
- // m_allocationRecordsSaveNames, we allocate our own memory to save off name and fileName.
- // When testing for memory leaks, on process shutdown AllocationRecords::~AllocationRecords
- // gets called to enumerate the remaining (leaked) allocations. Unfortunately, any names
- // referenced in dynamic module memory whose modules are unloaded won't be valid
- // references anymore and we won't get useful information from the enumeration print.
- // This code block ensures we keep our name/fileName valid for when we need it.
- const size_t nameLength = strlen(name);
- const size_t fileNameLength = strlen(fileName);
- const size_t totalLength = nameLength + fileNameLength + 2; // + 2 for terminating null characters
- ai.m_namesBlock = m_records.get_allocator().allocate(totalLength, 1);
- ai.m_namesBlockSize = totalLength;
- char* savedName = reinterpret_cast(ai.m_namesBlock);
- char* savedFileName = savedName + nameLength + 1;
- memcpy(reinterpret_cast(savedName), reinterpret_cast(name), nameLength + 1);
- memcpy(reinterpret_cast(savedFileName), reinterpret_cast(fileName), fileNameLength + 1);
- ai.m_name = savedName;
- ai.m_fileName = savedFileName;
- }
- else
- {
- ai.m_name = name;
- ai.m_fileName = fileName;
- ai.m_namesBlock = nullptr;
- ai.m_namesBlockSize = 0;
- }
- ai.m_lineNum = lineNum;
- ai.m_timeStamp = AZStd::GetTimeNowMicroSecond();
-
- // if we don't have a fileName,lineNum record the stack or if the user requested it.
- if ((fileName == nullptr && m_mode == RECORD_STACK_IF_NO_FILE_LINE) || m_mode == RECORD_FULL)
- {
- ai.m_stackFrames = m_numStackLevels ? reinterpret_cast(m_records.get_allocator().allocate(sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1)) : nullptr;
- if (ai.m_stackFrames)
+ // memory guard
+ if (m_memoryGuardSize == sizeof(Debug::GuardValue))
{
- Debug::StackRecorder::Record(ai.m_stackFrames, m_numStackLevels, stackSuppressCount + 1);
-
- if (m_decodeImmediately)
+ if (m_isAutoIntegrityCheck)
{
- // OPTIONAL DEBUGGING CODE - enable in app descriptor m_allocationRecordsAttemptDecodeImmediately
- // This is optionally-enabled code for tracking down memory allocations
- // that fail to be decoded. DecodeFrames() typically runs at the end of
- // your application when leaks were found. Sometimes you have stack prints
- // full of "(module-name not available)" and "(function-name not available)"
- // that are not actionable. If you have those, enable this code. It'll slow
- // down your process significantly because for every allocation recorded
- // we get the stack trace on the spot. Put a breakpoint in DecodeFrames()
- // at the "(module-name not available)" and "(function-name not available)"
- // locations and now at the moment those allocations happen you'll have the
- // full stack trace available and the ability to debug what could be causing it
+ IntegrityCheck();
+ }
+
+ AZ_Assert(byteSize > sizeof(Debug::GuardValue), "Did you forget to add the extra MemoryGuardSize() bytes?");
+ byteSize -= sizeof(Debug::GuardValue);
+ new (reinterpret_cast(address) + byteSize) Debug::GuardValue();
+ }
+
+ Debug::AllocationRecordsType::pair_iter_bool iterBool;
+ {
+ AZStd::scoped_lock lock(m_recordsMutex);
+ iterBool = m_records.insert_key(address);
+ }
+
+ if (!iterBool.second)
+ {
+ // If that memory address was already registered, print the stack trace of the previous registration
+ PrintAllocationsCB(true, (m_saveNames || m_mode == RECORD_FULL))(address, iterBool.first->second, m_numStackLevels);
+ AZ_Assert(iterBool.second, "Memory address 0x%p is already allocated and in the records!", address);
+ }
+
+ Debug::AllocationInfo& ai = iterBool.first->second;
+ ai.m_byteSize = byteSize;
+ ai.m_alignment = static_cast(alignment);
+ if ((m_saveNames || m_mode == RECORD_FULL) && name && fileName)
+ {
+ // In RECORD_FULL mode or when specifically enabled in app descriptor with
+ // m_allocationRecordsSaveNames, we allocate our own memory to save off name and fileName.
+ // When testing for memory leaks, on process shutdown AllocationRecords::~AllocationRecords
+ // gets called to enumerate the remaining (leaked) allocations. Unfortunately, any names
+ // referenced in dynamic module memory whose modules are unloaded won't be valid
+ // references anymore and we won't get useful information from the enumeration print.
+ // This code block ensures we keep our name/fileName valid for when we need it.
+ const size_t nameLength = strlen(name);
+ const size_t fileNameLength = strlen(fileName);
+ const size_t totalLength = nameLength + fileNameLength + 2; // + 2 for terminating null characters
+ ai.m_namesBlock = m_records.get_allocator().allocate(totalLength, 1);
+ ai.m_namesBlockSize = totalLength;
+ char* savedName = reinterpret_cast(ai.m_namesBlock);
+ char* savedFileName = savedName + nameLength + 1;
+ memcpy(reinterpret_cast(savedName), reinterpret_cast(name), nameLength + 1);
+ memcpy(reinterpret_cast(savedFileName), reinterpret_cast(fileName), fileNameLength + 1);
+ ai.m_name = savedName;
+ ai.m_fileName = savedFileName;
+ }
+ else
+ {
+ ai.m_name = name;
+ ai.m_fileName = fileName;
+ ai.m_namesBlock = nullptr;
+ ai.m_namesBlockSize = 0;
+ }
+ ai.m_lineNum = lineNum;
+ ai.m_timeStamp = AZStd::GetTimeNowMicroSecond();
+
+ // if we don't have a fileName,lineNum record the stack or if the user requested it.
+ if ((fileName == nullptr && m_mode == RECORD_STACK_IF_NO_FILE_LINE) || m_mode == RECORD_FULL)
+ {
+ ai.m_stackFrames = m_numStackLevels ? reinterpret_cast(m_records.get_allocator().allocate(
+ sizeof(AZ::Debug::StackFrame) * m_numStackLevels, 1))
+ : nullptr;
+ if (ai.m_stackFrames)
+ {
+ Debug::StackRecorder::Record(ai.m_stackFrames, m_numStackLevels, stackSuppressCount + 1);
+
+ if (m_decodeImmediately)
{
- const unsigned char decodeStep = 40;
- Debug::SymbolStorage::StackLine lines[decodeStep];
- unsigned char iFrame = 0;
- unsigned char numStackLevels = m_numStackLevels;
- while (numStackLevels > 0)
+ // OPTIONAL DEBUGGING CODE - enable in app descriptor m_allocationRecordsAttemptDecodeImmediately
+ // This is optionally-enabled code for tracking down memory allocations
+ // that fail to be decoded. DecodeFrames() typically runs at the end of
+ // your application when leaks were found. Sometimes you have stack prints
+ // full of "(module-name not available)" and "(function-name not available)"
+ // that are not actionable. If you have those, enable this code. It'll slow
+ // down your process significantly because for every allocation recorded
+ // we get the stack trace on the spot. Put a breakpoint in DecodeFrames()
+ // at the "(module-name not available)" and "(function-name not available)"
+ // locations and now at the moment those allocations happen you'll have the
+ // full stack trace available and the ability to debug what could be causing it
{
- unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
- Debug::SymbolStorage::DecodeFrames(&ai.m_stackFrames[iFrame], numToDecode, lines);
- numStackLevels -= numToDecode;
- iFrame += numToDecode;
+ const unsigned char decodeStep = 40;
+ Debug::SymbolStorage::StackLine lines[decodeStep];
+ unsigned char iFrame = 0;
+ unsigned char numStackLevels = m_numStackLevels;
+ while (numStackLevels > 0)
+ {
+ unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
+ Debug::SymbolStorage::DecodeFrames(&ai.m_stackFrames[iFrame], numToDecode, lines);
+ numStackLevels -= numToDecode;
+ iFrame += numToDecode;
+ }
}
}
}
}
+
+ AllocatorManager::Instance().DebugBreak(address, ai);
+
+ // statistics
+ m_requestedBytes += byteSize;
+
+ size_t currentRequestedBytePeak;
+ size_t newRequestedBytePeak;
+ do
+ {
+ currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
+ newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
+ } while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
+
+ ++m_requestedAllocs;
+
+ return &ai;
}
- AllocatorManager::Instance().DebugBreak(address, ai);
-
- // statistics
- m_requestedBytes += byteSize;
-
- size_t currentRequestedBytePeak;
- size_t newRequestedBytePeak;
- do
+ //=========================================================================
+ // UnregisterAllocation
+ // [9/11/2009]
+ //=========================================================================
+ void AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
{
- currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
- newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
- } while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
-
- ++m_requestedAllocs;
-
- return &ai;
-}
-
-//=========================================================================
-// UnregisterAllocation
-// [9/11/2009]
-//=========================================================================
-void AllocationRecords::UnregisterAllocation(void* address, size_t byteSize, size_t alignment, AllocationInfo* info)
-{
- if (m_mode == RECORD_NO_RECORDS)
- {
- return;
- }
- if (address == nullptr)
- {
- return;
- }
-
- AllocationInfo allocationInfo;
- {
- AZStd::scoped_lock lock(m_recordsMutex);
- Debug::AllocationRecordsType::iterator iter = m_records.find(address);
- // We cannot assert if an allocation does not exist because allocations may have been made before tracking was enabled.
- // It is currently impossible to actually track all allocations that happen before a certain point
- // AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
- if (iter == m_records.end())
+ if (m_mode == RECORD_NO_RECORDS)
{
return;
}
- allocationInfo = iter->second;
- m_records.erase(iter);
-
- // try to be more aggressive and keep the memory footprint low.
- // \todo store the load factor at the last rehash to avoid unnecessary rehash
- if (m_records.load_factor() < 0.9f)
+ if (address == nullptr)
{
- m_records.rehash(0);
+ return;
}
- }
-
- AllocatorManager::Instance().DebugBreak(address, allocationInfo);
-
- (void)byteSize;
- (void)alignment;
- AZ_Assert(byteSize==0||byteSize==allocationInfo.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
- AZ_Assert(alignment==0||alignment==allocationInfo.m_alignment, "Mismatched alignment at deallocation! You supplied an invalid value!");
-
- // statistics
- m_requestedBytes -= allocationInfo.m_byteSize;
-
-#if defined(ENABLE_MEMORY_GUARD)
- // memory guard
- if (m_memoryGuardSize == sizeof(Debug::GuardValue))
- {
- if (m_isAutoIntegrityCheck)
- {
- // full integrity check
- IntegrityCheck();
- }
- else
- {
- // check current allocation
- char* guardAddress = reinterpret_cast(address)+allocationInfo.m_byteSize;
- Debug::GuardValue* guard = reinterpret_cast(guardAddress);
- if (!guard->Validate())
- {
- AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
- PrintAllocationsCB printAlloc(true);
- printAlloc(address, allocationInfo, m_numStackLevels);
- AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
- }
- guard->~GuardValue();
- }
- }
-#endif
-
- // delete allocation record
- if (allocationInfo.m_namesBlock)
- {
- m_records.get_allocator().deallocate(allocationInfo.m_namesBlock, allocationInfo.m_namesBlockSize, 1);
- allocationInfo.m_namesBlock = nullptr;
- allocationInfo.m_namesBlockSize = 0;
- allocationInfo.m_name = nullptr;
- allocationInfo.m_fileName = nullptr;
- }
- if (allocationInfo.m_stackFrames)
- {
- m_records.get_allocator().deallocate(allocationInfo.m_stackFrames, sizeof(AZ::Debug::StackFrame)*m_numStackLevels, 1);
- allocationInfo.m_stackFrames = nullptr;
- }
-
- if (info)
- {
- *info = allocationInfo;
- }
-
-
-
- // if requested set memory to a specific value.
- if (m_isMarkUnallocatedMemory)
- {
- memset(address, GetUnallocatedMarkValue(), byteSize);
- }
-}
-
-//=========================================================================
-// ResizeAllocation
-// [9/20/2009]
-//=========================================================================
-void
-AllocationRecords::ResizeAllocation(void* address, size_t newSize)
-{
- if (m_mode == RECORD_NO_RECORDS)
- {
- return;
- }
-
- AllocationInfo* allocationInfo;
- {
- AZStd::scoped_lock lock(m_recordsMutex);
- Debug::AllocationRecordsType::iterator iter = m_records.find(address);
- AZ_Assert(iter != m_records.end(), "Could not find address 0x%p in the allocator!", address);
- allocationInfo = &iter->second;
- }
- AllocatorManager::Instance().DebugBreak(address, *allocationInfo);
-
-#if defined(ENABLE_MEMORY_GUARD)
- if (m_memoryGuardSize == sizeof(Debug::GuardValue))
- {
- if (m_isAutoIntegrityCheck)
- {
- // full integrity check
- IntegrityCheck();
- }
- else
- {
- // check memory guard
- char* guardAddress = reinterpret_cast(address) + allocationInfo->m_byteSize;
- Debug::GuardValue* guard = reinterpret_cast(guardAddress);
- if (!guard->Validate())
- {
- AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
- PrintAllocationsCB printAlloc(true);
- printAlloc(address, iter->second, m_numStackLevels);
- AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
- }
- guard->~GuardValue();
- }
- // init the new memory guard
- newSize -= sizeof(Debug::GuardValue);
- new(reinterpret_cast(address)+newSize) Debug::GuardValue();
- }
-#endif
-
- // statistics
- m_requestedBytes -= allocationInfo->m_byteSize;
- m_requestedBytes += newSize;
- size_t currentRequestedBytePeak;
- size_t newRequestedBytePeak;
- do
- {
- currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
- newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
- } while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
- ++m_requestedAllocs;
-
- // update allocation size
- allocationInfo->m_byteSize = newSize;
-}
-
-//=========================================================================
-// EnumerateAllocations
-// [9/29/2009]
-//=========================================================================
-void
-AllocationRecords::SetMode(Mode mode)
-{
- if (mode == RECORD_NO_RECORDS)
- {
+ AllocationInfo allocationInfo;
{
AZStd::scoped_lock lock(m_recordsMutex);
- m_records.clear();
+ Debug::AllocationRecordsType::iterator iter = m_records.find(address);
+ // We cannot assert if an allocation does not exist because allocations may have been made before tracking was enabled.
+ // It is currently impossible to actually track all allocations that happen before a certain point
+ // AZ_Assert(iter!=m_records.end(), "Could not find address 0x%p in the allocator!", address);
+ if (iter == m_records.end())
+ {
+ return;
+ }
+ allocationInfo = iter->second;
+ m_records.erase(iter);
+
+ // try to be more aggressive and keep the memory footprint low.
+ // \todo store the load factor at the last rehash to avoid unnecessary rehash
+ if (m_records.load_factor() < 0.9f)
+ {
+ m_records.rehash(0);
+ }
}
- m_requestedBytes = 0;
- m_requestedBytesPeak = 0;
- m_requestedAllocs = 0;
- }
- AZ_Warning("Memory", m_mode != RECORD_NO_RECORDS || mode == RECORD_NO_RECORDS, "Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations which were not recorded!");
+ AllocatorManager::Instance().DebugBreak(address, allocationInfo);
- m_mode = mode;
-}
+ (void)byteSize;
+ (void)alignment;
+ AZ_Assert(
+ byteSize == 0 || byteSize == allocationInfo.m_byteSize, "Mismatched byteSize at deallocation! You supplied an invalid value!");
+ AZ_Assert(
+ alignment == 0 || alignment == allocationInfo.m_alignment,
+ "Mismatched alignment at deallocation! You supplied an invalid value!");
-//=========================================================================
-// EnumerateAllocations
-// [9/29/2009]
-//=========================================================================
-void
-AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
-{
- // enumerate all allocations and stop if requested.
- // Since allocations can change during the iteration (code that prints out the records could allocate, which will
- // mutate m_records), we are going to make a copy and iterate the copy.
- Debug::AllocationRecordsType recordsCopy;
- {
- AZStd::scoped_lock lock(m_recordsMutex);
- recordsCopy = m_records;
- }
- for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
- {
- if (!cb(iter->first, iter->second, m_numStackLevels))
- {
- break;
- }
- }
-}
+ // statistics
+ m_requestedBytes -= allocationInfo.m_byteSize;
-//=========================================================================
-// IntegrityCheck
-// [9/9/2011]
-//=========================================================================
-void
-AllocationRecords::IntegrityCheck() const
-{
#if defined(ENABLE_MEMORY_GUARD)
- if (m_memoryGuardSize == sizeof(Debug::GuardValue))
+ // memory guard
+ if (m_memoryGuardSize == sizeof(Debug::GuardValue))
+ {
+ if (m_isAutoIntegrityCheck)
+ {
+ // full integrity check
+ IntegrityCheck();
+ }
+ else
+ {
+ // check current allocation
+ char* guardAddress = reinterpret_cast(address) + allocationInfo.m_byteSize;
+ Debug::GuardValue* guard = reinterpret_cast(guardAddress);
+ if (!guard->Validate())
+ {
+ AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
+ PrintAllocationsCB printAlloc(true);
+ printAlloc(address, allocationInfo, m_numStackLevels);
+ AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
+ }
+ guard->~GuardValue();
+ }
+ }
+#endif
+
+ // delete allocation record
+ if (allocationInfo.m_namesBlock)
+ {
+ m_records.get_allocator().deallocate(allocationInfo.m_namesBlock, allocationInfo.m_namesBlockSize, 1);
+ allocationInfo.m_namesBlock = nullptr;
+ allocationInfo.m_namesBlockSize = 0;
+ allocationInfo.m_name = nullptr;
+ allocationInfo.m_fileName = nullptr;
+ }
+ if (allocationInfo.m_stackFrames)
+ {
+ m_records.get_allocator().deallocate(allocationInfo.m_stackFrames, sizeof(AZ::Debug::StackFrame) * m_numStackLevels, 1);
+ allocationInfo.m_stackFrames = nullptr;
+ }
+
+ if (info)
+ {
+ *info = allocationInfo;
+ }
+
+ // if requested set memory to a specific value.
+ if (m_isMarkUnallocatedMemory)
+ {
+ memset(address, GetUnallocatedMarkValue(), byteSize);
+ }
+ }
+
+ //=========================================================================
+ // ResizeAllocation
+ // [9/20/2009]
+ //=========================================================================
+ void AllocationRecords::ResizeAllocation(void* address, size_t newSize)
{
+ if (m_mode == RECORD_NO_RECORDS)
+ {
+ return;
+ }
+
+ AllocationInfo* allocationInfo;
+ {
+ AZStd::scoped_lock lock(m_recordsMutex);
+ Debug::AllocationRecordsType::iterator iter = m_records.find(address);
+ AZ_Assert(iter != m_records.end(), "Could not find address 0x%p in the allocator!", address);
+ allocationInfo = &iter->second;
+ }
+ AllocatorManager::Instance().DebugBreak(address, *allocationInfo);
+
+#if defined(ENABLE_MEMORY_GUARD)
+ if (m_memoryGuardSize == sizeof(Debug::GuardValue))
+ {
+ if (m_isAutoIntegrityCheck)
+ {
+ // full integrity check
+ IntegrityCheck();
+ }
+ else
+ {
+ // check memory guard
+ char* guardAddress = reinterpret_cast(address) + allocationInfo->m_byteSize;
+ Debug::GuardValue* guard = reinterpret_cast(guardAddress);
+ if (!guard->Validate())
+ {
+ AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
+ PrintAllocationsCB printAlloc(true);
+ printAlloc(address, iter->second, m_numStackLevels);
+ AZ_Assert(false, "MEMORY STOMP DETECTED!!!");
+ }
+ guard->~GuardValue();
+ }
+ // init the new memory guard
+ newSize -= sizeof(Debug::GuardValue);
+ new (reinterpret_cast(address) + newSize) Debug::GuardValue();
+ }
+#endif
+
+ // statistics
+ m_requestedBytes -= allocationInfo->m_byteSize;
+ m_requestedBytes += newSize;
+ size_t currentRequestedBytePeak;
+ size_t newRequestedBytePeak;
+ do
+ {
+ currentRequestedBytePeak = m_requestedBytesPeak.load(std::memory_order::memory_order_relaxed);
+ newRequestedBytePeak = AZStd::GetMax(currentRequestedBytePeak, m_requestedBytes.load(std::memory_order::memory_order_relaxed));
+ } while (!m_requestedBytesPeak.compare_exchange_weak(currentRequestedBytePeak, newRequestedBytePeak));
+ ++m_requestedAllocs;
+
+ // update allocation size
+ allocationInfo->m_byteSize = newSize;
+ }
+
+ //=========================================================================
+ // EnumerateAllocations
+ // [9/29/2009]
+ //=========================================================================
+ void AllocationRecords::SetMode(Mode mode)
+ {
+ if (mode == RECORD_NO_RECORDS)
+ {
+ {
+ AZStd::scoped_lock lock(m_recordsMutex);
+ m_records.clear();
+ }
+ m_requestedBytes = 0;
+ m_requestedBytesPeak = 0;
+ m_requestedAllocs = 0;
+ }
+
+ AZ_Warning(
+ "Memory", m_mode != RECORD_NO_RECORDS || mode == RECORD_NO_RECORDS,
+ "Records recording was disabled and now it's enabled! You might get assert when you free memory, if a you have allocations "
+ "which were not recorded!");
+
+ m_mode = mode;
+ }
+
+ //=========================================================================
+ // EnumerateAllocations
+ // [9/29/2009]
+ //=========================================================================
+ void AllocationRecords::EnumerateAllocations(AllocationInfoCBType cb)
+ {
+ // enumerate all allocations and stop if requested.
+ // Since allocations can change during the iteration (code that prints out the records could allocate, which will
+ // mutate m_records), we are going to make a copy and iterate the copy.
Debug::AllocationRecordsType recordsCopy;
{
AZStd::scoped_lock lock(m_recordsMutex);
@@ -455,67 +438,93 @@ AllocationRecords::IntegrityCheck() const
}
for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
{
- // check memory guard
- const char* guardAddress = reinterpret_cast(iter->first)+ iter->second.m_byteSize;
- if (!reinterpret_cast(guardAddress)->Validate())
+ if (!cb(iter->first, iter->second, m_numStackLevels))
{
- // We have to turn off the integrity check at this point if we want to succesfully report the memory
- // stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
- // allocation done therein recurses this same code.
- *const_cast(&m_isAutoIntegrityCheck) = false;
- AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
- PrintAllocationsCB printAlloc(true);
- printAlloc(iter->first, iter->second, m_numStackLevels);
- AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
+ break;
}
}
}
-#endif
-}
-//=========================================================================
-// operator()
-// [9/29/2009]
-//=========================================================================
-bool
-PrintAllocationsCB::operator()(void* address, const AllocationInfo& info, unsigned char numStackLevels)
-{
- if (m_includeNameAndFilename && info.m_name)
+ //=========================================================================
+ // IntegrityCheck
+ // [9/9/2011]
+ //=========================================================================
+ void AllocationRecords::IntegrityCheck() const
{
- AZ_Printf("Memory", "Allocation Name: \"%s\" Addr: 0%p Size: %d Alignment: %d\n", info.m_name, address, info.m_byteSize, info.m_alignment);
- }
- else
- {
- AZ_Printf("Memory", "Allocation Addr: 0%p Size: %d Alignment: %d\n", address, info.m_byteSize, info.m_alignment);
- }
-
- if (m_isDetailed)
- {
- if (!info.m_stackFrames)
+#if defined(ENABLE_MEMORY_GUARD)
+ if (m_memoryGuardSize == sizeof(Debug::GuardValue))
{
- AZ_Printf("Memory", " %s (%d)\n", info.m_fileName, info.m_lineNum);
+ Debug::AllocationRecordsType recordsCopy;
+ {
+ AZStd::scoped_lock lock(m_recordsMutex);
+ recordsCopy = m_records;
+ }
+ for (Debug::AllocationRecordsType::const_iterator iter = recordsCopy.begin(); iter != recordsCopy.end(); ++iter)
+ {
+ // check memory guard
+ const char* guardAddress = reinterpret_cast(iter->first) + iter->second.m_byteSize;
+ if (!reinterpret_cast(guardAddress)->Validate())
+ {
+ // We have to turn off the integrity check at this point if we want to succesfully report the memory
+ // stomp we just found. If we don't turn this off, the printf just winds off the stack as each memory
+ // allocation done therein recurses this same code.
+ *const_cast(&m_isAutoIntegrityCheck) = false;
+ AZ_Printf("Memory", "Memory stomp located at address %p, part of allocation:", guardAddress);
+ PrintAllocationsCB printAlloc(true);
+ printAlloc(iter->first, iter->second, m_numStackLevels);
+ AZ_Error("Memory", false, "MEMORY STOMP DETECTED!!!");
+ }
+ }
+ }
+#endif
+ }
+
+ //=========================================================================
+ // operator()
+ // [9/29/2009]
+ //=========================================================================
+ bool PrintAllocationsCB::operator()(void* address, const AllocationInfo& info, unsigned char numStackLevels)
+ {
+ if (m_includeNameAndFilename && info.m_name)
+ {
+ AZ_Printf(
+ "Memory", "Allocation Name: \"%s\" Addr: 0%p Size: %d Alignment: %d\n", info.m_name, address, info.m_byteSize,
+ info.m_alignment);
}
else
{
- // Allocation callstack
- const unsigned char decodeStep = 40;
- Debug::SymbolStorage::StackLine lines[decodeStep];
- unsigned char iFrame = 0;
- while (numStackLevels>0)
+ AZ_Printf("Memory", "Allocation Addr: 0%p Size: %d Alignment: %d\n", address, info.m_byteSize, info.m_alignment);
+ }
+
+ if (m_isDetailed)
+ {
+ if (!info.m_stackFrames)
{
- unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
- Debug::SymbolStorage::DecodeFrames(&info.m_stackFrames[iFrame], numToDecode, lines);
- for (unsigned char i = 0; i < numToDecode; ++i)
+ AZ_Printf("Memory", " %s (%d)\n", info.m_fileName, info.m_lineNum);
+ }
+ else
+ {
+ // Allocation callstack
+ const unsigned char decodeStep = 40;
+ Debug::SymbolStorage::StackLine lines[decodeStep];
+ unsigned char iFrame = 0;
+ while (numStackLevels > 0)
{
- if (info.m_stackFrames[iFrame+i].IsValid())
+ unsigned char numToDecode = AZStd::GetMin(decodeStep, numStackLevels);
+ Debug::SymbolStorage::DecodeFrames(&info.m_stackFrames[iFrame], numToDecode, lines);
+ for (unsigned char i = 0; i < numToDecode; ++i)
{
- AZ_Printf("Memory", " %s\n", lines[i]);
+ if (info.m_stackFrames[iFrame + i].IsValid())
+ {
+ AZ_Printf("Memory", " %s\n", lines[i]);
+ }
}
+ numStackLevels -= numToDecode;
+ iFrame += numToDecode;
}
- numStackLevels -= numToDecode;
- iFrame += numToDecode;
}
}
+ return true; // continue enumerating
}
- return true; // continue enumerating
-}
+
+} // namespace AZ::Debug
diff --git a/Code/Framework/AzCore/AzCore/Memory/AllocatorBase.cpp b/Code/Framework/AzCore/AzCore/Memory/AllocatorBase.cpp
index 61e883bb4e..c2bf9fe45c 100644
--- a/Code/Framework/AzCore/AzCore/Memory/AllocatorBase.cpp
+++ b/Code/Framework/AzCore/AzCore/Memory/AllocatorBase.cpp
@@ -9,191 +9,361 @@
#include
#include
-using namespace AZ;
+#define RECORDING_ENABLED 0
-AllocatorBase::AllocatorBase(IAllocatorAllocate* allocationSource, const char* name, const char* desc) :
- IAllocator(allocationSource),
- m_name(name),
- m_desc(desc)
-{
-}
+#if RECORDING_ENABLED
-AllocatorBase::~AllocatorBase()
-{
- AZ_Assert(!m_isReady, "Allocator %s (%s) is being destructed without first having gone through proper calls to PreDestroy() and Destroy(). Use AllocatorInstance<> for global allocators or AllocatorWrapper<> for local allocators.", m_name, m_desc);
-}
+#include
+#include
+#include
+#include
-const char* AllocatorBase::GetName() const
+namespace
{
- return m_name;
-}
-
-const char* AllocatorBase::GetDescription() const
-{
- return m_desc;
-}
-
-IAllocatorAllocate* AllocatorBase::GetSchema()
-{
- return nullptr;
-}
-
-Debug::AllocationRecords* AllocatorBase::GetRecords()
-{
- return m_records;
-}
-
-void AllocatorBase::SetRecords(Debug::AllocationRecords* records)
-{
- m_records = records;
- m_memoryGuardSize = records ? records->MemoryGuardSize() : 0;
-}
-
-bool AllocatorBase::IsReady() const
-{
- return m_isReady;
-}
-
-bool AllocatorBase::CanBeOverridden() const
-{
- return m_canBeOverridden;
-}
-
-void AllocatorBase::PostCreate()
-{
- if (m_registrationEnabled)
+ class DebugAllocator
{
- if (AZ::Environment::IsReady())
+ public:
+ using pointer_type = void*;
+ using size_type = AZStd::size_t;
+ using difference_type = AZStd::ptrdiff_t;
+ using allow_memory_leaks = AZStd::false_type; ///< Regular allocators should not leak.
+
+ AZ_FORCE_INLINE pointer_type allocate(size_t byteSize, size_t alignment, int = 0)
{
- AllocatorManager::Instance().RegisterAllocator(this);
+ return AZ_OS_MALLOC(byteSize, alignment);
+ }
+ AZ_FORCE_INLINE size_type resize(pointer_type, size_type)
+ {
+ return 0;
+ }
+ AZ_FORCE_INLINE void deallocate(pointer_type ptr, size_type, size_type)
+ {
+ AZ_OS_FREE(ptr);
+ }
+ };
+
+ #pragma pack(push, 1)
+ struct alignas(1) AllocatorOperation
+ {
+ enum OperationType : size_t
+ {
+ ALLOCATE,
+ DEALLOCATE
+ };
+ OperationType m_type: 1;
+ size_t m_size : 28; // Can represent up to 256Mb requests
+ size_t m_alignment : 7; // Can represent up to 128 alignment
+ size_t m_recordId : 28; // Can represent up to 256M simultaneous requests, we reuse ids
+ };
+ #pragma pack(pop)
+ static_assert(sizeof(AllocatorOperation) == 8);
+
+ static AZStd::mutex s_operationsMutex = {};
+
+ static constexpr size_t s_maxNumberOfAllocationsToRecord = 16384;
+ static size_t s_numberOfAllocationsRecorded = 0;
+ static constexpr size_t s_allocationOperationCount = 5 * 1024;
+ static AZStd::array s_operations = {};
+ static uint64_t s_operationCounter = 0;
+
+ static unsigned int s_nextRecordId = 1;
+ using AllocatorOperationByAddress = AZStd::unordered_map, DebugAllocator>;
+ static AllocatorOperationByAddress s_allocatorOperationByAddress;
+ using AvailableRecordIds = AZStd::vector;
+ AvailableRecordIds s_availableRecordIds;
+
+ void RecordAllocatorOperation(AllocatorOperation::OperationType type, void* ptr, size_t size = 0, size_t alignment = 0)
+ {
+ AZStd::scoped_lock lock(s_operationsMutex);
+ if (s_operationCounter == s_allocationOperationCount)
+ {
+ AZ::IO::SystemFile file;
+ int mode = AZ::IO::SystemFile::OpenMode::SF_OPEN_APPEND | AZ::IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY;
+ if (!file.Exists("memoryrecordings.bin"))
+ {
+ mode |= AZ::IO::SystemFile::OpenMode::SF_OPEN_CREATE;
+ }
+ file.Open("memoryrecordings.bin", mode);
+ if (file.IsOpen())
+ {
+ file.Write(&s_operations, sizeof(AllocatorOperation) * s_allocationOperationCount);
+ file.Close();
+ }
+ s_operationCounter = 0;
+ }
+ AllocatorOperation& operation = s_operations[s_operationCounter++];
+ operation.m_type = type;
+ if (type == AllocatorOperation::OperationType::ALLOCATE)
+ {
+ if (s_numberOfAllocationsRecorded > s_maxNumberOfAllocationsToRecord)
+ {
+ // reached limit of allocations, dont record anymore
+ --s_operationCounter;
+ return;
+ }
+ ++s_numberOfAllocationsRecorded;
+ operation.m_size = size;
+ operation.m_alignment = alignment;
+ unsigned int recordId = 0;
+ if (!s_availableRecordIds.empty())
+ {
+ recordId = s_availableRecordIds.back();
+ s_availableRecordIds.pop_back();
+ }
+ else
+ {
+ recordId = s_nextRecordId;
+ ++s_nextRecordId;
+ }
+ operation.m_recordId = recordId;
+ auto it = s_allocatorOperationByAddress.emplace(ptr, operation);
+ if (!it.second)
+ {
+ // double alloc or resize, leave the current record and return the id
+ operation = it.first->second;
+ s_availableRecordIds.emplace_back(recordId);
+ }
}
else
{
- AllocatorManager::PreRegisterAllocator(this);
+ if (ptr == nullptr)
+ {
+ // common scenario, just record the operation
+ operation.m_size = 0;
+ operation.m_alignment = 0;
+ operation.m_recordId = 0; // recordId = 0 will flag this case
+ }
+ else
+ {
+ auto it = s_allocatorOperationByAddress.find(ptr);
+ if (it != s_allocatorOperationByAddress.end())
+ {
+ operation.m_size = it->second.m_size;
+ operation.m_alignment = it->second.m_alignment;
+ operation.m_recordId = it->second.m_recordId;
+ s_availableRecordIds.push_back(it->second.m_recordId);
+ s_allocatorOperationByAddress.erase(it);
+ }
+ else
+ {
+ // just dont record this operation
+ --s_operationCounter;
+ }
+ }
}
+
}
+}
+#endif
- const auto debugConfig = GetDebugConfig();
- if (!debugConfig.m_excludeFromDebugging)
+namespace AZ
+{
+ AllocatorBase::AllocatorBase(IAllocatorAllocate* allocationSource, const char* name, const char* desc)
+ : IAllocator(allocationSource)
+ , m_name(name)
+ , m_desc(desc)
{
- SetRecords(aznew Debug::AllocationRecords((unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory, GetName()));
}
- m_isReady = true;
-}
-
-void AllocatorBase::PreDestroy()
-{
- Debug::AllocationRecords* allocatorRecords = GetRecords();
- if(allocatorRecords)
+ AllocatorBase::~AllocatorBase()
{
- delete allocatorRecords;
- SetRecords(nullptr);
+ AZ_Assert(
+ !m_isReady,
+ "Allocator %s (%s) is being destructed without first having gone through proper calls to PreDestroy() and Destroy(). Use "
+ "AllocatorInstance<> for global allocators or AllocatorWrapper<> for local allocators.",
+ m_name, m_desc);
}
- if (m_registrationEnabled && AZ::AllocatorManager::IsReady())
+ const char* AllocatorBase::GetName() const
{
- AllocatorManager::Instance().UnRegisterAllocator(this);
+ return m_name;
}
- m_isReady = false;
-}
+ const char* AllocatorBase::GetDescription() const
+ {
+ return m_desc;
+ }
-void AllocatorBase::SetLazilyCreated(bool lazy)
-{
- m_isLazilyCreated = lazy;
-}
+ IAllocatorAllocate* AllocatorBase::GetSchema()
+ {
+ return nullptr;
+ }
-bool AllocatorBase::IsLazilyCreated() const
-{
- return m_isLazilyCreated;
-}
+ Debug::AllocationRecords* AllocatorBase::GetRecords()
+ {
+ return m_records;
+ }
-void AllocatorBase::SetProfilingActive(bool active)
-{
- m_isProfilingActive = active;
-}
+ void AllocatorBase::SetRecords(Debug::AllocationRecords* records)
+ {
+ m_records = records;
+ m_memoryGuardSize = records ? records->MemoryGuardSize() : 0;
+ }
-bool AllocatorBase::IsProfilingActive() const
-{
- return m_isProfilingActive;
-}
+ bool AllocatorBase::IsReady() const
+ {
+ return m_isReady;
+ }
-void AllocatorBase::DisableOverriding()
-{
- m_canBeOverridden = false;
-}
+ bool AllocatorBase::CanBeOverridden() const
+ {
+ return m_canBeOverridden;
+ }
-void AllocatorBase::DisableRegistration()
-{
- m_registrationEnabled = false;
-}
+ void AllocatorBase::PostCreate()
+ {
+ if (m_registrationEnabled)
+ {
+ if (AZ::Environment::IsReady())
+ {
+ AllocatorManager::Instance().RegisterAllocator(this);
+ }
+ else
+ {
+ AllocatorManager::PreRegisterAllocator(this);
+ }
+ }
-void AllocatorBase::ProfileAllocation(void* ptr, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, int suppressStackRecord)
-{
+ const auto debugConfig = GetDebugConfig();
+ if (!debugConfig.m_excludeFromDebugging)
+ {
+ SetRecords(aznew Debug::AllocationRecords(
+ (unsigned char)debugConfig.m_stackRecordLevels, debugConfig.m_usesMemoryGuards, debugConfig.m_marksUnallocatedMemory,
+ GetName()));
+ }
+
+ m_isReady = true;
+ }
+
+ void AllocatorBase::PreDestroy()
+ {
+ Debug::AllocationRecords* allocatorRecords = GetRecords();
+ if (allocatorRecords)
+ {
+ delete allocatorRecords;
+ SetRecords(nullptr);
+ }
+
+ if (m_registrationEnabled && AZ::AllocatorManager::IsReady())
+ {
+ AllocatorManager::Instance().UnRegisterAllocator(this);
+ }
+
+ m_isReady = false;
+ }
+
+ void AllocatorBase::SetLazilyCreated(bool lazy)
+ {
+ m_isLazilyCreated = lazy;
+ }
+
+ bool AllocatorBase::IsLazilyCreated() const
+ {
+ return m_isLazilyCreated;
+ }
+
+ void AllocatorBase::SetProfilingActive(bool active)
+ {
+ m_isProfilingActive = active;
+ }
+
+ bool AllocatorBase::IsProfilingActive() const
+ {
+ return m_isProfilingActive;
+ }
+
+ void AllocatorBase::DisableOverriding()
+ {
+ m_canBeOverridden = false;
+ }
+
+ void AllocatorBase::DisableRegistration()
+ {
+ m_registrationEnabled = false;
+ }
+
+ void AllocatorBase::ProfileAllocation(
+ void* ptr, size_t byteSize, size_t alignment, const char* name, const char* fileName, int lineNum, int suppressStackRecord)
+ {
#if defined(AZ_HAS_VARIADIC_TEMPLATES) && defined(AZ_DEBUG_BUILD)
- ++suppressStackRecord; // one more for the fact the ebus is a function
+ ++suppressStackRecord; // one more for the fact the ebus is a function
#endif // AZ_HAS_VARIADIC_TEMPLATES
- if (m_isProfilingActive)
- {
- auto records = GetRecords();
- if (records)
+ if (m_isProfilingActive)
{
- records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
+ auto records = GetRecords();
+ if (records)
+ {
+ records->RegisterAllocation(ptr, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1);
+ }
}
- }
-}
-void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t alignment, Debug::AllocationInfo* info)
-{
- if (m_isProfilingActive)
+#if RECORDING_ENABLED
+ RecordAllocatorOperation(AllocatorOperation::ALLOCATE, ptr, byteSize, alignment);
+#endif
+ }
+
+ void AllocatorBase::ProfileDeallocation(void* ptr, size_t byteSize, size_t alignment, Debug::AllocationInfo* info)
{
- auto records = GetRecords();
- if (records)
+ if (m_isProfilingActive)
{
- records->UnregisterAllocation(ptr, byteSize, alignment, info);
+ auto records = GetRecords();
+ if (records)
+ {
+ records->UnregisterAllocation(ptr, byteSize, alignment, info);
+ }
}
+#if RECORDING_ENABLED
+ RecordAllocatorOperation(AllocatorOperation::DEALLOCATE, ptr, byteSize, alignment);
+#endif
}
-}
-void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
-{
-}
-
-void AllocatorBase::ProfileReallocationEnd(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
-{
- if (m_isProfilingActive)
+ void AllocatorBase::ProfileReallocationBegin([[maybe_unused]] void* ptr, [[maybe_unused]] size_t newSize)
{
- Debug::AllocationInfo info;
- ProfileDeallocation(ptr, 0, 0, &info);
- ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
}
-}
-void AllocatorBase::ProfileReallocation(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
-{
- ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment);
-}
-
-void AllocatorBase::ProfileResize(void* ptr, size_t newSize)
-{
- if (newSize && m_isProfilingActive)
+ void AllocatorBase::ProfileReallocationEnd(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
{
- auto records = GetRecords();
- if (records)
+ if (m_isProfilingActive)
{
- records->ResizeAllocation(ptr, newSize);
+ Debug::AllocationInfo info;
+ ProfileDeallocation(ptr, 0, 0, &info);
+ ProfileAllocation(newPtr, newSize, newAlignment, info.m_name, info.m_fileName, info.m_lineNum, 0);
}
+#if RECORDING_ENABLED
+ RecordAllocatorOperation(AllocatorOperation::DEALLOCATE, ptr);
+ RecordAllocatorOperation(AllocatorOperation::ALLOCATE, newPtr, newSize, newAlignment);
+#endif
}
-}
-bool AllocatorBase::OnOutOfMemory(size_t byteSize, size_t alignment, int flags, const char* name, const char* fileName, int lineNum)
-{
- if (AllocatorManager::IsReady() && AllocatorManager::Instance().m_outOfMemoryListener)
+ void AllocatorBase::ProfileReallocation(void* ptr, void* newPtr, size_t newSize, size_t newAlignment)
{
- AllocatorManager::Instance().m_outOfMemoryListener(this, byteSize, alignment, flags, name, fileName, lineNum);
- return true;
+ ProfileReallocationEnd(ptr, newPtr, newSize, newAlignment);
}
- return false;
-}
+
+ void AllocatorBase::ProfileResize(void* ptr, size_t newSize)
+ {
+ if (newSize && m_isProfilingActive)
+ {
+ auto records = GetRecords();
+ if (records)
+ {
+ records->ResizeAllocation(ptr, newSize);
+ }
+ }
+#if RECORDING_ENABLED
+ RecordAllocatorOperation(AllocatorOperation::ALLOCATE, ptr, newSize);
+#endif
+ }
+
+ bool AllocatorBase::OnOutOfMemory(size_t byteSize, size_t alignment, int flags, const char* name, const char* fileName, int lineNum)
+ {
+ if (AllocatorManager::IsReady() && AllocatorManager::Instance().m_outOfMemoryListener)
+ {
+ AllocatorManager::Instance().m_outOfMemoryListener(this, byteSize, alignment, flags, name, fileName, lineNum);
+ return true;
+ }
+ return false;
+ }
+
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.cpp b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.cpp
index 30b0b78fe5..d55ca8b695 100644
--- a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.cpp
+++ b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.cpp
@@ -13,186 +13,182 @@
#include
-using namespace AZ;
-
-//=========================================================================
-// BestFitExternalMapAllocator
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapAllocator::BestFitExternalMapAllocator()
- : AllocatorBase(this, "BestFitExternalMapAllocator", "Best fit allocator with external tracking storage!")
- , m_schema(nullptr)
-{}
-
-//=========================================================================
-// Create
-// [1/28/2011]
-//=========================================================================
-bool
-BestFitExternalMapAllocator::Create(const Descriptor& desc)
+namespace AZ
{
- AZ_Assert(IsReady() == false, "BestFitExternalMapAllocator was already created!");
- if (IsReady())
+ //=========================================================================
+ // BestFitExternalMapAllocator
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::BestFitExternalMapAllocator()
+ : AllocatorBase(this, "BestFitExternalMapAllocator", "Best fit allocator with external tracking storage!")
+ , m_schema(nullptr)
{
- return false;
}
- bool isReady = true;
-
- m_desc = desc;
- BestFitExternalMapSchema::Descriptor schemaDesc;
- schemaDesc.m_mapAllocator = desc.m_mapAllocator;
- schemaDesc.m_memoryBlock = desc.m_memoryBlock;
- schemaDesc.m_memoryBlockByteSize = desc.m_memoryBlockByteSize;
-
- m_schema = azcreate(BestFitExternalMapSchema, (schemaDesc), SystemAllocator);
- if (m_schema == nullptr)
+ //=========================================================================
+ // Create
+ // [1/28/2011]
+ //=========================================================================
+ bool BestFitExternalMapAllocator::Create(const Descriptor& desc)
{
- isReady = false;
+ AZ_Assert(IsReady() == false, "BestFitExternalMapAllocator was already created!");
+ if (IsReady())
+ {
+ return false;
+ }
+
+ bool isReady = true;
+
+ m_desc = desc;
+ BestFitExternalMapSchema::Descriptor schemaDesc;
+ schemaDesc.m_mapAllocator = desc.m_mapAllocator;
+ schemaDesc.m_memoryBlock = desc.m_memoryBlock;
+ schemaDesc.m_memoryBlockByteSize = desc.m_memoryBlockByteSize;
+
+ m_schema = azcreate(BestFitExternalMapSchema, (schemaDesc), SystemAllocator);
+ if (m_schema == nullptr)
+ {
+ isReady = false;
+ }
+
+ return isReady;
}
- return isReady;
-}
+ //=========================================================================
+ // Destroy
+ // [1/28/2011]
+ //=========================================================================
+ void BestFitExternalMapAllocator::Destroy()
+ {
+ azdestroy(m_schema, SystemAllocator);
+ m_schema = nullptr;
+ }
-//=========================================================================
-// Destroy
-// [1/28/2011]
-//=========================================================================
-void
-BestFitExternalMapAllocator::Destroy()
-{
- azdestroy(m_schema, SystemAllocator);
- m_schema = nullptr;
-}
+ AllocatorDebugConfig BestFitExternalMapAllocator::GetDebugConfig()
+ {
+ return AllocatorDebugConfig()
+ .ExcludeFromDebugging(!m_desc.m_allocationRecords)
+ .StackRecordLevels(m_desc.m_stackRecordLevels)
+ .MarksUnallocatedMemory(false)
+ .UsesMemoryGuards(false);
+ }
-AllocatorDebugConfig BestFitExternalMapAllocator::GetDebugConfig()
-{
- return AllocatorDebugConfig()
- .ExcludeFromDebugging(!m_desc.m_allocationRecords)
- .StackRecordLevels(m_desc.m_stackRecordLevels)
- .MarksUnallocatedMemory(false)
- .UsesMemoryGuards(false);
-}
+ //=========================================================================
+ // Allocate
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::Allocate(
+ size_type byteSize,
+ size_type alignment,
+ int flags,
+ [[maybe_unused]] const char* name,
+ [[maybe_unused]] const char* fileName,
+ [[maybe_unused]] int lineNum,
+ unsigned int suppressStackRecord)
+ {
+ (void)suppressStackRecord;
-//=========================================================================
-// Allocate
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::Allocate(
- size_type byteSize,
- size_type alignment,
- int flags,
- [[maybe_unused]] const char* name,
- [[maybe_unused]] const char* fileName,
- [[maybe_unused]] int lineNum,
- unsigned int suppressStackRecord)
-{
- (void)suppressStackRecord;
+ AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
+ AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
+ byteSize = MemorySizeAdjustedUp(byteSize);
- AZ_Assert(byteSize > 0, "You can not allocate 0 bytes!");
- AZ_Assert((alignment & (alignment - 1)) == 0, "Alignment must be power of 2!");
- byteSize = MemorySizeAdjustedUp(byteSize);
+ BestFitExternalMapAllocator::pointer_type address = m_schema->Allocate(byteSize, alignment, flags);
+ AZ_Assert(
+ address != nullptr, "BestFitExternalMapAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!",
+ byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
+ AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
- BestFitExternalMapAllocator::pointer_type address = m_schema->Allocate(byteSize, alignment, flags);
- AZ_Assert(address != nullptr, "BestFitExternalMapAllocator: Failed to allocate %d bytes aligned on %d (flags: 0x%08x) %s : %s (%d)!", byteSize, alignment, flags, name ? name : "(no name)", fileName ? fileName : "(no file name)", lineNum);
- AZ_MEMORY_PROFILE(ProfileAllocation(address, byteSize, alignment, name, fileName, lineNum, suppressStackRecord + 1));
+ return address;
+ }
- return address;
-}
+ //=========================================================================
+ // DeAllocate
+ // [1/28/2011]
+ //=========================================================================
+ void BestFitExternalMapAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
+ {
+ byteSize = MemorySizeAdjustedUp(byteSize);
+ AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
-//=========================================================================
-// DeAllocate
-// [1/28/2011]
-//=========================================================================
-void
-BestFitExternalMapAllocator::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
-{
- byteSize = MemorySizeAdjustedUp(byteSize);
- AZ_MEMORY_PROFILE(ProfileDeallocation(ptr, byteSize, alignment, nullptr));
+ (void)byteSize;
+ (void)alignment;
+ m_schema->DeAllocate(ptr);
+ }
- (void)byteSize;
- (void)alignment;
- m_schema->DeAllocate(ptr);
-}
+ //=========================================================================
+ // Resize
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::Resize(pointer_type ptr, size_type newSize)
+ {
+ (void)ptr;
+ (void)newSize;
+ /* todo */
+ return 0;
+ }
-//=========================================================================
-// Resize
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapAllocator::size_type
-BestFitExternalMapAllocator::Resize(pointer_type ptr, size_type newSize)
-{
- (void)ptr;
- (void)newSize;
- /* todo */
- return 0;
-}
+ //=========================================================================
+ // ReAllocate
+ // [9/13/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::pointer_type BestFitExternalMapAllocator::ReAllocate(
+ pointer_type ptr, size_type newSize, size_type newAlignment)
+ {
+ (void)ptr;
+ (void)newSize;
+ (void)newAlignment;
+ AZ_Assert(false, "Not supported!");
+ return nullptr;
+ }
-//=========================================================================
-// ReAllocate
-// [9/13/2011]
-//=========================================================================
-BestFitExternalMapAllocator::pointer_type
-BestFitExternalMapAllocator::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
-{
- (void)ptr;
- (void)newSize;
- (void)newAlignment;
- AZ_Assert(false, "Not supported!");
- return nullptr;
-}
+ //=========================================================================
+ // AllocationSize
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::AllocationSize(pointer_type ptr)
+ {
+ return MemorySizeAdjustedDown(m_schema->AllocationSize(ptr));
+ }
-//=========================================================================
-// AllocationSize
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapAllocator::size_type
-BestFitExternalMapAllocator::AllocationSize(pointer_type ptr)
-{
- return MemorySizeAdjustedDown(m_schema->AllocationSize(ptr));
-}
+ //=========================================================================
+ // NumAllocatedBytes
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::NumAllocatedBytes() const
+ {
+ return m_schema->NumAllocatedBytes();
+ }
-//=========================================================================
-// NumAllocatedBytes
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapAllocator::size_type
-BestFitExternalMapAllocator::NumAllocatedBytes() const
-{
- return m_schema->NumAllocatedBytes();
-}
+ //=========================================================================
+ // Capacity
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::Capacity() const
+ {
+ return m_schema->Capacity();
+ }
-//=========================================================================
-// Capacity
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapAllocator::size_type
-BestFitExternalMapAllocator::Capacity() const
-{
- return m_schema->Capacity();
-}
+ //=========================================================================
+ // GetMaxAllocationSize
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapAllocator::size_type BestFitExternalMapAllocator::GetMaxAllocationSize() const
+ {
+ return m_schema->GetMaxAllocationSize();
+ }
-//=========================================================================
-// GetMaxAllocationSize
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapAllocator::size_type
-BestFitExternalMapAllocator::GetMaxAllocationSize() const
-{
- return m_schema->GetMaxAllocationSize();
-}
+ auto BestFitExternalMapAllocator::GetMaxContiguousAllocationSize() const -> size_type
+ {
+ return m_schema->GetMaxContiguousAllocationSize();
+ }
-auto BestFitExternalMapAllocator::GetMaxContiguousAllocationSize() const -> size_type
-{
- return m_schema->GetMaxContiguousAllocationSize();
-}
+ //=========================================================================
+ // GetSubAllocator
+ // [1/28/2011]
+ //=========================================================================
+ IAllocatorAllocate* BestFitExternalMapAllocator::GetSubAllocator()
+ {
+ return m_schema->GetSubAllocator();
+ }
-//=========================================================================
-// GetSubAllocator
-// [1/28/2011]
-//=========================================================================
-IAllocatorAllocate*
-BestFitExternalMapAllocator::GetSubAllocator()
-{
- return m_schema->GetSubAllocator();
-}
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.h b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.h
index 17425625b7..90e2056d65 100644
--- a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.h
+++ b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapAllocator.h
@@ -5,8 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-#ifndef AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
-#define AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
+#pragma once
#include
@@ -76,7 +75,3 @@ namespace AZ
};
}
-#endif // AZ_BEST_FIT_EXT_MAP_ALLOCATOR_H
-#pragma once
-
-
diff --git a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.cpp b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.cpp
index 715ecd221e..841f36f58a 100644
--- a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.cpp
+++ b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.cpp
@@ -9,194 +9,199 @@
#include
#include
-using namespace AZ;
-
-//=========================================================================
-// BestFitExternalMapSchema
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapSchema::BestFitExternalMapSchema(const Descriptor& desc)
- : m_desc(desc)
- , m_used(0)
- , m_freeChunksMap(FreeMapType::key_compare(), AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance::Get()))
- , m_allocChunksMap(AllocMapType::hasher(), AllocMapType::key_eq(), AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance::Get()))
+namespace AZ
{
- if (m_desc.m_mapAllocator == nullptr)
+ //=========================================================================
+ // BestFitExternalMapSchema
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapSchema::BestFitExternalMapSchema(const Descriptor& desc)
+ : m_desc(desc)
+ , m_used(0)
+ , m_freeChunksMap(
+ FreeMapType::key_compare(),
+ AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance::Get()))
+ , m_allocChunksMap(
+ AllocMapType::hasher(),
+ AllocMapType::key_eq(),
+ AZStdIAllocator(desc.m_mapAllocator != nullptr ? desc.m_mapAllocator : &AllocatorInstance::Get()))
{
- m_desc.m_mapAllocator = &AllocatorInstance::Get(); // used as our sub allocator
- }
- AZ_Assert(m_desc.m_memoryBlockByteSize > 0, "You must provide memory block size!");
- AZ_Assert(m_desc.m_memoryBlock != nullptr, "You must provide memory block allocated as you with!");
- //if( m_desc.m_memoryBlock == NULL) there is no point to automate this cause we need to flag this memory special, otherwise there is no point to use this allocator at all
- // m_desc.m_memoryBlock = azmalloc(SystemAllocator,m_desc.m_memoryBlockByteSize,16);
- m_freeChunksMap.insert(AZStd::make_pair(m_desc.m_memoryBlockByteSize, reinterpret_cast(m_desc.m_memoryBlock)));
-}
-
-//=========================================================================
-// Allocate
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapSchema::pointer_type
-BestFitExternalMapSchema::Allocate(size_type byteSize, size_type alignment, int flags)
-{
- (void)flags;
- char* address = nullptr;
- AZ_Assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be >0 and power of 2!");
- for (int i = 0; i < 2; ++i) // max 2 attempts to allocate
- {
- FreeMapType::iterator iter = m_freeChunksMap.find(byteSize);
- size_t blockSize = 0;
- char* blockAddress = nullptr;
- size_t preAllocBlockSize = 0;
- while (iter != m_freeChunksMap.end())
+ if (m_desc.m_mapAllocator == nullptr)
{
- blockSize = iter->first;
- blockAddress = iter->second;
- char* alignedAddr = PointerAlignUp(blockAddress, alignment);
- preAllocBlockSize = alignedAddr - blockAddress;
- if (preAllocBlockSize + byteSize <= blockSize)
- {
- m_freeChunksMap.erase(iter); // we have our allocation
- m_used += byteSize;
- address = alignedAddr;
- m_allocChunksMap.insert(AZStd::make_pair(address, byteSize));
- break;
- }
- ++iter;
+ m_desc.m_mapAllocator = &AllocatorInstance::Get(); // used as our sub allocator
}
- if (address != nullptr)
+ AZ_Assert(m_desc.m_memoryBlockByteSize > 0, "You must provide memory block size!");
+ AZ_Assert(m_desc.m_memoryBlock != nullptr, "You must provide memory block allocated as you with!");
+ // if( m_desc.m_memoryBlock == NULL) there is no point to automate this cause we need to flag this memory special, otherwise there
+ // is no point to use this allocator at all
+ // m_desc.m_memoryBlock = azmalloc(SystemAllocator,m_desc.m_memoryBlockByteSize,16);
+ m_freeChunksMap.insert(AZStd::make_pair(m_desc.m_memoryBlockByteSize, reinterpret_cast(m_desc.m_memoryBlock)));
+ }
+
+ //=========================================================================
+ // Allocate
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapSchema::pointer_type BestFitExternalMapSchema::Allocate(size_type byteSize, size_type alignment, int flags)
+ {
+ (void)flags;
+ char* address = nullptr;
+ AZ_Assert(alignment > 0 && (alignment & (alignment - 1)) == 0, "Alignment must be >0 and power of 2!");
+ for (int i = 0; i < 2; ++i) // max 2 attempts to allocate
{
- // split blocks
- if (preAllocBlockSize) // if we have a block before the alignment
+ FreeMapType::iterator iter = m_freeChunksMap.find(byteSize);
+ size_t blockSize = 0;
+ char* blockAddress = nullptr;
+ size_t preAllocBlockSize = 0;
+ while (iter != m_freeChunksMap.end())
{
- m_freeChunksMap.insert(AZStd::make_pair(preAllocBlockSize, blockAddress));
- }
- size_t postAllocBlockSize = blockSize - preAllocBlockSize - byteSize;
- if (postAllocBlockSize)
- {
- m_freeChunksMap.insert(AZStd::make_pair(postAllocBlockSize, address + byteSize));
- }
-
- break;
- }
- else
- {
- GarbageCollect();
- }
- }
- return address;
-}
-
-//=========================================================================
-// DeAllocate
-// [1/28/2011]
-//=========================================================================
-void
-BestFitExternalMapSchema::DeAllocate(pointer_type ptr)
-{
- if (ptr == nullptr)
- {
- return;
- }
- AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast(ptr));
- if (iter != m_allocChunksMap.end())
- {
- m_used -= iter->second;
- m_freeChunksMap.insert(AZStd::make_pair(iter->second, iter->first));
- m_allocChunksMap.erase(iter);
- }
-}
-
-//=========================================================================
-// AllocationSize
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapSchema::size_type
-BestFitExternalMapSchema::AllocationSize(pointer_type ptr)
-{
- AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast(ptr));
- if (iter != m_allocChunksMap.end())
- {
- return iter->second;
- }
- return 0;
-}
-
-//=========================================================================
-// GetMaxAllocationSize
-// [1/28/2011]
-//=========================================================================
-BestFitExternalMapSchema::size_type
-BestFitExternalMapSchema::GetMaxAllocationSize() const
-{
- if (!m_freeChunksMap.empty())
- {
- return m_freeChunksMap.rbegin()->first;
- }
- return 0;
-}
-
-auto BestFitExternalMapSchema::GetMaxContiguousAllocationSize() const -> size_type
-{
- // Return the maximum size of any single allocation
- return AZ_CORE_MAX_ALLOCATOR_SIZE;
-}
-
-//=========================================================================
-// GarbageCollect
-// [1/28/2011]
-//=========================================================================
-void
-BestFitExternalMapSchema::GarbageCollect()
-{
- for (FreeMapType::iterator curBlock = m_freeChunksMap.begin(); curBlock != m_freeChunksMap.end(); )
- {
- char* curStart = curBlock->second;
- char* curEnd = curStart + curBlock->first;
- bool isMerge = false;
- for (FreeMapType::iterator nextBlock = curBlock++; nextBlock != m_freeChunksMap.end(); )
- {
- char* nextStart = nextBlock->second;
- char* nextEnd = nextStart + nextBlock->first;
- if (curStart == nextEnd)
- {
- // merge
- size_t newBlockSize = curBlock->first + nextBlock->first;
- char* newBlockAddress = nextStart;
- m_freeChunksMap.erase(nextBlock);
- FreeMapType::iterator toErase = curBlock;
- ++curBlock;
- m_freeChunksMap.erase(toErase);
- FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
- if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first) // if the newBlock in before the next in the list, update next in the list to current
+ blockSize = iter->first;
+ blockAddress = iter->second;
+ char* alignedAddr = PointerAlignUp(blockAddress, alignment);
+ preAllocBlockSize = alignedAddr - blockAddress;
+ if (preAllocBlockSize + byteSize <= blockSize)
{
- curBlock = newBlock;
+ m_freeChunksMap.erase(iter); // we have our allocation
+ m_used += byteSize;
+ address = alignedAddr;
+ m_allocChunksMap.insert(AZStd::make_pair(address, byteSize));
+ break;
}
- isMerge = true;
- break;
+ ++iter;
}
- else if (curEnd == nextStart)
+ if (address != nullptr)
{
- // merge
- size_t newBlockSize = curBlock->first + nextBlock->first;
- char* newBlockAddress = curStart;
- m_freeChunksMap.erase(nextBlock);
- FreeMapType::iterator toErase = curBlock;
- ++curBlock;
- m_freeChunksMap.erase(toErase);
- FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
- if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first) // if the newBlock in before the next in the list, update next in the list to current
+ // split blocks
+ if (preAllocBlockSize) // if we have a block before the alignment
{
- curBlock = newBlock;
+ m_freeChunksMap.insert(AZStd::make_pair(preAllocBlockSize, blockAddress));
}
- isMerge = true;
+ size_t postAllocBlockSize = blockSize - preAllocBlockSize - byteSize;
+ if (postAllocBlockSize)
+ {
+ m_freeChunksMap.insert(AZStd::make_pair(postAllocBlockSize, address + byteSize));
+ }
+
break;
}
- ++nextBlock;
+ else
+ {
+ GarbageCollect();
+ }
}
- if (!isMerge)
+ return address;
+ }
+
+ //=========================================================================
+ // DeAllocate
+ // [1/28/2011]
+ //=========================================================================
+ void BestFitExternalMapSchema::DeAllocate(pointer_type ptr)
+ {
+ if (ptr == nullptr)
{
- ++curBlock;
+ return;
+ }
+ AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast(ptr));
+ if (iter != m_allocChunksMap.end())
+ {
+ m_used -= iter->second;
+ m_freeChunksMap.insert(AZStd::make_pair(iter->second, iter->first));
+ m_allocChunksMap.erase(iter);
}
}
-}
+
+ //=========================================================================
+ // AllocationSize
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapSchema::size_type BestFitExternalMapSchema::AllocationSize(pointer_type ptr)
+ {
+ AllocMapType::iterator iter = m_allocChunksMap.find(reinterpret_cast(ptr));
+ if (iter != m_allocChunksMap.end())
+ {
+ return iter->second;
+ }
+ return 0;
+ }
+
+ //=========================================================================
+ // GetMaxAllocationSize
+ // [1/28/2011]
+ //=========================================================================
+ BestFitExternalMapSchema::size_type BestFitExternalMapSchema::GetMaxAllocationSize() const
+ {
+ if (!m_freeChunksMap.empty())
+ {
+ return m_freeChunksMap.rbegin()->first;
+ }
+ return 0;
+ }
+
+ auto BestFitExternalMapSchema::GetMaxContiguousAllocationSize() const -> size_type
+ {
+ // Return the maximum size of any single allocation
+ return AZ_CORE_MAX_ALLOCATOR_SIZE;
+ }
+
+ //=========================================================================
+ // GarbageCollect
+ // [1/28/2011]
+ //=========================================================================
+ void BestFitExternalMapSchema::GarbageCollect()
+ {
+ for (FreeMapType::iterator curBlock = m_freeChunksMap.begin(); curBlock != m_freeChunksMap.end();)
+ {
+ char* curStart = curBlock->second;
+ char* curEnd = curStart + curBlock->first;
+ bool isMerge = false;
+ for (FreeMapType::iterator nextBlock = curBlock++; nextBlock != m_freeChunksMap.end();)
+ {
+ char* nextStart = nextBlock->second;
+ char* nextEnd = nextStart + nextBlock->first;
+ if (curStart == nextEnd)
+ {
+ // merge
+ size_t newBlockSize = curBlock->first + nextBlock->first;
+ char* newBlockAddress = nextStart;
+ m_freeChunksMap.erase(nextBlock);
+ FreeMapType::iterator toErase = curBlock;
+ ++curBlock;
+ m_freeChunksMap.erase(toErase);
+ FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
+ // if the newBlock in before the next in the list, update next in the list to current
+ if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first)
+ {
+ curBlock = newBlock;
+ }
+ isMerge = true;
+ break;
+ }
+ else if (curEnd == nextStart)
+ {
+ // merge
+ size_t newBlockSize = curBlock->first + nextBlock->first;
+ char* newBlockAddress = curStart;
+ m_freeChunksMap.erase(nextBlock);
+ FreeMapType::iterator toErase = curBlock;
+ ++curBlock;
+ m_freeChunksMap.erase(toErase);
+ FreeMapType::iterator newBlock = m_freeChunksMap.insert(AZStd::make_pair(newBlockSize, newBlockAddress)).first;
+ // if the newBlock in before the next in the list, update next in the list to current
+ if (curBlock != m_freeChunksMap.end() && newBlockSize < curBlock->first)
+ {
+ curBlock = newBlock;
+ }
+ isMerge = true;
+ break;
+ }
+ ++nextBlock;
+ }
+ if (!isMerge)
+ {
+ ++curBlock;
+ }
+ }
+ }
+
+} // namespace AZ
diff --git a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.h b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.h
index eaab614593..0055a86ee2 100644
--- a/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.h
+++ b/Code/Framework/AzCore/AzCore/Memory/BestFitExternalMapSchema.h
@@ -5,8 +5,7 @@
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
-#ifndef AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
-#define AZ_BEST_FIT_EXT_MAP_ALLOCATION_SCHEME_H
+#pragma once
#include