Forráskód Böngészése

Added photosensitive seizure warnings.

A new AtomSampleComponent base class is shared by all ASV samples. If any sample needs to warn the user about its content, there is a ContentWarning variable that can be overridden. The SampleComponentManager will display the warning before opening that sample. I also added similar warnings when opening the Script Runner and Pre-Commit Wizard dialogs, because any automation script is likely to cause flashing images.

Note that I also remove the ability to use Ctrl-0 through Ctrl-9 to open samples. It only worked for the first 10 samples, and was useful in the early days of AtomSampleViewer when we couldn’t show ImGui during RHI samples. Now that all samples keep ImGui visible, we can stop maintaining this feature.

Fixes https://github.com/o3de/o3de-atom-sampleviewer/issues/398

Signed-off-by: santorac <[email protected]>
santorac 3 éve
szülő
commit
dbeb75b6c9

+ 14 - 0
Gem/Code/Source/AtomSampleComponent.cpp

@@ -0,0 +1,14 @@
+/*
+ * 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 <AtomSampleComponent.h>
+
+namespace AtomSampleViewer
+{
+
+}

+ 31 - 0
Gem/Code/Source/AtomSampleComponent.h

@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+
+namespace AtomSampleViewer
+{
+    class AtomSampleComponent
+        : public AZ::Component
+    {
+    public:
+        AZ_RTTI(AtomSampleComponent, "{2318DFD6-BC6B-4335-9F25-8E270A10CA81}", AZ::Component);
+
+        AtomSampleComponent() = default;
+        ~AtomSampleComponent() override = default;
+
+        // Redefine this string in the sample component subclass to provide a sample-specific warning message.
+        // Any non-empty string will automatically cause a warning message to be displayed before opening the sample.
+        static constexpr const char* ContentWarning = "";
+        
+        // This is a common photosensitive/seizure warning that could be used for the above ContentWarning in specific samples as needed.
+        static constexpr const char CommonPhotosensitiveWarning[] = "This sample includes flashing images that could cause seizures or other adverse effects in photosensitive individuals.";
+    };
+} // namespace AtomSampleViewer

+ 3 - 3
Gem/Code/Source/CommonSampleComponentBase.h

@@ -8,7 +8,7 @@
 
 
 #pragma once
 #pragma once
 
 
-#include <AzCore/Component/Component.h>
+#include <AtomSampleComponent.h>
 #include <AzCore/Component/TransformBus.h>
 #include <AzCore/Component/TransformBus.h>
 #include <AzCore/Component/EntityBus.h>
 #include <AzCore/Component/EntityBus.h>
 #include <AzFramework/Entity/EntityContextBus.h>
 #include <AzFramework/Entity/EntityContextBus.h>
@@ -25,12 +25,12 @@
 namespace AtomSampleViewer
 namespace AtomSampleViewer
 {
 {
     class CommonSampleComponentBase
     class CommonSampleComponentBase
-        : public AZ::Component
+        : public AtomSampleComponent
         , public AZ::TransformNotificationBus::MultiHandler
         , public AZ::TransformNotificationBus::MultiHandler
         , public AZ::EntityBus::MultiHandler
         , public AZ::EntityBus::MultiHandler
     {
     {
     public:
     public:
-        AZ_TYPE_INFO(CommonSampleComponentBase, "{7EECDF09-B774-46C1-AD6E-060CE5717C05}");
+        AZ_RTTI(CommonSampleComponentBase, "{7EECDF09-B774-46C1-AD6E-060CE5717C05}", AtomSampleComponent);
 
 
         static void Reflect(AZ::ReflectContext* context);
         static void Reflect(AZ::ReflectContext* context);
 
 

+ 3 - 3
Gem/Code/Source/RHI/BasicRHIComponent.h

@@ -7,7 +7,7 @@
  */
  */
 
 
 #pragma once
 #pragma once
