diff --git a/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h b/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h index 101b123bb5..6129c3ec08 100644 --- a/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h +++ b/Gems/ImGui/Code/Include/LYImGuiUtils/HistogramContainer.h @@ -18,8 +18,7 @@ namespace ImGui namespace LYImGuiUtils { /** - * A small class to help manage values for an ImGui Histogram ( ImGui doesn't want to manage the values itself ). - * Nothing crazy, just helps reduce boiler plate if you are ImGui::PlotHistogram()'ing + * A small class to help manage values for an ImGui Histogram (ImGui is not managing values itself). */ class HistogramContainer { @@ -40,9 +39,24 @@ namespace ImGui // Static Type to String function static const char* ViewTypeToString(ViewType viewType); + //! Horizontal move direction of the histogram when pushing new values. + enum MoveDirection : AZ::u8 + { + PushLeftMoveRight = 0, //! Push new values to the front of the buffer, which corresponds to the left side, and make the histogram move to the right. + PushRightMoveLeft = 1, //! Push new values to the back of the buffer, which corresponds to the right side, and make the histogram move to the left. + }; + + //! Mode determining the min and max values for the visible range of the vertical axis for the histogram. + enum ScaleMode : AZ::u8 + { + NoAutoScale = 0, //! Use the min and max values given by Init() as visible range. + AutoExpand = 1, //! Expand scale in case a sample is out of the current bounds. Does only expand the scale but not decrease it back again. + AutoScale = 2, //! Use a running average to expand and shrink the visible range. + }; + // Do all of the set up via Init - void Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale - , bool autoExpandScale, bool startCollapsed = false, bool drawMostRecentValue = true); + void Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale, + ScaleMode scaleMode = AutoScale, bool startCollapsed = false, bool drawMostRecentValue = true); // How many values are in the container currently int GetSize() { return static_cast(m_values.size()); } @@ -50,9 +64,6 @@ namespace ImGui // What is the max size of the container int GetMaxSize() { return m_maxSize; } - // Set the Max Size and clear the container - void SetMaxSize(int size) { m_values.clear(); m_maxSize = size; } - // Push a value to this histogram container void PushValue(float val); @@ -65,7 +76,18 @@ namespace ImGui // Draw this histogram with ImGui void Draw(float histogramWidth, float histogramHeight); + //! Adjust the scale mode to determine the min and max values for the visible range of the vertical axis for the histogram. + void SetScaleMode(ScaleMode scaleMode) { m_scaleMode = scaleMode; } + + //! Adjust the horizontal move direction of the histogram when pushing new values. + void SetMoveDirection(MoveDirection moveDirection) { m_moveDirection = moveDirection; } + + //! Calculate the min and maximum values for the present samples. + void CalcMinMaxValues(float& outMin, float& outMax); + private: + // Set the Max Size and clear the container + void SetMaxSize(int size); AZStd::string m_histogramName; AZStd::deque m_values; @@ -73,8 +95,10 @@ namespace ImGui ViewType m_viewType = ViewType::Histogram; float m_minScale; float m_maxScale; + MoveDirection m_moveDirection = PushLeftMoveRight; //! Specify if values will be added on the left and the histogram moves right or the other way around. bool m_dispalyOverlays; - bool m_autoExpandScale; + ScaleMode m_scaleMode; //! Determines if the vertical range of the histogram will be manually specified, auto-expanded or automatically scaled based on the samples. + float m_autoScaleSpeed = 0.05f; //! Indicates how fast the min max values and the visible vertical range are adapting to new samples. bool m_collapsed; bool m_drawMostRecentValueText; }; diff --git a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp index 1df74903e6..e079a01de1 100644 --- a/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp +++ b/Gems/ImGui/Code/Source/LYCommonMenu/ImGuiLYCameraMonitor.cpp @@ -34,13 +34,13 @@ namespace ImGui ImGuiCameraMonitorRequestBus::Handler::BusConnect(); // Init Histogram Containers - m_dofMinZHisto.Init( "DOF Min Z", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); - m_dofMinZBlendMultHisto.Init( "DOF Min Z Blend Mult", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f, true); - m_dofMinZScaleHisto.Init( "DOF Min Z Scale", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f, true); + m_dofMinZHisto.Init( "DOF Min Z", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); + m_dofMinZBlendMultHisto.Init( "DOF Min Z Blend Mult", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f); + m_dofMinZScaleHisto.Init( "DOF Min Z Scale", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 50.0f, 50.0f); - m_globalActiveCamInfo.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f, true); - m_globalActiveCamInfo.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); - m_globalActiveCamInfo.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); + m_globalActiveCamInfo.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f); + m_globalActiveCamInfo.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); + m_globalActiveCamInfo.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); } void ImGuiLYCameraMonitor::Shutdown() @@ -214,7 +214,7 @@ namespace ImGui } // save this cam off as the current one m_currentCamera = newCamId; - + // create a new empty CameraInfo in the queue m_cameraHistory.push_front(CameraInfo()); @@ -224,9 +224,9 @@ namespace ImGui AZ::ComponentApplicationBus::BroadcastResult(newCam.m_camName, &AZ::ComponentApplicationBus::Events::GetEntityName, m_currentCamera); newCam.m_activeTime = 0.0f; newCam.m_activeFrames = 0; - newCam.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f, true); - newCam.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); - newCam.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f, true); + newCam.m_fovHisto.Init( "FOV", 120, LYImGuiUtils::HistogramContainer::ViewType::Lines, true, 50.0f, 50.0f); + newCam.m_facingVectorDeltaHisto.Init( "Facing Vec Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); + newCam.m_positionDeltaHisto.Init( "Position Frame Delta", 120, LYImGuiUtils::HistogramContainer::ViewType::Histogram, true, 0.0f, 0.0f); // reset a few variables on the global camera info m_globalActiveCamInfo.m_camId = newCam.m_camId; diff --git a/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp b/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp index e3fd3f2054..1915cc3721 100644 --- a/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp +++ b/Gems/ImGui/Code/Source/LYImGuiUtils/HistogramContainer.cpp @@ -16,45 +16,92 @@ namespace ImGui { namespace LYImGuiUtils { - void HistogramContainer::Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale - , bool autoExpandScale, bool startCollapsed/* = false*/, bool drawMostRecentValue/* = true*/) + void HistogramContainer::Init(const char* histogramName, int maxValueCountSize, ViewType viewType, bool displayOverlays, float minScale, float maxScale, + ScaleMode scaleMode, bool startCollapsed/* = false*/, bool drawMostRecentValue/* = true*/) { m_histogramName = histogramName; m_minScale = minScale; m_maxScale = maxScale; m_viewType = viewType; m_dispalyOverlays = displayOverlays; - m_autoExpandScale = autoExpandScale; + m_scaleMode = scaleMode; m_collapsed = startCollapsed; m_drawMostRecentValueText = drawMostRecentValue; SetMaxSize(maxValueCountSize); } - void HistogramContainer::PushValue(float val) + void HistogramContainer::SetMaxSize(int size) + { + m_values.resize(size); + m_maxSize = size; + + // Pre-fill the histogram with zeros so that the bars do not fill the space and + // scale horizontally when there are not enough samples yet. + for (float& value : m_values) + { + value = 0.0f; + } + } + + void HistogramContainer::PushValue(float value) { if (m_maxSize == 0) { return; } + if (m_values.size() == m_maxSize) { - m_values.pop_back(); + if (m_moveDirection == PushLeftMoveRight) + { + m_values.pop_back(); + } + else + { + m_values.pop_front(); + } } else if (m_values.size() > m_maxSize) { m_values.erase(m_values.begin() + (m_maxSize - 1), m_values.end()); } - m_values.push_front(val); - if (m_autoExpandScale) + if (m_moveDirection == PushLeftMoveRight) { - if (val < m_minScale) + m_values.push_front(value); + } + else + { + m_values.push_back(value); + } + + switch (m_scaleMode) + { + case AutoExpand: { - m_minScale = val; + if (value < m_minScale) + { + m_minScale = value; + } + else if (value > m_maxScale) + { + m_maxScale = value; + } + break; } - else if (val > m_maxScale) + case AutoScale: { - m_maxScale = val; + float min = 0.0f; + float max = 0.0f; + CalcMinMaxValues(min, max); + + m_minScale = AZ::Lerp(m_minScale, min, m_autoScaleSpeed); + m_maxScale = AZ::Lerp(m_maxScale, max, m_autoScaleSpeed); + break; + } + default: + { + break; } } } @@ -86,7 +133,6 @@ namespace ImGui ImGui::DragInt("History Size", &m_maxSize, 1, 1, 1000, "%f"); ImGui::DragFloat("Max Scale", &m_maxScale, 0.0001f, -100.0f, 100.0f); ImGui::DragFloat("Min Scale", &m_minScale, 0.0001f, -100.0f, 100.0f); - ImGui::Checkbox("Auto Expand Scale", &m_autoExpandScale); ImGui::EndPopup(); } @@ -157,6 +203,26 @@ namespace ImGui return "Lines"; } } + + void HistogramContainer::CalcMinMaxValues(float& outMin, float& outMax) + { + // Use the manually set min and max scale values in case there are no samples. + if (m_values.empty()) + { + outMin = m_minScale; + outMax = m_maxScale; + return; + } + + outMin = +AZ::Constants::FloatMax; + outMax = -AZ::Constants::FloatMax; + + for (const float x : m_values) + { + outMin = AZ::GetMin(outMin, x); + outMax = AZ::GetMax(outMax, x); + } + } } } #endif // #ifdef IMGUI_ENABLED