-#include <AzCore/Component/Component.h>
+#include <AtomSampleComponent.h>
 #include <AzCore/std/smart_ptr/shared_ptr.h>
 #include <AzCore/std/smart_ptr/shared_ptr.h>
 
 
 #include <Atom/RPI.Public/Image/StreamingImage.h>
 #include <Atom/RPI.Public/Image/StreamingImage.h>
@@ -81,13 +81,13 @@ namespace AtomSampleViewer
     };
     };
 
 
     class BasicRHIComponent
     class BasicRHIComponent
-        : public AZ::Component
+        : public AtomSampleComponent
         , public AZ::RHI::RHISystemNotificationBus::Handler
         , public AZ::RHI::RHISystemNotificationBus::Handler
     {
     {
         friend class RHISamplePass;
         friend class RHISamplePass;
 
 
     public:
     public:
-        AZ_RTTI(BasicRHIComponent, "{FAB340E4-2D91-48CD-A7BC-81ED25721415}", AZ::Component);
+        AZ_RTTI(BasicRHIComponent, "{FAB340E4-2D91-48CD-A7BC-81ED25721415}", AtomSampleComponent);
 
 
         BasicRHIComponent() = default;
         BasicRHIComponent() = default;
         ~BasicRHIComponent() override = default;
         ~BasicRHIComponent() override = default;

+ 2 - 0
Gem/Code/Source/RHI/MultiViewportSwapchainComponent.h

@@ -30,6 +30,8 @@ namespace AtomSampleViewer
         , public AzFramework::WindowNotificationBus::Handler
         , public AzFramework::WindowNotificationBus::Handler
     {
     {
     public:
     public:
+        static constexpr const char* ContentWarning = CommonPhotosensitiveWarning;
+
         AZ_COMPONENT(MultiViewportSwapchainComponent, "{45118741-F7DB-4EE0-9EBF-59B85D7F6194}", AZ::Component);
         AZ_COMPONENT(MultiViewportSwapchainComponent, "{45118741-F7DB-4EE0-9EBF-59B85D7F6194}", AZ::Component);
         AZ_DISABLE_COPY(MultiViewportSwapchainComponent);
         AZ_DISABLE_COPY(MultiViewportSwapchainComponent);
 
 

+ 2 - 0
Gem/Code/Source/RHI/SwapchainExampleComponent.h

@@ -18,6 +18,8 @@ namespace AtomSampleViewer
         , public AZ::TickBus::Handler
         , public AZ::TickBus::Handler
     {
     {
     public:
     public:
+        static constexpr const char* ContentWarning = CommonPhotosensitiveWarning;
+
         AZ_COMPONENT(SwapchainExampleComponent, "{F8A990AD-63C0-43D8-AE9B-FB9D84CB58E2}", AZ::Component);
         AZ_COMPONENT(SwapchainExampleComponent, "{F8A990AD-63C0-43D8-AE9B-FB9D84CB58E2}", AZ::Component);
 
 
         static void Reflect(AZ::ReflectContext* context);
         static void Reflect(AZ::ReflectContext* context);

+ 35 - 45
Gem/Code/Source/SampleComponentManager.cpp

@@ -165,6 +165,7 @@ namespace AtomSampleViewer
         entry.m_componentDescriptor = T::CreateDescriptor();
         entry.m_componentDescriptor = T::CreateDescriptor();
         entry.m_parentMenuName = menuName;
         entry.m_parentMenuName = menuName;
         entry.m_fullName = entry.m_parentMenuName + '/' + entry.m_sampleName;
         entry.m_fullName = entry.m_parentMenuName + '/' + entry.m_sampleName;
+        entry.m_contentWarning = T::ContentWarning;
 
 
         return entry;
         return entry;
     }
     }
@@ -333,8 +334,6 @@ namespace AtomSampleViewer
         m_exampleEntity = aznew AZ::Entity();
         m_exampleEntity = aznew AZ::Entity();
 
 
         m_entityContextId = AzFramework::EntityContextId::CreateNull();
         m_entityContextId = AzFramework::EntityContextId::CreateNull();
-
-        memset(m_alphanumericNumbersDown, 0, s_alphanumericCount);
     }
     }
 
 
     SampleComponentManager::~SampleComponentManager()
     SampleComponentManager::~SampleComponentManager()
@@ -556,16 +555,6 @@ namespace AtomSampleViewer
             {
             {
                 screenshotRequest = true;
                 screenshotRequest = true;
             }
             }
-
-            for (size_t i = 0; i < m_availableSamples.size(); ++i)
-            {
-                if (m_alphanumericNumbersDown[i] && i < s_alphanumericCount && m_isSampleSupported[i])
-                {
-                    m_sampleChangeRequest = true;
-                    m_selectedSampleIndex = static_cast<int32_t>(i);
-                    break;
-                }
-            }
         }
         }
 
 
         // Request a frame capture only once per key press, even if the keys are held down for multiple ticks.
         // Request a frame capture only once per key press, even if the keys are held down for multiple ticks.
@@ -705,14 +694,6 @@ namespace AtomSampleViewer
                 m_escapeDown = true;
                 m_escapeDown = true;
             }
             }
 
 
-            for (size_t i = 0; i < samplesAvailableCount; ++i)
-            {
-                if ((i < s_alphanumericCount) && (inputChannelId == sampleInputMapping[i]))
-                {
-                    m_alphanumericNumbersDown[i] = true;
-                }
-            }
-
             break;
             break;
         }
         }
         case AzFramework::InputChannel::State::Ended:
         case AzFramework::InputChannel::State::Ended:
@@ -742,14 +723,6 @@ namespace AtomSampleViewer
                 m_escapeDown = false;
                 m_escapeDown = false;
             }
             }
 
 
-            for (size_t i = 0; i < samplesAvailableCount; ++i)
-            {
-                if ((i < s_alphanumericCount) && (inputChannelId == sampleInputMapping[i]))
-                {
-                    m_alphanumericNumbersDown[i] = false;
-                }
-            }
-
             break;
             break;
         }
         }
         default:
         default:
@@ -852,6 +825,7 @@ namespace AtomSampleViewer
 
 
         m_scriptManager->TickImGui();
         m_scriptManager->TickImGui();
 
 
+        m_contentWarningDialog.TickPopup();
     }
     }
 
 
     void SampleComponentManager::ShowMenuBar()
     void SampleComponentManager::ShowMenuBar()
@@ -928,35 +902,37 @@ namespace AtomSampleViewer
                             SampleEntry& sample = m_availableSamples[index];
                             SampleEntry& sample = m_availableSamples[index];
                             const char* sampleName = sample.m_sampleName.c_str();
                             const char* sampleName = sample.m_sampleName.c_str();
                             bool enabled = m_isSampleSupported[index];
                             bool enabled = m_isSampleSupported[index];
-                            if (index < s_alphanumericCount)
+
+                            if (ImGui::MenuItem(sampleName, nullptr, false, enabled))
                             {
                             {
-                                const AZStd::string hotkeyName = AZStd::string::format("Ctrl-%d: ", (index + 1) % 10);
+                                Utils::ReportScriptableAction("OpenSample('%s')", sample.m_sampleName.c_str());
 
 
-                                if (ImGui::MenuItem(sampleName, hotkeyName.c_str(), false, enabled))
+                                if (sample.m_contentWarning.empty())
                                 {
                                 {
-                                    m_selectedSampleIndex = index;
                                     m_sampleChangeRequest = true;
                                     m_sampleChangeRequest = true;
+                                    m_selectedSampleIndex = index;
                                 }
                                 }
-                            }
-                            else
-                            {
-                                if (ImGui::MenuItem(sampleName, nullptr, false, enabled))
+                                else
                                 {
                                 {
-                                    m_selectedSampleIndex = index;
-                                    m_sampleChangeRequest = true;
+                                    m_contentWarningDialog.OpenPopupConfirmation(
+                                        "Sample Content Warning",
+                                        sample.m_contentWarning,
+                                        [this, index]() {
+                                            m_sampleChangeRequest = true;
+                                            m_selectedSampleIndex = index;
+                                        });
                                 }
                                 }
+
                             }
                             }
+
+
+
                         }
                         }
 
 
                         ImGui::EndMenu();
                         ImGui::EndMenu();
                     }
                     }
                 }
                 }
 
 
-                if (m_sampleChangeRequest)
-                {
-                    Utils::ReportScriptableAction("OpenSample('%s')", m_availableSamples[m_selectedSampleIndex].m_sampleName.c_str());
-                }
-
                 ImGui::EndMenu();
                 ImGui::EndMenu();
             }
             }
 #ifdef AZ_PROFILE_TELEMETRY
 #ifdef AZ_PROFILE_TELEMETRY
@@ -972,13 +948,27 @@ namespace AtomSampleViewer
 
 
             if (ImGui::BeginMenu("Automation"))
             if (ImGui::BeginMenu("Automation"))
             {
             {
+                const char* AutomationContentWarningTitle = "Sample Content Warning";
+                const char* AutomationContentWarning = "Running automated scripts will trigger flashing images that could cause seizures or other adverse effects in photosensitive individuals.";
+
                 if (ImGui::MenuItem("Run Script..."))
                 if (ImGui::MenuItem("Run Script..."))
                 {
                 {
-                    m_scriptManager->OpenScriptRunnerDialog();
+                    m_contentWarningDialog.OpenPopupConfirmation(
+                        AutomationContentWarningTitle,
+                        AutomationContentWarning,
+                        [this]() {
+                            m_scriptManager->OpenScriptRunnerDialog();
+                        });
+
                 }
                 }
                 if (ImGui::MenuItem("Run Precommit Wizard..."))
                 if (ImGui::MenuItem("Run Precommit Wizard..."))
                 {
                 {
-                    m_scriptManager->OpenPrecommitWizard();
+                    m_contentWarningDialog.OpenPopupConfirmation(
+                        AutomationContentWarningTitle,
+                        AutomationContentWarning,
+                        [this]() {
+                            m_scriptManager->OpenPrecommitWizard();
+                        });
                 }
                 }
 
 
                 ImGui::EndMenu();
                 ImGui::EndMenu();

+ 4 - 4
Gem/Code/Source/SampleComponentManager.h

@@ -40,6 +40,7 @@
 
 
 #include <Utils/ImGuiSaveFilePath.h>
 #include <Utils/ImGuiSaveFilePath.h>
 #include <Utils/ImGuiHistogramQueue.h>
 #include <Utils/ImGuiHistogramQueue.h>
+#include <Utils/ImGuiMessageBox.h>
 
 
 namespace AZ
 namespace AZ
 {
 {
@@ -67,6 +68,7 @@ namespace AtomSampleViewer
         AZStd::function<bool()> m_isSupportedFunc;
         AZStd::function<bool()> m_isSupportedFunc;
         SamplePipelineType m_pipelineType = SamplePipelineType::RHI;
         SamplePipelineType m_pipelineType = SamplePipelineType::RHI;
         AZ::ComponentDescriptor* m_componentDescriptor;
         AZ::ComponentDescriptor* m_componentDescriptor;
+        AZStd::string m_contentWarning;
 
 
         bool operator==(const SampleEntry& other)
         bool operator==(const SampleEntry& other)
         {
         {
@@ -200,6 +202,8 @@ namespace AtomSampleViewer
         static constexpr uint32_t FrameTimeLogSize = 30;
         static constexpr uint32_t FrameTimeLogSize = 30;
         ImGuiHistogramQueue m_imGuiFrameTimer;
         ImGuiHistogramQueue m_imGuiFrameTimer;
 
 
+        ImGuiMessageBox m_contentWarningDialog;
+
         bool m_showImGuiMetrics = false;
         bool m_showImGuiMetrics = false;
         bool m_showSampleHelper = false;
         bool m_showSampleHelper = false;
         bool m_showResizeViewportDialog = false;
         bool m_showResizeViewportDialog = false;
@@ -228,10 +232,6 @@ namespace AtomSampleViewer
         bool m_canSwitchSample = true;
         bool m_canSwitchSample = true;
         bool m_canCaptureRADTM = true;
         bool m_canCaptureRADTM = true;
 
 
-        // 10 number keys 0-9
-        static constexpr size_t s_alphanumericCount = 10;
-        bool m_alphanumericNumbersDown[s_alphanumericCount];
-
         bool m_exitRequested = false;
         bool m_exitRequested = false;
 
 
         AzFramework::EntityContextId m_entityContextId;
         AzFramework::EntityContextId m_entityContextId;

+ 5 - 0
Gem/Code/Source/SceneReloadSoakTestComponent.h

@@ -27,6 +27,11 @@ namespace AtomSampleViewer
         using Base = EntityLatticeTestComponent;
         using Base = EntityLatticeTestComponent;
     public:
     public:
         AZ_COMPONENT(SceneReloadSoakTestComponent, "{5D0B03A6-F7B9-4952-90AB-C91306229964}", EntityLatticeTestComponent);
         AZ_COMPONENT(SceneReloadSoakTestComponent, "{5D0B03A6-F7B9-4952-90AB-C91306229964}", EntityLatticeTestComponent);
+
+        // Instead of using the CommonPhotosensitiveWarning, I used a custom message here that specifically calls out headaches and nausea
+        // as I've personally experienced those while looking at this sample, even though I don't otherwise consider myself to be photosensitive.
+        static constexpr const char ContentWarning[] = "This sample has lots of flashing, may cause headaches and nausea, or may cause seizures for people with certain photosensitivity.";
+
         SceneReloadSoakTestComponent() = default;
         SceneReloadSoakTestComponent() = default;
 
 
         static void Reflect(AZ::ReflectContext* context);
         static void Reflect(AZ::ReflectContext* context);

+ 2 - 2
Gem/Code/Source/ShaderReloadTestComponent.h

@@ -8,10 +8,10 @@
 
 
 #pragma once
 #pragma once
 
 
+#include <AtomSampleComponent.h>
 #include <Atom/Bootstrap/DefaultWindowBus.h>
 #include <Atom/Bootstrap/DefaultWindowBus.h>
 #include <Atom/Feature/ImGui/ImGuiUtils.h>
 #include <Atom/Feature/ImGui/ImGuiUtils.h>
 
 
-#include <AzCore/Component/Component.h>
 #include <AzCore/Component/EntityBus.h>
 #include <AzCore/Component/EntityBus.h>
 #include <AzCore/Component/TickBus.h>
 #include <AzCore/Component/TickBus.h>
 
 
@@ -28,7 +28,7 @@ namespace AtomSampleViewer
     // to render a FullscreenTrianglePass, with the purpose on validating that the
     // to render a FullscreenTrianglePass, with the purpose on validating that the
     // shader reload notification events work properly.
     // shader reload notification events work properly.
     class ShaderReloadTestComponent final
     class ShaderReloadTestComponent final
-        : public AZ::Component
+        : public AtomSampleComponent
         , public AZ::Render::Bootstrap::DefaultWindowNotificationBus::Handler
         , public AZ::Render::Bootstrap::DefaultWindowNotificationBus::Handler
         , public AZ::TickBus::Handler
         , public AZ::TickBus::Handler
     {
     {

+ 2 - 0
Gem/Code/atomsampleviewergem_private_files.cmake

@@ -7,6 +7,8 @@
 #
 #
 
 
 set(FILES
 set(FILES
+    Source/AtomSampleComponent.cpp
+    Source/AtomSampleComponent.h
     Source/AtomSampleViewerOptions.h
     Source/AtomSampleViewerOptions.h
     Source/AtomSampleViewerSystemComponent.cpp
     Source/AtomSampleViewerSystemComponent.cpp
     Source/AtomSampleViewerSystemComponent.h
     Source/AtomSampleViewerSystemComponent.h