Merge branch 'stabilization/2110' into Atom/santorac/FixedThinObjectTransmission

This commit is contained in:
santorac
2021-11-08 10:18:18 -08:00
86 changed files with 905 additions and 1062 deletions
@@ -50,6 +50,7 @@ def NvCloth_AddClothSimulationToActor():
# Constants
FRAMES_IN_GAME_MODE = 200
CLOTH_GEM_ERROR_WARNING_LIST = ["Cloth", "NvCloth", "ClothComponentMesh", "ActorClothSkinning", "ActorClothSkinning", "TangentSpaceHelper", "MeshAssetHelper", "ActorAssetHelper", "ClothDebugDisplay"]
helper.init_idle()
# 1) Load the level
@@ -64,14 +65,16 @@ def NvCloth_AddClothSimulationToActor():
general.idle_wait_frames(FRAMES_IN_GAME_MODE)
# 5) Verify there are no errors and warnings in the logs
success_condition = not (section_tracer.has_errors or section_tracer.has_warnings)
Report.result(Tests.no_errors_and_warnings_found, success_condition)
if not success_condition:
if section_tracer.has_warnings:
Report.info(f"Warnings found: {section_tracer.warnings}")
if section_tracer.has_errors:
Report.info(f"Errors found: {section_tracer.errors}")
Report.failure(Tests.no_errors_and_warnings_found)
has_errors_or_warnings = False
for error_msg in section_tracer.errors:
if error_msg.window in CLOTH_GEM_ERROR_WARNING_LIST:
has_errors_or_warnings = True
Report.info(f"Cloth error found: {error_msg}")
for warning_msg in section_tracer.warnings:
if warning_msg.window in CLOTH_GEM_ERROR_WARNING_LIST:
has_errors_or_warnings = True
Report.info(f"Cloth warning found: {warning_msg}")
Report.result(Tests.no_errors_and_warnings_found, not has_errors_or_warnings)
# 6) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
@@ -50,6 +50,7 @@ def NvCloth_AddClothSimulationToMesh():
# Constants
FRAMES_IN_GAME_MODE = 200
CLOTH_GEM_ERROR_WARNING_LIST = ["Cloth", "NvCloth", "ClothComponentMesh", "ActorClothSkinning", "ActorClothSkinning", "TangentSpaceHelper", "MeshAssetHelper", "ActorAssetHelper", "ClothDebugDisplay"]
helper.init_idle()
# 1) Load the level
@@ -64,14 +65,16 @@ def NvCloth_AddClothSimulationToMesh():
general.idle_wait_frames(FRAMES_IN_GAME_MODE)
# 5) Verify there are no errors and warnings in the logs
success_condition = not (section_tracer.has_errors or section_tracer.has_warnings)
Report.result(Tests.no_errors_and_warnings_found, success_condition)
if not success_condition:
if section_tracer.has_warnings:
Report.info(f"Warnings found: {section_tracer.warnings}")
if section_tracer.has_errors:
Report.info(f"Errors found: {section_tracer.errors}")
Report.failure(Tests.no_errors_and_warnings_found)
has_errors_or_warnings = False
for error_msg in section_tracer.errors:
if error_msg.window in CLOTH_GEM_ERROR_WARNING_LIST:
has_errors_or_warnings = True
Report.info(f"Cloth error found: {error_msg}")
for warning_msg in section_tracer.warnings:
if warning_msg.window in CLOTH_GEM_ERROR_WARNING_LIST:
has_errors_or_warnings = True
Report.info(f"Cloth warning found: {warning_msg}")
Report.result(Tests.no_errors_and_warnings_found, not has_errors_or_warnings)
# 6) Exit game mode
helper.exit_game_mode(Tests.exit_game_mode)
@@ -13,9 +13,32 @@
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/Render/IntersectorInterface.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
#include <EditorViewportSettings.h>
AZ_CVAR(
bool,
ed_cameraPinDefaultOrbit,
true,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Sets whether the default orbit point moves with the camera or not");
AZ_CVAR(
bool,
ed_cameraDefaultOrbitAxesOrtho,
true,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Sets whether to draw the default orbit point as orthographic or not");
AZ_CVAR(
float,
ed_cameraDefaultOrbitFadeDuration,
0.5f,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"Sets how long the default orbit point should take to appear and disappear");
namespace SandboxEditor
{
static AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds()
@@ -174,7 +197,7 @@ namespace SandboxEditor
return SandboxEditor::CameraScrollSpeed();
};
const auto pivotFn = []
const auto pivotFn = []() -> AZStd::optional<AZ::Vector3>
{
// use the manipulator transform as the pivot point
AZStd::optional<AZ::Transform> entityPivot;
@@ -187,8 +210,7 @@ namespace SandboxEditor
return entityPivot->GetTranslation();
}
// otherwise just use the identity
return AZ::Vector3::CreateZero();
return AZStd::nullopt;
};
m_firstPersonFocusCamera =
@@ -199,9 +221,26 @@ namespace SandboxEditor
m_orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>(SandboxEditor::CameraOrbitChannelId());
m_orbitCamera->SetPivotFn(
[pivotFn]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
[this, pivotFn](const AZ::Vector3& position, const AZ::Vector3& direction)
{
return pivotFn();
// return the pivot
if (auto pivot = pivotFn())
{
return pivot.value();
}
// start ticking and drawing (for the default pivot)
AZ::TickBus::Handler::BusConnect();
AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
m_defaultOrbiting = true;
// calculate the default orbit point
if (!ed_cameraPinDefaultOrbit || m_orbitCamera->Beginning())
{
m_defaultOrbitPoint = position + direction * SandboxEditor::CameraDefaultOrbitDistance();
}
return m_defaultOrbitPoint;
});
m_orbitRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(SandboxEditor::CameraOrbitLookChannelId());
@@ -306,4 +345,67 @@ namespace SandboxEditor
m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::ClearReferenceFrame);
}
}
void EditorModularViewportCameraComposer::OnTick(const float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
{
const float delta = [duration = &ed_cameraDefaultOrbitFadeDuration, deltaTime] {
if (*duration == 0.0f) {
return 1.0f;
}
return deltaTime / *duration;
}();
if (m_defaultOrbiting)
{
m_defaultOrbitOpacity = AZStd::min(m_defaultOrbitOpacity + delta, 1.0f);
}
else
{
m_defaultOrbitOpacity = AZStd::max(m_defaultOrbitOpacity - delta, 0.0f);
if (m_defaultOrbitOpacity == 0.0f)
{
AZ::TickBus::Handler::BusDisconnect();
AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect();
}
}
m_defaultOrbiting = false;
}
static void DrawTransformAxis(
AzFramework::DebugDisplayRequests& display,
const AzFramework::CameraState& cameraState,
const AZ::Vector3& pivot,
const float axisLength,
const float alpha)
{
const int prevState = display.GetState();
display.DepthWriteOff();
display.DepthTestOff();
display.CullOff();
const float orthoScale =
ed_cameraDefaultOrbitAxesOrtho ? AzToolsFramework::CalculateScreenToWorldMultiplier(pivot, cameraState) : 1.0f;
display.SetColor(AZ::Color::CreateFromVector3AndFloat(AZ::Colors::Red.GetAsVector3(), alpha));
display.DrawLine(pivot, pivot + AZ::Vector3::CreateAxisX() * axisLength * orthoScale);
display.SetColor(AZ::Color::CreateFromVector3AndFloat(AZ::Colors::LawnGreen.GetAsVector3(), alpha));
display.DrawLine(pivot, pivot + AZ::Vector3::CreateAxisY() * axisLength * orthoScale);
display.SetColor(AZ::Color::CreateFromVector3AndFloat(AZ::Colors::Blue.GetAsVector3(), alpha));
display.DrawLine(pivot, pivot + AZ::Vector3::CreateAxisZ() * axisLength * orthoScale);
display.DepthWriteOn();
display.DepthTestOn();
display.CullOn();
display.SetState(prevState);
}
void EditorModularViewportCameraComposer::DisplayViewport(
[[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
{
DrawTransformAxis(
debugDisplay, AzToolsFramework::GetCameraState(viewportInfo.m_viewportId), m_defaultOrbitPoint, 1.0f, m_defaultOrbitOpacity);
}
} // namespace SandboxEditor
@@ -9,6 +9,8 @@
#pragma once
#include <AtomToolsFramework/Viewport/ModularViewportCameraController.h>
#include <AzCore/Component/TickBus.h>
#include <AzFramework/Entity/EntityDebugDisplayBus.h>
#include <AzFramework/Viewport/CameraInput.h>
#include <AzToolsFramework/API/EditorCameraBus.h>
#include <EditorModularViewportCameraComposerBus.h>
@@ -20,6 +22,8 @@ namespace SandboxEditor
class EditorModularViewportCameraComposer
: private EditorModularViewportCameraComposerNotificationBus::Handler
, private Camera::EditorCameraNotificationBus::Handler
, private AzFramework::ViewportDebugDisplayEventBus::Handler
, private AZ::TickBus::Handler
{
public:
SANDBOX_API explicit EditorModularViewportCameraComposer(AzFramework::ViewportId viewportId);
@@ -29,6 +33,12 @@ namespace SandboxEditor
SANDBOX_API AZStd::shared_ptr<AtomToolsFramework::ModularViewportCameraController> CreateModularViewportCameraController();
private:
// AzFramework::ViewportDebugDisplayEventBus overrides ...
void DisplayViewport(const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay) override;
// AZ::TickBus overrides ...
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
//! Setup all internal camera inputs.
void SetupCameras();
@@ -52,5 +62,9 @@ namespace SandboxEditor
AZStd::shared_ptr<AzFramework::FocusCameraInput> m_orbitFocusCamera;
AzFramework::ViewportId m_viewportId;
float m_defaultOrbitOpacity = 0.0f; //!< The default orbit axes opacity (to fade in and out).
AZ::Vector3 m_defaultOrbitPoint = AZ::Vector3::CreateZero(); //!< The orbit point to use when no entity is selected.
bool m_defaultOrbiting = false; //!< Is the camera default orbiting (orbiting when there's no selected entity).
};
} // namespace SandboxEditor
@@ -61,7 +61,7 @@ static AZStd::vector<AZStd::string> GetEditorInputNames()
void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serialize)
{
serialize.Class<CameraMovementSettings>()
->Version(3)
->Version(4)
->Field("TranslateSpeed", &CameraMovementSettings::m_translateSpeed)
->Field("RotateSpeed", &CameraMovementSettings::m_rotateSpeed)
->Field("BoostMultiplier", &CameraMovementSettings::m_boostMultiplier)
@@ -76,9 +76,8 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
->Field("OrbitYawRotationInverted", &CameraMovementSettings::m_orbitYawRotationInverted)
->Field("PanInvertedX", &CameraMovementSettings::m_panInvertedX)
->Field("PanInvertedY", &CameraMovementSettings::m_panInvertedY)
->Field("DefaultPositionX", &CameraMovementSettings::m_defaultCameraPositionX)
->Field("DefaultPositionY", &CameraMovementSettings::m_defaultCameraPositionY)
->Field("DefaultPositionZ", &CameraMovementSettings::m_defaultCameraPositionZ);
->Field("DefaultPosition", &CameraMovementSettings::m_defaultPosition)
->Field("DefaultOrbitDistance", &CameraMovementSettings::m_defaultOrbitDistance);
serialize.Class<CameraInputSettings>()
->Version(2)
@@ -159,14 +158,12 @@ void CEditorPreferencesPage_ViewportCamera::Reflect(AZ::SerializeContext& serial
AZ::Edit::UIHandlers::CheckBox, &CameraMovementSettings::m_captureCursorLook, "Camera Capture Look Cursor",
"Should the cursor be captured (hidden) while performing free look")
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultCameraPositionX, "Default X Camera Position",
"Default X Camera Position when a level is opened")
AZ::Edit::UIHandlers::Vector3, &CameraMovementSettings::m_defaultPosition, "Default Camera Position",
"Default Camera Position when a level is first opened")
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultCameraPositionY, "Default Y Camera Position",
"Default Y Camera Position when a level is opened")
->DataElement(
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultCameraPositionZ, "Default Z Camera Position",
"Default Z Camera Position when a level is opened");
AZ::Edit::UIHandlers::SpinBox, &CameraMovementSettings::m_defaultOrbitDistance, "Default Orbit Distance",
"The default distance to orbit about when there is no entity selected")
->Attribute(AZ::Edit::Attributes::Min, minValue);
editContext->Class<CameraInputSettings>("Camera Input Settings", "")
->DataElement(
@@ -283,12 +280,8 @@ void CEditorPreferencesPage_ViewportCamera::OnApply()
SandboxEditor::SetCameraOrbitYawRotationInverted(m_cameraMovementSettings.m_orbitYawRotationInverted);
SandboxEditor::SetCameraPanInvertedX(m_cameraMovementSettings.m_panInvertedX);
SandboxEditor::SetCameraPanInvertedY(m_cameraMovementSettings.m_panInvertedY);
SandboxEditor::SetDefaultCameraEditorPosition(
AZ::Vector3(
m_cameraMovementSettings.m_defaultCameraPositionX,
m_cameraMovementSettings.m_defaultCameraPositionY,
m_cameraMovementSettings.m_defaultCameraPositionZ
));
SandboxEditor::SetCameraDefaultEditorPosition(m_cameraMovementSettings.m_defaultPosition);
SandboxEditor::SetCameraDefaultOrbitDistance(m_cameraMovementSettings.m_defaultOrbitDistance);
SandboxEditor::SetCameraTranslateForwardChannelId(m_cameraInputSettings.m_translateForwardChannelId);
SandboxEditor::SetCameraTranslateBackwardChannelId(m_cameraInputSettings.m_translateBackwardChannelId);
@@ -325,11 +318,8 @@ void CEditorPreferencesPage_ViewportCamera::InitializeSettings()
m_cameraMovementSettings.m_orbitYawRotationInverted = SandboxEditor::CameraOrbitYawRotationInverted();
m_cameraMovementSettings.m_panInvertedX = SandboxEditor::CameraPanInvertedX();
m_cameraMovementSettings.m_panInvertedY = SandboxEditor::CameraPanInvertedY();
AZ::Vector3 defaultCameraPosition = SandboxEditor::DefaultEditorCameraPosition();
m_cameraMovementSettings.m_defaultCameraPositionX = defaultCameraPosition.GetX();
m_cameraMovementSettings.m_defaultCameraPositionY = defaultCameraPosition.GetY();
m_cameraMovementSettings.m_defaultCameraPositionZ = defaultCameraPosition.GetZ();
m_cameraMovementSettings.m_defaultPosition = SandboxEditor::CameraDefaultEditorPosition();
m_cameraMovementSettings.m_defaultOrbitDistance = SandboxEditor::CameraDefaultOrbitDistance();
m_cameraInputSettings.m_translateForwardChannelId = SandboxEditor::CameraTranslateForwardChannelId().GetName();
m_cameraInputSettings.m_translateBackwardChannelId = SandboxEditor::CameraTranslateBackwardChannelId().GetName();
@@ -9,9 +9,12 @@
#pragma once
#include "Include/IPreferencesPage.h"
#include <AzCore/Math/Vector3.h>
#include <AzCore/RTTI/RTTI.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <QIcon>
inline AZ::Crc32 EditorPropertyVisibility(const bool enabled)
@@ -43,6 +46,7 @@ private:
{
AZ_TYPE_INFO(CameraMovementSettings, "{60B8C07E-5F48-4171-A50B-F45558B5CCA1}")
AZ::Vector3 m_defaultPosition;
float m_translateSpeed;
float m_rotateSpeed;
float m_scrollSpeed;
@@ -50,16 +54,14 @@ private:
float m_panSpeed;
float m_boostMultiplier;
float m_rotateSmoothness;
bool m_rotateSmoothing;
float m_translateSmoothness;
bool m_translateSmoothing;
float m_defaultOrbitDistance;
bool m_captureCursorLook;
bool m_orbitYawRotationInverted;
bool m_panInvertedX;
bool m_panInvertedY;
float m_defaultCameraPositionX;
float m_defaultCameraPositionY;
float m_defaultCameraPositionZ;
bool m_rotateSmoothing;
bool m_translateSmoothing;
AZ::Crc32 RotateSmoothingVisibility() const
{
+17 -6
View File
@@ -38,6 +38,7 @@ namespace SandboxEditor
constexpr AZStd::string_view CameraTranslateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/TranslateSmoothing";
constexpr AZStd::string_view CameraRotateSmoothingSetting = "/Amazon/Preferences/Editor/Camera/RotateSmoothing";
constexpr AZStd::string_view CameraCaptureCursorLookSetting = "/Amazon/Preferences/Editor/Camera/CaptureCursorLook";
constexpr AZStd::string_view CameraDefaultOrbitDistanceSetting = "/Amazon/Preferences/Editor/Camera/DefaultOrbitDistance";
constexpr AZStd::string_view CameraTranslateForwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateForwardId";
constexpr AZStd::string_view CameraTranslateBackwardIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateBackwardId";
constexpr AZStd::string_view CameraTranslateLeftIdSetting = "/Amazon/Preferences/Editor/Camera/CameraTranslateLeftId";
@@ -114,15 +115,15 @@ namespace SandboxEditor
return AZStd::make_unique<EditorViewportSettingsCallbacksImpl>();
}
AZ::Vector3 DefaultEditorCameraPosition()
AZ::Vector3 CameraDefaultEditorPosition()
{
float xPosition = aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionX, 0.0));
float yPosition = aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionY, -10.0));
float zPosition = aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionZ, 4.0));
return AZ::Vector3(xPosition, yPosition, zPosition);
return AZ::Vector3(
aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionX, 0.0)),
aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionY, -10.0)),
aznumeric_cast<float>(GetRegistry(CameraDefaultStartingPositionZ, 4.0)));
}
void SetDefaultCameraEditorPosition(const AZ::Vector3 defaultCameraPosition)
void SetCameraDefaultEditorPosition(const AZ::Vector3& defaultCameraPosition)
{
SetRegistry(CameraDefaultStartingPositionX, defaultCameraPosition.GetX());
SetRegistry(CameraDefaultStartingPositionY, defaultCameraPosition.GetY());
@@ -359,6 +360,16 @@ namespace SandboxEditor
SetRegistry(CameraCaptureCursorLookSetting, capture);
}
float CameraDefaultOrbitDistance()
{
return aznumeric_cast<float>(GetRegistry(CameraDefaultOrbitDistanceSetting, 20.0));
}
void SetCameraDefaultOrbitDistance(const float distance)
{
SetRegistry(CameraDefaultOrbitDistanceSetting, distance);
}
AzFramework::InputChannelId CameraTranslateForwardChannelId()
{
return AzFramework::InputChannelId(
+6 -3
View File
@@ -33,9 +33,6 @@ namespace SandboxEditor
//! event will fire when a value in the settings registry (editorpreferences.setreg) is modified.
SANDBOX_API AZStd::unique_ptr<EditorViewportSettingsCallbacks> CreateEditorViewportSettingsCallbacks();
SANDBOX_API AZ::Vector3 DefaultEditorCameraPosition();
SANDBOX_API void SetDefaultCameraEditorPosition(AZ::Vector3 defaultCameraPosition);
SANDBOX_API AZ::u64 MaxItemsShownInAssetBrowserSearch();
SANDBOX_API void SetMaxItemsShownInAssetBrowserSearch(AZ::u64 numberOfItemsShown);
@@ -105,6 +102,12 @@ namespace SandboxEditor
SANDBOX_API bool CameraCaptureCursorForLook();
SANDBOX_API void SetCameraCaptureCursorForLook(bool capture);
SANDBOX_API AZ::Vector3 CameraDefaultEditorPosition();
SANDBOX_API void SetCameraDefaultEditorPosition(const AZ::Vector3& position);
SANDBOX_API float CameraDefaultOrbitDistance();
SANDBOX_API void SetCameraDefaultOrbitDistance(float distance);
SANDBOX_API AzFramework::InputChannelId CameraTranslateForwardChannelId();
SANDBOX_API void SetCameraTranslateForwardChannelId(AZStd::string_view cameraTranslateForwardId);
+9 -9
View File
@@ -620,9 +620,9 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event)
break;
case eNotify_OnEndNewScene:
PopDisableRendering();
{
PopDisableRendering();
Matrix34 viewTM;
viewTM.SetIdentity();
@@ -638,9 +638,9 @@ void EditorViewportWidget::OnEditorNotifyEvent(EEditorNotifyEvent event)
break;
case eNotify_OnEndTerrainCreate:
PopDisableRendering();
{
PopDisableRendering();
Matrix34 viewTM;
viewTM.SetIdentity();
@@ -2021,10 +2021,6 @@ void EditorViewportWidget::SetDefaultCamera()
GetViewManager()->SetCameraObjectId(GUID_NULL);
SetName(m_defaultViewName);
// Set the default Editor Camera position.
m_defaultViewTM.SetTranslation(Vec3(m_editorViewportSettings.DefaultEditorCameraPosition()));
SetViewTM(m_defaultViewTM);
// Synchronize the configured editor viewport FOV to the default camera
if (m_viewPane)
{
@@ -2041,6 +2037,10 @@ void EditorViewportWidget::SetDefaultCamera()
atomViewportRequests->PushView(contextName, m_defaultView);
}
// Set the default Editor Camera position.
m_defaultViewTM.SetTranslation(Vec3(m_editorViewportSettings.DefaultEditorCameraPosition()));
SetViewTM(m_defaultViewTM);
PostCameraSet();
}
@@ -2527,7 +2527,7 @@ bool EditorViewportSettings::StickySelectEnabled() const
AZ::Vector3 EditorViewportSettings::DefaultEditorCameraPosition() const
{
return SandboxEditor::DefaultEditorCameraPosition();
return SandboxEditor::CameraDefaultEditorPosition();
}
AZ_CVAR_EXTERNED(bool, ed_previewGameInFullscreen_once);
@@ -806,12 +806,20 @@ namespace AzFramework
[[maybe_unused]] float scrollDelta,
[[maybe_unused]] float deltaTime)
{
const auto pivot = m_pivotFn();
if (!pivot.has_value())
{
EndActivation();
return targetCamera;
}
if (Beginning())
{
// as the camera starts, record the camera we would like to end up as
m_nextCamera.m_offset = m_offsetFn(m_pivotFn().GetDistance(targetCamera.Translation()));
m_nextCamera.m_offset = m_offsetFn(pivot.value().GetDistance(targetCamera.Translation()));
const auto angles =
EulerAngles(AZ::Matrix3x3::CreateFromMatrix3x4(AZ::Matrix3x4::CreateLookAt(targetCamera.Translation(), m_pivotFn())));
EulerAngles(AZ::Matrix3x3::CreateFromMatrix3x4(AZ::Matrix3x4::CreateLookAt(targetCamera.Translation(), pivot.value())));
m_nextCamera.m_pitch = angles.GetX();
m_nextCamera.m_yaw = angles.GetZ();
m_nextCamera.m_pivot = targetCamera.m_pivot;
@@ -651,7 +651,7 @@ namespace AzFramework
class FocusCameraInput : public CameraInput
{
public:
using PivotFn = AZStd::function<AZ::Vector3()>;
using PivotFn = AZStd::function<AZStd::optional<AZ::Vector3>()>;
FocusCameraInput(const InputChannelId& focusChannelId, FocusOffsetFn offsetFn);
@@ -10,6 +10,8 @@
#include <AzCore/IO/SystemFile.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include <AzFramework/Process/ProcessWatcher.h>
#include <sys/types.h>
#include <unistd.h>
@@ -24,14 +26,20 @@ namespace AzFramework::AssetSystem::Platform
AZ::IO::FixedMaxPath assetProcessorPath{ executableDirectory };
// In Mac the Editor and game is within a bundle, so the path to the sibling app
// has to go up from the Contents/MacOS folder the binary is in
assetProcessorPath /= "../../../AssetProcessor.app";
assetProcessorPath /= "../../../AssetProcessor.app/Contents/MacOS/AssetProcessor";
assetProcessorPath = assetProcessorPath.LexicallyNormal();
if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str()))
{
// Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure.
assetProcessorPath =
AZ::IO::FixedMaxPath{engineRoot} / "bin" / AZ_TRAIT_OS_PLATFORM_NAME / AZ_BUILD_CONFIGURATION_TYPE / "AssetProcessor.app";
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
if (AZ::IO::FixedMaxPath installedBinariesPath;
settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
{
// Check for existence of one under a "bin" directory, i.e. engineRoot is an SDK structure.
assetProcessorPath = AZ::IO::FixedMaxPath{ engineRoot } / installedBinariesPath / "AssetProcessor.app/Contents/MacOS/AssetProcessor";
}
}
if (!AZ::IO::SystemFile::Exists(assetProcessorPath.c_str()))
{
@@ -39,23 +47,21 @@ namespace AzFramework::AssetSystem::Platform
}
}
auto fullLaunchCommand = AZ::IO::FixedMaxPathString::format(R"(open -g "%s" --args --start-hidden)", assetProcessorPath.c_str());
AZStd::string commandLineParams;
// Add the engine path to the launch command if not empty
if (!engineRoot.empty())
{
fullLaunchCommand += R"( --engine-path=")";
fullLaunchCommand += engineRoot;
fullLaunchCommand += '"';
commandLineParams += AZStd::string::format("\"--engine-path=\"%s\"\"", engineRoot.data());
}
// Add the active project path to the launch command if not empty
if (!projectPath.empty())
{
fullLaunchCommand += R"( --project-path=")";
fullLaunchCommand += projectPath;
fullLaunchCommand += '"';
commandLineParams += AZStd::string::format(" \"--regset=/Amazon/AzCore/Bootstrap/project_path=\"%s\"\"", projectPath.data());
}
return system(fullLaunchCommand.c_str()) == 0;
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
processLaunchInfo.m_processExecutableString = AZStd::move(assetProcessorPath.Native());
processLaunchInfo.m_commandlineParameters = commandLineParams;
return AzFramework::ProcessLauncher::LaunchUnwatchedProcess(processLaunchInfo);
}
}
@@ -40,9 +40,9 @@ namespace AzToolsFramework
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QModelIndex parent(const QModelIndex& child) const override;
QModelIndex sibling(int row, int column, const QModelIndex& idx) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
protected:
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role /* = Qt::DisplayRole */) const override;
////////////////////////////////////////////////////////////////////
@@ -55,7 +55,7 @@ namespace AzToolsFramework
private slots:
void SourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
private:
AZ::u64 m_numberOfItemsDisplayed = 0;
AZ::u64 m_numberOfItemsDisplayed = 50;
int m_displayedItemsCounter = 0;
QPointer<AssetBrowserFilterModel> m_filterModel;
QMap<int, QModelIndex> m_indexMap;
@@ -0,0 +1,344 @@
/*
* 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 <AzTest/AzTest.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserComponent.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserTableModel.h>
#include <AzToolsFramework/AssetBrowser/Entries/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Entries/FolderAssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Entries/ProductAssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Entries/RootAssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Entries/SourceAssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Search/SearchWidget.h>
#include <AzToolsFramework/AssetDatabase/AssetDatabaseConnection.h>
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/UnitTest/AzToolsFrameworkTestHelpers.h>
#include <QAbstractItemModelTester>
namespace UnitTest
{
// Test fixture for the AssetBrowser model that uses a QAbstractItemModelTester to validate the state of the model
// when QAbstractItemModel signals fire. Tests will exit with a fatal error if an invalid state is detected.
class AssetBrowserTest
: public ToolsApplicationFixture
, public testing::WithParamInterface<const char*>
{
protected:
enum class AssetEntryType
{
Root,
Folder,
Source,
Product
};
enum class FolderType
{
Root,
File
};
void SetUpEditorFixtureImpl() override;
void TearDownEditorFixtureImpl() override;
//! Creates a Mock Scan Folder
void AddScanFolder(AZ::s64 folderID, AZStd::string folderPath, AZStd::string displayName, FolderType folderType = FolderType::File);
//! Creates a Source entry from a mock file
AZ::Uuid CreateSourceEntry(
AZ::s64 fileID, AZ::s64 parentFolderID, AZStd::string filename, AssetEntryType sourceType = AssetEntryType::Source);
//! Creates a product from a given sourceEntry
void CreateProduct(AZ::s64 productID, AZ::Uuid sourceUuid, AZStd::string productName);
void SetupAssetBrowser();
void PrintModel(const QAbstractItemModel* model, AZStd::function<void(const QString&)> printer);
QModelIndex GetModelIndex(const QAbstractItemModel* model, int targetDepth, int row = 0);
AZStd::shared_ptr<AzToolsFramework::AssetBrowser::RootAssetBrowserEntry> GetRootEntry();
AZStd::vector<QString> GetVectorFromFormattedString(const QString& formattedString);
protected:
QString m_assetBrowserHierarchy = QString();
AZStd::unique_ptr<AzToolsFramework::AssetBrowser::SearchWidget> m_searchWidget;
AZStd::unique_ptr<AzToolsFramework::AssetBrowser::AssetBrowserComponent> m_assetBrowserComponent;
AZStd::unique_ptr<AzToolsFramework::AssetBrowser::AssetBrowserFilterModel> m_filterModel;
AZStd::unique_ptr<AzToolsFramework::AssetBrowser::AssetBrowserTableModel> m_tableModel;
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTesterAssetBrowser;
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTesterFilterModel;
AZStd::unique_ptr<QAbstractItemModelTester> m_modelTesterTableModel;
QVector<int> m_folderIds = { 13, 14, 15 };
QVector<int> m_sourceIDs = { 1, 2, 3, 4, 5 };
QVector<int> m_productIDs = { 1, 2, 3, 4, 5 };
};
void AssetBrowserTest::SetUpEditorFixtureImpl()
{
GetApplication()->RegisterComponentDescriptor(AzToolsFramework::EditorEntityContextComponent::CreateDescriptor());
m_assetBrowserComponent = AZStd::make_unique<AzToolsFramework::AssetBrowser::AssetBrowserComponent>();
m_assetBrowserComponent->Activate();
m_filterModel = AZStd::make_unique<AzToolsFramework::AssetBrowser::AssetBrowserFilterModel>();
m_tableModel = AZStd::make_unique<AzToolsFramework::AssetBrowser::AssetBrowserTableModel>();
m_filterModel->setSourceModel(m_assetBrowserComponent->GetAssetBrowserModel());
m_tableModel->setSourceModel(m_filterModel.get());
m_modelTesterAssetBrowser = AZStd::make_unique<QAbstractItemModelTester>(m_assetBrowserComponent->GetAssetBrowserModel());
m_modelTesterFilterModel = AZStd::make_unique<QAbstractItemModelTester>(m_filterModel.get());
m_modelTesterTableModel = AZStd::make_unique<QAbstractItemModelTester>(m_tableModel.get());
m_searchWidget = AZStd::make_unique<AzToolsFramework::AssetBrowser::SearchWidget>();
// Setup String filters
m_searchWidget->Setup(true, true);
m_filterModel->SetFilter(m_searchWidget->GetFilter());
SetupAssetBrowser();
}
void AssetBrowserTest::TearDownEditorFixtureImpl()
{
m_modelTesterAssetBrowser.reset();
m_modelTesterFilterModel.reset();
m_modelTesterTableModel.reset();
m_tableModel.reset();
m_filterModel.reset();
m_assetBrowserComponent->Deactivate();
m_assetBrowserComponent.reset();
m_searchWidget.reset();
}
void AssetBrowserTest::AddScanFolder(
AZ::s64 folderID, AZStd::string folderPath, AZStd::string displayName, FolderType folderType /*= FolderType::File*/)
{
AzToolsFramework::AssetDatabase::ScanFolderDatabaseEntry scanFolder = AzToolsFramework::AssetDatabase::ScanFolderDatabaseEntry();
scanFolder.m_scanFolderID = folderID;
scanFolder.m_scanFolder = folderPath;
scanFolder.m_displayName = displayName;
scanFolder.m_isRoot = folderType == FolderType::Root;
GetRootEntry()->AddScanFolder(scanFolder);
}
AZ::Uuid AssetBrowserTest::CreateSourceEntry(
AZ::s64 fileID, AZ::s64 parentFolderID, AZStd::string filename, AssetEntryType sourceType /*= AssetEntryType::Source*/)
{
AzToolsFramework::AssetDatabase::FileDatabaseEntry entry = AzToolsFramework::AssetDatabase::FileDatabaseEntry();
entry.m_scanFolderPK = parentFolderID;
entry.m_fileID = fileID;
entry.m_fileName = filename;
entry.m_isFolder = sourceType == AssetEntryType::Folder;
GetRootEntry()->AddFile(entry);
if (!entry.m_isFolder)
{
AzToolsFramework::AssetBrowser::SourceWithFileID entrySource = AzToolsFramework::AssetBrowser::SourceWithFileID();
entrySource.first = entry.m_fileID;
entrySource.second = AzToolsFramework::AssetDatabase::SourceDatabaseEntry();
entrySource.second.m_scanFolderPK = parentFolderID;
entrySource.second.m_sourceName = filename;
entrySource.second.m_sourceID = fileID;
entrySource.second.m_sourceGuid = AZ::Uuid::CreateRandom();
GetRootEntry()->AddSource(entrySource);
return entrySource.second.m_sourceGuid;
}
return AZ::Uuid::CreateNull();
}
void AssetBrowserTest::CreateProduct(AZ::s64 productID, AZ::Uuid sourceUuid, AZStd::string productName)
{
AzToolsFramework::AssetBrowser::ProductWithUuid product = AzToolsFramework::AssetBrowser::ProductWithUuid();
product.first = sourceUuid;
product.second = AzToolsFramework::AssetDatabase::ProductDatabaseEntry();
product.second.m_productID = productID;
product.second.m_subID = aznumeric_cast<AZ::u32>(productID);
product.second.m_productName = productName;
GetRootEntry()->AddProduct(product);
}
void AssetBrowserTest::SetupAssetBrowser()
{
// RootEntries : 1 | Folders : 4 | SourceEntries : 5 | ProductEntries : 9
m_assetBrowserHierarchy = R"(
D:
\
dev
o3de
GameProject
Assets
Source_1
Product_1_1
Product_1_0
Source_0
Product_0_3
Product_0_2
Product_0_1
Product_0_0
Scripts
Source_3
Source_2
Product_2_2
Product_2_1
Product_2_0
Misc
Source_4
Product_4_2
Product_4_1
Product_4_0 )";
namespace AzAssetBrowser = AzToolsFramework::AssetBrowser;
AddScanFolder(m_folderIds.at(2), "D:/dev/o3de/GameProject/Misc", "Misc");
AZ::Uuid sourceUuid_4 = CreateSourceEntry(m_sourceIDs.at(4), m_folderIds.at(2), "Source_4");
CreateProduct(m_productIDs.at(0), sourceUuid_4, "Product_4_0");
CreateProduct(m_productIDs.at(1), sourceUuid_4, "Product_4_1");
CreateProduct(m_productIDs.at(2), sourceUuid_4, "Product_4_2");
AddScanFolder(m_folderIds.at(1), "D:/dev/o3de/GameProject/Scripts", "Scripts");
AZ::Uuid sourceUuid_2 = CreateSourceEntry(m_sourceIDs.at(2), m_folderIds.at(1), "Source_2");
CreateProduct(m_productIDs.at(0), sourceUuid_2, "Product_2_0");
CreateProduct(m_productIDs.at(1), sourceUuid_2, "Product_2_1");
CreateProduct(m_productIDs.at(2), sourceUuid_2, "Product_2_2");
CreateSourceEntry(m_sourceIDs.at(3), m_folderIds.at(1), "Source_3");
AddScanFolder(m_folderIds.at(0), "D:/dev/o3de/GameProject/Assets", "Assets");
AZ::Uuid sourceUuid_0 = CreateSourceEntry(m_sourceIDs.at(0), m_folderIds.at(0), "Source_0");
CreateProduct(m_productIDs.at(0), sourceUuid_0, "Product_0_0");
CreateProduct(m_productIDs.at(1), sourceUuid_0, "Product_0_1");
CreateProduct(m_productIDs.at(2), sourceUuid_0, "Product_0_2");
CreateProduct(m_productIDs.at(3), sourceUuid_0, "Product_0_3");
AZ::Uuid sourceUuid_1 = CreateSourceEntry(m_sourceIDs.at(1), m_folderIds.at(0), "Source_1");
CreateProduct(m_productIDs.at(0), sourceUuid_1, "Product_1_0");
CreateProduct(m_productIDs.at(1), sourceUuid_1, "Product_1_1");
}
void AssetBrowserTest::PrintModel(const QAbstractItemModel* model, AZStd::function<void(const QString&)> printer)
{
AZStd::deque<AZStd::pair<QModelIndex, int>> indices;
indices.push_back({ model->index(0, 0), 0 });
while (!indices.empty())
{
auto [index, depth] = indices.front();
indices.pop_front();
QString indentString;
for (int i = 0; i < depth; ++i)
{
indentString += " ";
}
const QString message = indentString + index.data(Qt::DisplayRole).toString();
printer(message);
for (int i = 0; i < model->rowCount(index); ++i)
{
indices.emplace_front(model->index(i, 0, index), depth + 1);
}
}
}
QModelIndex AssetBrowserTest::GetModelIndex(const QAbstractItemModel* model, int targetDepth, int row)
{
AZStd::deque<AZStd::pair<QModelIndex, int>> indices;
indices.push_back({ model->index(0, 0), 0 });
while (!indices.empty())
{
auto [index, depth] = indices.front();
indices.pop_front();
for (int i = 0; i < model->rowCount(index); ++i)
{
if (depth + 1 == targetDepth && row == i)
{
return model->index(i, 0, index);
}
indices.emplace_front(model->index(i, 0, index), depth + 1);
}
}
return QModelIndex();
}
AZStd::shared_ptr<AzToolsFramework::AssetBrowser::RootAssetBrowserEntry> AssetBrowserTest::GetRootEntry()
{
return m_assetBrowserComponent->GetAssetBrowserModel()->GetRootEntry();
}
AZStd::vector<QString> AssetBrowserTest::GetVectorFromFormattedString(const QString& formattedString)
{
AZStd::vector<QString> hierarchySections;
QStringList splittedList = formattedString.split('\n', Qt::SkipEmptyParts);
for (auto& str : splittedList)
{
str.replace(" ", "");
hierarchySections.push_back(str);
}
return hierarchySections;
}
TEST_F(AssetBrowserTest, CheckCorrectNumberOfEntriesInTableView)
{
m_filterModel->FilterUpdatedSlotImmediate();
const int tableViewRowcount = m_tableModel->rowCount();
// RowCount should be 17 -> 5 SourceEntries + 12 ProductEntries)
EXPECT_EQ(tableViewRowcount, 17);
}
TEST_F(AssetBrowserTest, CheckCorrectNumberOfEntriesInTableViewAfterStringFilter)
{
/*
*-Source_1
* |
* |-product_1_0
* |-product_1_1
*
*
* Matching entries = 3
*/
// Apply string filter
m_searchWidget->SetTextFilter(QString("source_1"));
m_filterModel->FilterUpdatedSlotImmediate();
const int tableViewRowcount = m_tableModel->rowCount();
EXPECT_EQ(tableViewRowcount, 3);
}
TEST_F(AssetBrowserTest, CheckScanFolderAddition)
{
EXPECT_EQ(m_assetBrowserComponent->GetAssetBrowserModel()->rowCount(), 1);
const int newFolderId = 20;
AddScanFolder(newFolderId, "E:/TestFolder/TestFolder2", "TestFolder");
// Since the folder is empty it shouldn't be added to the model.
EXPECT_EQ(m_assetBrowserComponent->GetAssetBrowserModel()->rowCount(), 1);
CreateSourceEntry(123, newFolderId, "DummyFile");
// When we add a file to the folder it should be added to the model
EXPECT_EQ(m_assetBrowserComponent->GetAssetBrowserModel()->rowCount(), 2);
}
} // namespace UnitTest
@@ -123,6 +123,7 @@ set(FILES
UI/EntityIdQLineEditTests.cpp
UI/EntityOutlinerTests.cpp
UI/EntityPropertyEditorTests.cpp
UI/AssetBrowserTests.cpp
UndoStack.cpp
Viewport/ClusterTests.cpp
Viewport/ViewportEditorModeTests.cpp
@@ -76,6 +76,12 @@ foreach(project_name project_path IN ZIP_LISTS LY_PROJECTS_TARGET_NAME LY_PROJEC
Legacy::CrySystem
)
if(PAL_TRAIT_BUILD_SERVER_SUPPORTED)
set(server_runtime_dependencies
Legacy::CrySystem
)
endif()
endif()
################################################################################
+2 -2
View File
@@ -1121,8 +1121,8 @@ inline ISystem* GetISystem()
// Description:
// This function must be called once by each module at the beginning, to setup global pointers.
extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, const char* moduleName);
extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem(ISystem* pSystem);
void ModuleInitISystem(ISystem* pSystem, const char* moduleName);
void ModuleShutdownISystem(ISystem* pSystem);
extern "C" AZ_DLL_EXPORT void InjectEnvironment(void* env);
extern "C" AZ_DLL_EXPORT void DetachEnvironment();
+2 -2
View File
@@ -74,7 +74,7 @@ void InitCRTHandlers() {}
//////////////////////////////////////////////////////////////////////////
// This is an entry to DLL initialization function that must be called for each loaded module
//////////////////////////////////////////////////////////////////////////
extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName)
void ModuleInitISystem(ISystem* pSystem, [[maybe_unused]] const char* moduleName)
{
if (gEnv) // Already registered.
{
@@ -96,7 +96,7 @@ extern "C" AZ_DLL_EXPORT void ModuleInitISystem(ISystem* pSystem, [[maybe_unused
} // if pSystem
}
extern "C" AZ_DLL_EXPORT void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem)
void ModuleShutdownISystem([[maybe_unused]] ISystem* pSystem)
{
// Unregister with AZ environment.
AZ::Environment::Detach();
-23
View File
@@ -173,8 +173,6 @@ void CryEngineSignalHandler(int signal)
//////////////////////////////////////////////////////////////////////////
#if defined(WIN32) || defined(LINUX) || defined(APPLE)
# define DLL_MODULE_INIT_ISYSTEM "ModuleInitISystem"
# define DLL_MODULE_SHUTDOWN_ISYSTEM "ModuleShutdownISystem"
# define DLL_INITFUNC_RENDERER "PackageRenderConstructor"
# define DLL_INITFUNC_SOUND "CreateSoundSystem"
# define DLL_INITFUNC_FONT "CreateCryFontInterface"
@@ -188,8 +186,6 @@ void CryEngineSignalHandler(int signal)
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
# define DLL_MODULE_INIT_ISYSTEM (LPCSTR)2
# define DLL_MODULE_SHUTDOWN_ISYSTEM (LPCSTR)3
# define DLL_INITFUNC_RENDERER (LPCSTR)1
# define DLL_INITFUNC_RENDERER (LPCSTR)1
# define DLL_INITFUNC_SOUND (LPCSTR)1
@@ -445,18 +441,6 @@ AZStd::unique_ptr<AZ::DynamicModuleHandle> CSystem::LoadDLL(const char* dllName)
return handle;
}
//////////////////////////////////////////////////////////////////////////
// After loading DLL initialize it by calling ModuleInitISystem
//////////////////////////////////////////////////////////////////////////
AZStd::string moduleName = PathUtil::GetFileName(dllName);
typedef void*(*PtrFunc_ModuleInitISystem)(ISystem* pSystem, const char* moduleName);
PtrFunc_ModuleInitISystem pfnModuleInitISystem = handle->GetFunction<PtrFunc_ModuleInitISystem>(DLL_MODULE_INIT_ISYSTEM);
if (pfnModuleInitISystem)
{
pfnModuleInitISystem(this, moduleName.c_str());
}
return handle;
}
@@ -497,13 +481,6 @@ void CSystem::ShutdownModuleLibraries()
#if !defined(AZ_MONOLITHIC_BUILD)
for (auto iterator = m_moduleDLLHandles.begin(); iterator != m_moduleDLLHandles.end(); ++iterator)
{
typedef void*( * PtrFunc_ModuleShutdownISystem )(ISystem* pSystem);
PtrFunc_ModuleShutdownISystem pfnModuleShutdownISystem = iterator->second->GetFunction<PtrFunc_ModuleShutdownISystem>(DLL_MODULE_SHUTDOWN_ISYSTEM);
if (pfnModuleShutdownISystem)
{
pfnModuleShutdownISystem(this);
}
if (iterator->second->IsLoaded())
{
iterator->second->Unload();
-5
View File
@@ -333,11 +333,6 @@ void CXConsole::Init(ISystem* pSystem)
m_nLoadingBackTexID = -1;
if (gEnv->IsDedicated())
{
m_bConsoleActive = true;
}
REGISTER_COMMAND("ConsoleShow", &ConsoleShow, VF_NULL, "Opens the console");
REGISTER_COMMAND("ConsoleHide", &ConsoleHide, VF_NULL, "Closes the console");
@@ -25,7 +25,7 @@ namespace AssetProcessor
: public ::testing::Test
{
protected:
UnitTestUtils::AssertAbsorber* m_errorAbsorber;
AZStd::unique_ptr<UnitTestUtils::AssertAbsorber> m_errorAbsorber{};
FileStatePassthrough m_fileStateCache;
void SetUp() override
@@ -40,7 +40,7 @@ namespace AssetProcessor
m_ownsSysAllocator = true;
AZ::AllocatorInstance<AZ::SystemAllocator>::Create();
}
m_errorAbsorber = new UnitTestUtils::AssertAbsorber();
m_errorAbsorber = AZStd::make_unique<UnitTestUtils::AssertAbsorber>();
m_application = AZStd::make_unique<AzFramework::Application>();
@@ -62,8 +62,8 @@ namespace AssetProcessor
AssetUtilities::ResetAssetRoot();
m_application.reset();
delete m_errorAbsorber;
m_errorAbsorber = nullptr;
m_errorAbsorber.reset();
if (m_ownsSysAllocator)
{
AZ::AllocatorInstance<AZ::SystemAllocator>::Destroy();
@@ -49,6 +49,12 @@ int main(int argc, char* argv[])
AZStd::unique_ptr<AzFramework::ProcessWatcher> shellProcess(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE));
shellProcess->WaitForProcessToExit(120);
shellProcess.reset();
parameters = AZStd::string::format("-c \"%s/scripts/o3de.sh register --this-engine\"", enginePath.c_str());
shellProcessLaunch.m_commandlineParameters = parameters;
shellProcess.reset(AzFramework::ProcessWatcher::LaunchProcess(shellProcessLaunch, AzFramework::ProcessCommunicationType::COMMUNICATOR_TYPE_NONE));
shellProcess->WaitForProcessToExit(120);
shellProcess.reset();
AZ::IO::FixedMaxPath projectManagerPath = installedBinariesFolder/"o3de.app"/"Contents"/"MacOS"/"o3de";
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
@@ -10,6 +10,8 @@
#include <QProcessEnvironment>
#include <QDir>
#include <AzCore/Utils/Utils.h>
namespace O3DE::ProjectManager
{
namespace ProjectUtils
@@ -94,5 +96,10 @@ namespace O3DE::ProjectManager
QProcessEnvironment::systemEnvironment(),
QObject::tr("Running get_python script..."));
}
AZ::IO::FixedMaxPath GetEditorDirectory()
{
return AZ::Utils::GetExecutableDirectory();
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -11,6 +11,9 @@
#include <QStandardPaths>
#include <QDir>
#include <AzCore/Utils/Utils.h>
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
namespace O3DE::ProjectManager
{
namespace ProjectUtils
@@ -104,5 +107,35 @@ namespace O3DE::ProjectManager
QProcessEnvironment::systemEnvironment(),
QObject::tr("Running get_python script..."));
}
AZ::IO::FixedMaxPath GetEditorDirectory()
{
AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
AZ::IO::FixedMaxPath editorPath{ executableDirectory };
editorPath /= "../../../Editor.app/Contents/MacOS";
editorPath = editorPath.LexicallyNormal();
if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str()))
{
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
{
if (AZ::IO::FixedMaxPath installedBinariesPath;
settingsRegistry->Get(installedBinariesPath.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_InstalledBinaryFolder))
{
if (AZ::IO::FixedMaxPath engineRootFolder;
settingsRegistry->Get(engineRootFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_EngineRootFolder))
{
editorPath = engineRootFolder / installedBinariesPath / "Editor.app/Contents/MacOS";
}
}
}
if (!AZ::IO::SystemFile::IsDirectory(editorPath.c_str()))
{
AZ_Error("ProjectManager", false, "Unable to find the Editor app bundle!");
}
}
return editorPath;
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -14,6 +14,8 @@
#include <QProcess>
#include <QProcessEnvironment>
#include <AzCore/Utils/Utils.h>
namespace O3DE::ProjectManager
{
namespace ProjectUtils
@@ -139,5 +141,10 @@ namespace O3DE::ProjectManager
QProcessEnvironment::systemEnvironment(),
QObject::tr("Running get_python script..."));
}
AZ::IO::FixedMaxPath GetEditorDirectory()
{
return AZ::Utils::GetExecutableDirectory();
}
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -14,6 +14,7 @@
#include <QWidget>
#include <QProcessEnvironment>
#include <AzCore/IO/Path/Path_fwd.h>
#include <AzCore/Outcome/Outcome.h>
namespace O3DE::ProjectManager
@@ -67,7 +68,8 @@ namespace O3DE::ProjectManager
AZ::Outcome<QString, QString> GetProjectBuildPath(const QString& projectPath);
AZ::Outcome<void, QString> OpenCMakeGUI(const QString& projectPath);
AZ::Outcome<QString, QString> RunGetPythonScript(const QString& enginePath);
AZ::IO::FixedMaxPath GetEditorDirectory();
} // namespace ProjectUtils
} // namespace O3DE::ProjectManager
@@ -392,11 +392,11 @@ namespace O3DE::ProjectManager
{
if (!WarnIfInBuildQueue(projectPath))
{
AZ::IO::FixedMaxPath executableDirectory = AZ::Utils::GetExecutableDirectory();
AZ::IO::FixedMaxPath executableDirectory = ProjectUtils::GetEditorDirectory();
AZStd::string executableFilename = "Editor";
AZ::IO::FixedMaxPath editorExecutablePath = executableDirectory / (executableFilename + AZ_TRAIT_OS_EXECUTABLE_EXTENSION);
auto cmdPath = AZ::IO::FixedMaxPathString::format(
"%s -regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(),
"%s --regset=\"/Amazon/AzCore/Bootstrap/project_path=%s\"", editorExecutablePath.c_str(),
projectPath.toStdString().c_str());
AzFramework::ProcessLauncher::ProcessLaunchInfo processLaunchInfo;
@@ -63,7 +63,7 @@ namespace AZ
}
ProcessingOverlayWidget::ProcessingOverlayWidget(UI::OverlayWidget* overlay, Layout layout, Uuid traceTag)
: QWidget()
: QWidget(nullptr, Qt::Tool | Qt::WindowStaysOnTopHint)
, m_traceTag(traceTag)
, ui(new Ui::ProcessingOverlayWidget())
, m_overlay(overlay)
@@ -100,13 +100,6 @@ namespace ImageProcessingAtom
//compare whether two images are same. return true if they are same.
virtual bool CompareImage(const IImageObjectPtr otherImage) const = 0;
// Writes this image to file used for runtime, overwrites any existing file.
// It may write alpha image as attached image into the same file
// outFilePaths will save filenames finally saved to since the image might be split and saved to multiple files
virtual bool SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector<AZStd::string>& outFilePaths) const = 0;
virtual bool SaveImage(AZ::IO::SystemFileStream& out) const = 0;
virtual bool SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const = 0;
//get total image data size in memory of all mipmaps. Not includs header and flags.
virtual AZ::u32 GetTextureMemory() const = 0;
@@ -135,9 +128,6 @@ namespace ImageProcessingAtom
// The algorithm is based on the Frequency Domain Normal Mapping implementation presented by Neubelt and Pettineo at Siggraph 2013.
virtual void GlossFromNormals(bool hasAuthoredGloss) = 0;
//convert gloss map from legacy distribution to new one. New World is still using legacy gloss map.
virtual void ConvertLegacyGloss() = 0;
//clear image with color
virtual void ClearColor(float r, float g, float b, float a) = 0;
};
@@ -45,10 +45,7 @@ namespace ImageProcessingAtom
->Field("MinTextureSize", &PresetSettings::m_minTextureSize)
->Field("IsPowerOf2", &PresetSettings::m_isPowerOf2)
->Field("SizeReduceLevel", &PresetSettings::m_sizeReduceLevel)
->Field("IsColorChart", &PresetSettings::m_isColorChart)
->Field("HighPassMip", &PresetSettings::m_highPassMip)
->Field("GlossFromNormal", &PresetSettings::m_glossFromNormals)
->Field("UseLegacyGloss", &PresetSettings::m_isLegacyGloss)
->Field("MipRenormalize", &PresetSettings::m_isMipRenormalize)
->Field("NumberResidentMips", &PresetSettings::m_numResidentMips)
->Field("Swizzle", &PresetSettings::m_swizzle)
@@ -200,10 +197,7 @@ namespace ImageProcessingAtom
m_maxTextureSize == other.m_maxTextureSize &&
m_isPowerOf2 == other.m_isPowerOf2 &&
m_sizeReduceLevel == other.m_sizeReduceLevel &&
m_isColorChart == other.m_isColorChart &&
m_highPassMip == other.m_highPassMip &&
m_glossFromNormals == other.m_glossFromNormals &&
m_isLegacyGloss == other.m_isLegacyGloss &&
m_swizzle == other.m_swizzle &&
m_isMipRenormalize == other.m_isMipRenormalize &&
m_numResidentMips == other.m_numResidentMips;
@@ -239,10 +233,7 @@ namespace ImageProcessingAtom
m_maxTextureSize = other.m_maxTextureSize;
m_isPowerOf2 = other.m_isPowerOf2;
m_sizeReduceLevel = other.m_sizeReduceLevel;
m_isColorChart = other.m_isColorChart;
m_highPassMip = other.m_highPassMip;
m_glossFromNormals = other.m_glossFromNormals;
m_isLegacyGloss = other.m_isLegacyGloss;
m_swizzle = other.m_swizzle;
m_isMipRenormalize = other.m_isMipRenormalize;
m_numResidentMips = other.m_numResidentMips;
@@ -84,16 +84,7 @@ namespace ImageProcessingAtom
//settings for mipmap generation. it's null if this preset disable mipmap.
AZStd::unique_ptr<MipmapSettings> m_mipmapSetting;
//some specific settings
// "colorchart". This is to indicate if need to extract color chart from the image and output the color chart data.
// This is very specific usage for cryEngine. Check ColorChart.cpp for better explanation.
bool m_isColorChart = false;
//"highpass". Defines which mip level is subtracted when applying the high pass filter
//this is only used for terrain asset. we might remove it later since it can be done with source image directly
AZ::u32 m_highPassMip = 0;
//"glossfromnormals". Bake normal variance into smoothness stored in alpha channel
AZ::u32 m_glossFromNormals = 0;
@@ -109,10 +100,6 @@ namespace ImageProcessingAtom
//that add up to 64K or lower
AZ::u8 m_numResidentMips = 0;
//legacy options might be removed later
//"glosslegacydist". If the gloss map use legacy distribution. NW is still using legacy dist
bool m_isLegacyGloss = false;
//"swizzle". need to be 4 character and each character need to be one of "rgba01"
AZStd::string m_swizzle;
@@ -1,307 +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 <Processing/ImageObjectImpl.h>
#include <Processing/ImageToProcess.h>
namespace ImageProcessingAtom
{
const int COLORCHART_IMAGE_WIDTH = 78;
const int COLORCHART_IMAGE_HEIGHT = 66;
// color chart in cry engine is a special image data, with size 78x66, you may see in game screenshot which is defined by a rectangle
// area with a yellow-black dash line boarder
// Create color chart function is to read that block of image data and convert it to a color table then save it to another image
// with size 256x16.
class C3dLutColorChart
{
public:
C3dLutColorChart() {}
~C3dLutColorChart() {};
//generate default color chart data
void GenerateDefault();
//generate color chart data from input image
bool GenerateFromInput(IImageObjectPtr image);
//ouput the color chart data to an image object
IImageObjectPtr GenerateChartImage();
protected:
//extract color chart data from specified location in an image
void ExtractFromImageAt(IImageObjectPtr pImg, AZ::u32 x, AZ::u32 y);
//find color chart location in an image
static bool FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY);
//if there is a color chart at specified location
static bool IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch);
private:
enum EPrimaryShades
{
ePS_Red = 16,
ePS_Green = 16,
ePS_Blue = 16,
ePS_NumColors = ePS_Red * ePS_Green * ePS_Blue
};
struct SColor
{
unsigned char r, g, b, _padding;
};
typedef AZStd::vector<SColor> ColorMapping;
ColorMapping m_mapping;
};
void C3dLutColorChart::GenerateDefault()
{
m_mapping.reserve(ePS_NumColors);
for (int b = 0; b < ePS_Blue; ++b)
{
for (int g = 0; g < ePS_Green; ++g)
{
for (int r = 0; r < ePS_Red; ++r)
{
SColor col;
col.r = static_cast<unsigned char>(255 * r / (ePS_Red));
col.g = static_cast<unsigned char>(255 * g / (ePS_Green));
col.b = static_cast<unsigned char>(255 * b / (ePS_Blue));
int l = 255 - (col.r * 3 + col.g * 6 + col.b) / 10;
col.r = col.g = col.b = (unsigned char)l;
m_mapping.push_back(col);
}
}
}
}
//find color chart location in a image
bool C3dLutColorChart::FindColorChart(const IImageObjectPtr pImg, AZ::u32& outLocX, AZ::u32& outLocY)
{
const AZ::u32 width = pImg->GetWidth(0);
const AZ::u32 height = pImg->GetHeight(0);
//the origin image is too small to have a color chart
if (width < COLORCHART_IMAGE_WIDTH || height < COLORCHART_IMAGE_HEIGHT)
{
return false;
}
AZ::u8* pData;
AZ::u32 pitch;
pImg->GetImagePointer(0, pData, pitch);
//check all the posible start location on whether there might be a color chart
for (AZ::u32 y = 0; y <= height - COLORCHART_IMAGE_HEIGHT; ++y)
{
for (AZ::u32 x = 0; x <= width - COLORCHART_IMAGE_WIDTH; ++x)
{
if (IsColorChartAt(x, y, pData, pitch))
{
outLocX = x;
outLocY = y;
return true;
}
}
}
return false;
}
bool C3dLutColorChart::GenerateFromInput(IImageObjectPtr image)
{
AZ::u32 outLocX, outLocY;
if (FindColorChart(image, outLocX, outLocY))
{
ExtractFromImageAt(image, outLocX, outLocY);
return true;
}
return false;
}
IImageObjectPtr C3dLutColorChart::GenerateChartImage()
{
IImageObjectPtr image(IImageObject::CreateImage(ePS_Red* ePS_Blue, ePS_Green, 1, ePixelFormat_R8G8B8A8));
{
AZ::u8* pData;
AZ::u32 pitch;
image->GetImagePointer(0, pData, pitch);
size_t nSlicePitch = (pitch / ePS_Blue);
AZ::u32 src = 0;
for (int b = 0; b < ePS_Blue; ++b)
{
for (int g = 0; g < ePS_Green; ++g)
{
AZ::u8* p = pData + g * pitch + b * nSlicePitch;
for (int r = 0; r < ePS_Red; ++r)
{
const SColor& c = m_mapping[src];
p[0] = c.r;
p[1] = c.g;
p[2] = c.b;
p[3] = 255;
++src;
p += 4;
}
}
}
}
return image;
}
void C3dLutColorChart::ExtractFromImageAt(IImageObjectPtr image, AZ::u32 x, AZ::u32 y)
{
int ox = x + 1;
int oy = y + 1;
AZ::u8* pData;
AZ::u32 pitch;
image->GetImagePointer(0, pData, pitch);
m_mapping.reserve(ePS_NumColors);
for (int b = 0; b < ePS_Blue; ++b)
{
int px = ox + ePS_Red * (b % 4);
int py = oy + ePS_Green * (b / 4);
for (int g = 0; g < ePS_Green; ++g)
{
for (int r = 0; r < ePS_Red; ++r)
{
AZ::u8* p = pData + pitch * (py + g) + (px + r) * 4;
SColor col;
col.r = p[0];
col.g = p[1];
col.b = p[2];
m_mapping.push_back(col);
}
}
}
}
//check if image data at location x and y could be a color chart
//based on if the boarder is dash lines with two pixel each segement
//the idea and implementation are both coming from CryEngine.
bool C3dLutColorChart::IsColorChartAt(AZ::u32 x, AZ::u32 y, void* pData, AZ::u32 pitch)
{
struct Color
{
private:
int c[3];
public:
Color(AZ::u32 x, AZ::u32 y, void* pPixels, AZ::u32 pitch)
{
const uint8* p = (const uint8*)pPixels + pitch * y + x * 4;
c[0] = p[0];
c[1] = p[1];
c[2] = p[2];
}
bool isSimilar(const Color& a, int maxDiff) const
{
return
abs(a.c[0] - c[0]) <= maxDiff &&
abs(a.c[1] - c[1]) <= maxDiff &&
abs(a.c[2] - c[2]) <= maxDiff;
}
};
const Color colorRef[2] =
{
Color(x, y, pData, pitch),
Color(x + 2, y, pData, pitch)
};
// We require two colors of the border to be at least a bit different
if (colorRef[0].isSimilar(colorRef[1], 15))
{
return false;
}
static const int kMaxDiff = 3;
int refIdx = 0;
//rectangle's top
for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2)
{
if (!colorRef[refIdx].isSimilar(Color(x + i, y, pData, pitch), kMaxDiff) ||
!colorRef[refIdx].isSimilar(Color(x + i + 1, y, pData, pitch), kMaxDiff))
{
return false;
}
refIdx ^= 1;
}
refIdx = 0;
//left
for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2)
{
if (!colorRef[refIdx].isSimilar(Color(x, y + i, pData, pitch), kMaxDiff) ||
!colorRef[refIdx].isSimilar(Color(x, y + i + 1, pData, pitch), kMaxDiff))
{
return false;
}
refIdx ^= 1;
}
refIdx = 0;
//right
for (int i = 0; i < COLORCHART_IMAGE_HEIGHT; i += 2)
{
if (!colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i, pData, pitch), kMaxDiff) ||
!colorRef[refIdx].isSimilar(Color(x + COLORCHART_IMAGE_WIDTH - 1, y + i + 1, pData, pitch), kMaxDiff))
{
return false;
}
refIdx ^= 1;
}
refIdx = 0;
//bottom
for (int i = 0; i < COLORCHART_IMAGE_WIDTH; i += 2)
{
if (!colorRef[refIdx].isSimilar(Color(x + i, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff) ||
!colorRef[refIdx].isSimilar(Color(x + i + 1, y + COLORCHART_IMAGE_HEIGHT - 1, pData, pitch), kMaxDiff))
{
return false;
}
refIdx ^= 1;
}
return true;
}
void ImageToProcess::CreateColorChart()
{
C3dLutColorChart colorChart;
//get color chart data from source image.
if (!colorChart.GenerateFromInput(m_img))
{
//if load from image failed then generate default color data
colorChart.GenerateDefault();
}
//save color chart data to an image and save as current
m_img = colorChart.GenerateChartImage();
}
}
@@ -547,7 +547,7 @@ namespace ImageProcessingAtom
}
//generate box filtered source image mip chain
IImageObjectPtr mippedSourceImage(IImageObject::CreateImage(outWidth, outHeight, maxMipCount, ePixelFormat_R32G32B32A32F));
IImageObjectPtr mippedSourceImage(IImageObject::CreateImage(outWidth, outHeight, maxMipCount, srcPixelFormat));
mippedSourceImage->CopyPropertiesFrom(m_image->Get());
for (int iSide = 0; iSide < 6; ++iSide)
@@ -1,100 +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 <Processing/ImageObjectImpl.h>
#include <Processing/ImageToProcess.h>
#include <Processing/ImageConvert.h>
#include <Processing/PixelFormatInfo.h>
#include <Converters/FIR-Windows.h>
#include <Converters/PixelOperation.h>
namespace ImageProcessingAtom
{
// higher mip level is subtracted by lower mip level when applying the [cheap] high pass filter
void ImageToProcess::CreateHighPass(AZ::u32 dwMipDown)
{
//no need to convert if mip go down 0
if (dwMipDown == 0)
{
return;
}
const EPixelFormat ePixelFormat = m_img->GetPixelFormat();
if (ePixelFormat != ePixelFormat_R32G32B32A32F)
{
AZ_Assert(false, "You need convert the orginal image to ePixelFormat_R32G32B32A32F before call this function");
return;
}
AZ::u32 dwWidth, dwHeight, dwMips;
dwWidth = m_img->GetWidth(0);
dwHeight = m_img->GetHeight(0);
dwMips = m_img->GetMipCount();
if (dwMipDown >= dwMips)
{
AZ_Warning("Image Processing", false, "CreateHighPass can't go down %i MIP levels for high pass as there are not\
enough MIP levels available, going down by %i instead", dwMipDown, dwMips - 1);
dwMipDown = dwMips - 1;
}
IImageObjectPtr newImage(IImageObject::CreateImage(dwWidth, dwHeight, dwMips, ePixelFormat));
newImage->CopyPropertiesFrom(m_img);
IPixelOperationPtr pixelOp = CreatePixelOperation(ePixelFormat);
AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(ePixelFormat)->bitsPerBlock / 8;
AZ::u32 dstMips = newImage->GetMipCount();
for (AZ::u32 dstMip = 0; dstMip < dwMipDown; ++dstMip)
{
// linear interpolation
FilterImage(MipGenType::triangle, MipGenEvalType::sum, 0.0f, 0.0f, m_img, dwMipDown, newImage, dstMip, NULL, NULL);
//substraction
AZ::u8* srcPixelBuf;
AZ::u32 srcPitch;
m_img->GetImagePointer(dstMip, srcPixelBuf, srcPitch);
AZ::u8* dstPixelBuf;
AZ::u32 dstPitch;
newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch);
const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip);
for (AZ::u32 i = 0; i < pixelCount; ++i, srcPixelBuf += pixelBytes, dstPixelBuf += pixelBytes)
{
float r1, g1, b1, a1, r2, g2, b2, a2;
pixelOp->GetRGBA(srcPixelBuf, r1, g1, b1, a1);
pixelOp->GetRGBA(dstPixelBuf, r2, g2, b2, a2);
r2 = AZ::GetClamp<float>(r1 - r2 + 0.5f, 0.0f, 1.0f);
g2 = AZ::GetClamp<float>(g1 - g2 + 0.5f, 0.0f, 1.0f);
b2 = AZ::GetClamp<float>(b1 - b2 + 0.5f, 0.0f, 1.0f);
a2 = AZ::GetClamp<float>(a1 - a2 + 0.5f, 0.0f, 1.0f);
pixelOp->SetRGBA(dstPixelBuf, r2, g2, b2, a2);
}
}
// mips below the chosen highpass mip are grey
for (AZ::u32 dstMip = dwMipDown; dstMip < dstMips; ++dstMip)
{
AZ::u8* dstPixelBuf;
AZ::u32 dstPitch;
newImage->GetImagePointer(dstMip, dstPixelBuf, dstPitch);
const AZ::u32 pixelCount = newImage->GetPixelCount(dstMip);
for (AZ::u32 i = 0; i < pixelCount; ++i, dstPixelBuf += pixelBytes)
{
pixelOp->SetRGBA(dstPixelBuf, 0.5f, 0.5f, 0.5f, 1.0f);
}
}
m_img = newImage;
}
} // namespace ImageProcessingAtom
@@ -82,10 +82,7 @@ namespace ImageProcessingAtomEditor
presetInfoText += "\n";
presetInfoText += QString("Suppress Engine Reduce: %1\n").arg(presetSettings->m_suppressEngineReduce ? "True" : "False");
presetInfoText += QString("Discard Alpha: %1\n").arg(presetSettings->m_discardAlpha ? "True" : "False");
presetInfoText += QString("Is Color Chart: %1\n").arg(presetSettings->m_isColorChart ? "True" : "False");
presetInfoText += QString("High Pass Mip: %1\n").arg(presetSettings->m_highPassMip);
presetInfoText += QString("Gloss From Normal: %1\n").arg(presetSettings->m_glossFromNormals);
presetInfoText += QString("Use Legacy Gloss: %1\n").arg(presetSettings->m_isLegacyGloss ? "True" : "False");
presetInfoText += QString("Mip Re-normalize: %1\n").arg(presetSettings->m_isMipRenormalize ? "True" : "False");
presetInfoText += QString("Resident Mips Number: %1\n").arg(presetSettings->m_numResidentMips);
presetInfoText += QString("Swizzle: %1\n").arg(presetSettings->m_swizzle.c_str());
@@ -74,7 +74,7 @@ namespace ImageProcessingAtom
builderDescriptor.m_busId = azrtti_typeid<ImageBuilderWorker>();
builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDescriptor.m_version = 25; // [ATOM-16575]
builderDescriptor.m_version = 26; // [ATOM-15086]
builderDescriptor.m_analysisFingerprint = ImageProcessingAtom::BuilderSettingManager::Instance()->GetAnalysisFingerprint();
m_imageBuilder.BusConnect(builderDescriptor.m_busId);
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
@@ -46,7 +46,6 @@ namespace ImageProcessingAtom
enum ConvertStep
{
StepValidateInput = 0,
StepGenerateColorChart,
StepConvertToLinear,
StepSwizzle,
StepCubemapLayout,
@@ -55,9 +54,7 @@ namespace ImageProcessingAtom
StepMipmap,
StepGlossFromNormal,
StepPostNormalize,
StepCreateHighPass,
StepConvertOutputColorSpace,
StepAlphaImage,
StepConvertPixelFormat,
StepSaveToFile,
StepAll
@@ -66,7 +63,6 @@ namespace ImageProcessingAtom
[[maybe_unused]] const char ProcessStepNames[StepAll][64] =
{
"ValidateInput",
"GenerateColorChart",
"ConvertToLinear",
"Swizzle",
"CubemapLayout",
@@ -75,9 +71,7 @@ namespace ImageProcessingAtom
"Mipmap",
"GlossFromNormal",
"PostNormalize",
"CreateHighPass",
"ConvertOutputColorSpace",
"AlphaImage",
"ConvertPixelFormat",
"SaveToFile",
};
@@ -94,11 +88,6 @@ namespace ImageProcessingAtom
return nullptr;
}
IImageObjectPtr ImageConvertProcess::GetOutputAlphaImage()
{
return m_alphaImage;
}
IImageObjectPtr ImageConvertProcess::GetOutputIBLSpecularCubemap()
{
return m_iblSpecularCubemapImage;
@@ -180,6 +169,58 @@ namespace ImageProcessingAtom
m_image = new ImageToProcess(IImageObjectPtr(m_input->m_inputImage->Clone(mipsToClone)));
}
break;
case StepConvertToLinear:
// convert to linear space and the output image pixel format should be rgba32f
ConvertToLinear();
break;
case StepSwizzle:
{
// swizzle if swizzle was set or decard alpha
bool swizzleWasSet = m_input->m_presetSetting.m_swizzle.size() >= 4;
if (swizzleWasSet || m_input->m_presetSetting.m_discardAlpha)
{
AZStd::string swizzle = "rgba";
if (swizzleWasSet)
{
swizzle = m_input->m_presetSetting.m_swizzle.substr(0, 4);
}
if (m_input->m_presetSetting.m_discardAlpha)
{
swizzle[3] = '1';
}
m_image->Get()->Swizzle(swizzle.c_str());
if (!m_input->m_presetSetting.m_discardAlpha)
{
m_alphaContent = EAlphaContent::eAlphaContent_Absent;
}
else
{
m_alphaContent = m_image->Get()->GetAlphaContent();
}
}
}
break;
case StepCubemapLayout:
// convert cubemap image's layout to vertical strip used in game.
if (IsConvertToCubemap())
{
if (!m_image->ConvertCubemapLayout(CubemapLayoutVertical))
{
m_image->Set(nullptr);
}
}
break;
case StepPreNormalize:
// normalize base image before mipmap generation if glossfromnormals is enabled and require normalize
if (m_input->m_presetSetting.m_isMipRenormalize && m_input->m_presetSetting.m_glossFromNormals)
{
// Normalize the base mip map. This has to be done explicitly because we need to disable mip renormalization to
// preserve the normal length when deriving the normal variance
m_image->Get()->NormalizeVectors(0, 1);
}
break;
case StepGenerateIBL:
if (IsConvertToCubemap())
@@ -204,56 +245,6 @@ namespace ImageProcessingAtom
m_isFinished = true;
}
break;
case StepGenerateColorChart:
// GenerateColorChart.
if (m_input->m_presetSetting.m_isColorChart)
{
// Convert to uncompressed format if it's compressed format. For example, loaded from DDS file.
if (!CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_image->Get()->GetPixelFormat()))
{
m_image->ConvertFormat(ePixelFormat_R32G32B32A32F);
}
m_image->CreateColorChart();
}
break;
case StepConvertToLinear:
// convert to linear space and the output image pixel format should be rgba32f
ConvertToLinear();
break;
case StepSwizzle:
// convert texture format.
if (m_input->m_presetSetting.m_swizzle.size() >= 4)
{
m_image->Get()->Swizzle(m_input->m_presetSetting.m_swizzle.substr(0, 4).c_str());
m_alphaContent = m_image->Get()->GetAlphaContent();
}
// convert gloss map (alhpa channel) from legacy distribution to new one
if (m_input->m_presetSetting.m_isLegacyGloss)
{
m_image->Get()->ConvertLegacyGloss();
}
break;
case StepCubemapLayout:
// convert cubemap image's layout to vertical strip used in game.
if (IsConvertToCubemap())
{
if (!m_image->ConvertCubemapLayout(CubemapLayoutVertical))
{
m_image->Set(nullptr);
}
}
break;
case StepPreNormalize:
// normalize base image before mipmap generation if glossfromnormals is enabled and require normalize
if (m_input->m_presetSetting.m_isMipRenormalize && m_input->m_presetSetting.m_glossFromNormals)
{
// Normalize the base mip map. This has to be done explicitly because we need to disable mip renormalization to
// preserve the normal length when deriving the normal variance
m_image->Get()->NormalizeVectors(0, 1);
}
break;
case StepMipmap:
// generate mipmaps
if (IsConvertToCubemap())
@@ -304,20 +295,10 @@ namespace ImageProcessingAtom
m_image->Get()->AddImageFlags(EIF_RenormalizedTexture);
}
break;
case StepCreateHighPass:
if (m_input->m_presetSetting.m_highPassMip > 0)
{
m_image->CreateHighPass(m_input->m_presetSetting.m_highPassMip);
}
break;
case StepConvertOutputColorSpace:
// convert image from linear space to desired output color space
ConvertToOuputColorSpace();
break;
case StepAlphaImage:
// save alpha channel to separate image if it's needed
CreateAlphaImage();
break;
case StepConvertPixelFormat:
// convert pixel format
ConvertPixelformat();
@@ -411,12 +392,6 @@ namespace ImageProcessingAtom
return;
}
// don't do any reduce for color chart
if (presetSettings->m_isColorChart)
{
return;
}
// get suitable size for dest pixel format
CPixelFormats::GetInstance().GetSuitableImageSize(presetSettings->m_pixelFormat, inputWidth, inputHeight,
outWidth, outHeight);
@@ -510,52 +485,6 @@ namespace ImageProcessingAtom
return true;
}
void ImageConvertProcess::CreateAlphaImage()
{
// if alpha content doesn't have alpha or we need to discard alpha, skip
// we won't create alpha image for cubemap too
if (m_alphaContent == EAlphaContent::eAlphaContent_Absent
|| m_alphaContent == EAlphaContent::eAlphaContent_OnlyWhite
|| m_input->m_presetSetting.m_discardAlpha || IsConvertToCubemap())
{
return;
}
// if dest format could save alpha, skip too
if (!CPixelFormats::GetInstance().IsPixelFormatWithoutAlpha(m_input->m_presetSetting.m_pixelFormat))
{
return;
}
// now create alpha image
ImageToProcess alphaImage(m_image->Get());
alphaImage.ConvertFormat(ePixelFormat_A8);
// validate pixelformatalpha
if (CPixelFormats::GetInstance().IsFormatSingleChannel(m_input->m_presetSetting.m_pixelFormatAlpha))
{
alphaImage.ConvertFormat(m_input->m_presetSetting.m_pixelFormatAlpha);
}
else
{
//For ASTC compression we need to clear out the alpha to get accurate rgb compression.
if (IsASTCFormat(m_input->m_presetSetting.m_pixelFormat))
{
alphaImage.ConvertFormat(ePixelFormat_R8G8B8X8);
alphaImage.ConvertFormat(m_input->m_presetSetting.m_pixelFormatAlpha);
}
else
{
AZ_Assert(false, "PixelFormatAlpha only supports single channel pixel formats or ASTC formats");
}
}
// get final result and save it to member variable for later use
m_alphaImage = alphaImage.Get();
m_image->Get()->AddImageFlags(EIF_AttachedAlpha);
}
// pixel format conversion
bool ImageConvertProcess::ConvertPixelformat()
{
@@ -575,12 +504,6 @@ namespace ImageProcessingAtom
m_image->GetCompressOption().rgbWeight = m_input->m_presetSetting.GetColorWeight();
m_image->GetCompressOption().discardAlpha = m_input->m_presetSetting.m_discardAlpha;
//For ASTC compression we need to clear out the alpha to get accurate rgb compression.
if(m_alphaImage && IsASTCFormat(m_input->m_presetSetting.m_pixelFormat))
{
m_image->GetCompressOption().discardAlpha = true;
}
m_image->ConvertFormat(m_input->m_presetSetting.m_pixelFormat);
return true;
@@ -762,7 +685,6 @@ namespace ImageProcessingAtom
if (ImageProcess##PrivateName::DoesSupport(m_input->m_platform)) \
{ \
ImageProcess##PrivateName::PrepareImageForExport(m_image->Get()); \
ImageProcess##PrivateName::PrepareImageForExport(m_alphaImage); \
}
AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS
#undef AZ_RESTRICTED_PLATFORM_EXPANSION
@@ -115,7 +115,6 @@ namespace ImageProcessingAtom
//get output images
IImageObjectPtr GetOutputImage();
IImageObjectPtr GetOutputAlphaImage();
IImageObjectPtr GetOutputIBLSpecularCubemap();
IImageObjectPtr GetOutputIBLDiffuseCubemap();
@@ -131,8 +130,6 @@ namespace ImageProcessingAtom
//for alpha
//to indicate the current alpha channel content
EAlphaContent m_alphaContent;
//An image object to hold alpha channel in a separate image
IImageObjectPtr m_alphaImage;
//output results of IBL cubemap generation, used in unit tests
IImageObjectPtr m_iblSpecularCubemapImage;
@@ -171,9 +168,6 @@ namespace ImageProcessingAtom
//convert to output color space before compression
bool ConvertToOuputColorSpace();
//create alpha image if it's needed
void CreateAlphaImage();
//pixel format convertion/compression
bool ConvertPixelformat();
@@ -108,17 +108,14 @@ namespace ImageProcessingAtom
}
IImageObjectPtr outputImage = m_process->GetOutputImage();
IImageObjectPtr outputImageAlpha = m_process->GetOutputAlphaImage();
m_output->SetOutputImage(outputImage, ImageConvertOutput::Base);
m_output->SetOutputImage(outputImageAlpha, ImageConvertOutput::Alpha);
if (!IsJobCancelled())
{
// For preview, combine image output with alpha if any
m_output->SetProgress(1.0f / static_cast<float>(m_previewProcessStep));
IImageObjectPtr combinedImage = MergeOutputImageForPreview(outputImage, outputImageAlpha);
m_output->SetOutputImage(combinedImage, ImageConvertOutput::Preview);
m_output->SetOutputImage(outputImage, ImageConvertOutput::Preview);
}
m_output->SetReady(true);
@@ -20,7 +20,7 @@ namespace ImageProcessingAtom
const static AZ::u32 EIF_Greyscale = 0x8; // hint for the engine (e.g. greyscale light beams can be applied to shadow mask), can be for DXT1 because compression artfacts don't count as color
const static AZ::u32 EIF_SupressEngineReduce = 0x10; // info for the engine: don't reduce texture resolution on this texture
const static AZ::u32 EIF_UNUSED_BIT = 0x40; // Free to use
const static AZ::u32 EIF_AttachedAlpha = 0x400; // info for the engine: it's a texture with attached alpha channel
const static AZ::u32 EIF_AttachedAlpha = 0x400; // deprecated: info for the engine: it's a texture with attached alpha channel
const static AZ::u32 EIF_SRGBRead = 0x800; // info for the engine: if gamma corrected rendering is on, this texture requires SRGBRead (it's not stored in linear)
const static AZ::u32 EIF_DontResize = 0x8000; // info for the engine: for dds textures that shouldn't be resized
const static AZ::u32 EIF_RenormalizedTexture = 0x10000; // info for the engine: for dds textures that have renormalized color range
@@ -316,130 +316,6 @@ namespace ImageProcessingAtom
m_mips.clear();
}
//note: there are some unreasonable parts of the save files formats for cry textures. We might need to rethink about
// it for new renderer
bool CImageObject::SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector<AZStd::string>& outFilePaths) const
{
AZ::IO::SystemFile file;
file.Open(filename, AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY);
AZ::IO::SystemFileStream fileSaveStream(&file, true);
if (!fileSaveStream.IsOpen())
{
AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, filename);
return false;
}
if (alphaImage)
{
AZ_Assert(HasImageFlags(EIF_AttachedAlpha), "attached alpha image flag wasn't set");
AZ_Assert(!alphaImage->HasImageFlags(EIF_AttachedAlpha), "alpha image shouldn't have attached alpha image flag");
// inherit cubemap and decal image flags to attached alpha image
alphaImage->AddImageFlags(GetImageFlags() & (EIF_Cubemap
| EIF_Decal | EIF_Splitted));
alphaImage->SetNumPersistentMips(m_numPersistentMips);
}
bool bOk = SaveImage(fileSaveStream);
bool hasSplitFlag = HasImageFlags(EIF_Splitted);
//append alpha image data in the end if there is no split
if (bOk && alphaImage && !hasSplitFlag)
{
//4 bytes extension tag, 4 bytes attached alpha tag, then 4 bytes of chunk size
fileSaveStream.Write(sizeof(FOURCC_CExt), &FOURCC_CExt); // marker for the start of O3DE Extended data
fileSaveStream.Write(sizeof(FOURCC_AttC), &FOURCC_AttC); // Attached Channel chunk
uint32_t size = 0;
uint32_t sizeBytes = sizeof(size);
fileSaveStream.Write(sizeBytes, &size); //size of attached chunk
//save alpha image and get the size
AZ::IO::SizeType startPos = fileSaveStream.GetCurPos();
bOk = alphaImage->SaveImage(fileSaveStream);
AZ::IO::SizeType endPos = fileSaveStream.GetCurPos();
size = static_cast<uint32_t>(endPos - startPos);
//move back to beginning of chunk and write chunk size then move back to end
fileSaveStream.Seek(startPos - sizeBytes, AZ::IO::GenericStream::ST_SEEK_BEGIN);
fileSaveStream.Write(sizeBytes, &size);
fileSaveStream.Seek(endPos, AZ::IO::GenericStream::ST_SEEK_BEGIN);
// marker for the end of O3DE Extended data
fileSaveStream.Write(sizeof(FOURCC_CEnd), &FOURCC_CEnd);
}
if (!bOk)
{
AZ::IO::SystemFile::Delete(filename);
return false;
}
// It's important to maintain the product output sequence. Asset Database/Browser will use the first product to determine the source type!
outFilePaths.push_back(filename);
// save stand alone products
if (hasSplitFlag)
{
// alpha
if (alphaImage)
{
AZStd::string alphaFile = AZStd::string::format("%s.a", filename);
AZ::IO::SystemFile outAlphaFile;
outAlphaFile.Open(alphaFile.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY);
AZ::IO::SystemFileStream alphaFileSaveStream(&outAlphaFile, true);
if (alphaFileSaveStream.IsOpen())
{
alphaImage->SaveImage(alphaFileSaveStream);
outFilePaths.push_back(alphaFile);
}
else
{
AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, alphaFile.c_str());
}
}
// mips
AZ::u32 numStreamable = GetMipCount() - m_numPersistentMips;
for (AZ::u32 mip = 0; mip < numStreamable; mip++)
{
AZ::u32 nameIdx = numStreamable - mip;
AZStd::string mipFileName = AZStd::string::format("%s.%d", filename, nameIdx);
SaveMipToFile(mip, mipFileName);
outFilePaths.push_back(mipFileName);
if (alphaImage)
{
AZStd::string mipAlphaFileName = mipFileName + "a";
alphaImage->SaveMipToFile(mip, mipAlphaFileName);
outFilePaths.push_back(mipAlphaFileName);
}
}
}
return bOk;
}
bool CImageObject::SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const
{
AZ::IO::SystemFile saveFile;
saveFile.Open(filename.c_str(), AZ::IO::SystemFile::SF_OPEN_CREATE | AZ::IO::SystemFile::SF_OPEN_CREATE_PATH | AZ::IO::SystemFile::SF_OPEN_WRITE_ONLY);
AZ::IO::SystemFileStream saveFileStream(&saveFile, true);
if (!saveFileStream.IsOpen())
{
AZ_Warning("Image Processing", false, "%s: failed to create file %s", __FUNCTION__, filename.c_str());
return false;
}
saveFileStream.Write(GetMipBufSize(mip), m_mips[mip]->m_pData);
return true;
}
float CImageObject::CalculateAverageBrightness() const
{
//if it's compressed format, return a default value
@@ -642,63 +518,6 @@ namespace ImageProcessingAtom
return true;
}
bool CImageObject::SaveImage(AZ::IO::SystemFileStream& saveFileStream) const
{
DDS_FILE_DESC_LEGACY desc;
DDS_HEADER_DXT10 exthead;
desc.dwMagic = FOURCC_DDS;
if (!BuildSurfaceHeader(desc.header))
{
return false;
}
if (desc.header.IsDX10Ext() && !BuildSurfaceExtendedHeader(exthead))
{
return false;
}
saveFileStream.Write(sizeof(desc), &desc);
if (desc.header.IsDX10Ext())
{
saveFileStream.Write(sizeof(exthead), &exthead);
}
AZ::u32 faces = 1;
//for cubemap. export each face and its mipmap
if (HasImageFlags(EIF_Cubemap))
{
faces = 6;
}
AZ::u32 mipStart = 0;
if (HasImageFlags(EIF_Splitted))
{
if (m_numPersistentMips < m_mips.size())
{
mipStart = (AZ::u32)m_mips.size() - m_numPersistentMips;
}
else
{
AZ_Assert(false, "numPersistentMips wasn't setup correctly");
}
}
for (AZ::u32 face = 0; face < faces; face++)
{
for (AZ::u32 mip = mipStart; mip < m_mips.size(); ++mip)
{
const MipLevel& level = *m_mips[mip];
AZ::u32 faceBufSize = level.m_pitch * level.m_rowCount / faces;
saveFileStream.Write(faceBufSize, level.m_pData + faceBufSize * face);
}
}
return true;
}
void CImageObject::GetExtent(AZ::u32& width, AZ::u32& height, AZ::u32& mipCount) const
{
mipCount = (AZ::u32)m_mips.size();
@@ -953,35 +772,4 @@ namespace ImageProcessingAtom
}
}
}
void CImageObject::ConvertLegacyGloss()
{
if (!(CPixelFormats::GetInstance().IsPixelFormatUncompressed(m_pixelFormat)))
{
AZ_Assert(false, "%s function only works with uncompressed pixel format", __FUNCTION__);
return;
}
//create pixel operation function
IPixelOperationPtr pixelOp = CreatePixelOperation(m_pixelFormat);
//get count of bytes per pixel
AZ::u32 pixelBytes = CPixelFormats::GetInstance().GetPixelFormatInfo(m_pixelFormat)->bitsPerBlock / 8;
const AZ::u32 mips = (AZ::u32)m_mips.size();
float color[4];
for (AZ::u32 mip = 0; mip < mips; ++mip)
{
AZ::u8* pixelBuf = m_mips[mip]->m_pData;
const AZ::u32 pixelCount = GetPixelCount(mip);
for (AZ::u32 i = 0; i < pixelCount; ++i, pixelBuf += pixelBytes)
{
pixelOp->GetRGBA(pixelBuf, color[0], color[1], color[2], color[3]);
// Convert from (1 - s * 0.7)^6 to (1 - s)^2
color[3] = 1 - pow(1.0f - color[3] * 0.7f, 3.0f);
pixelOp->SetRGBA(pixelBuf, color[0], color[1], color[2], color[3]);
}
}
}
} // namespace ImageProcessingAtom
@@ -57,10 +57,6 @@ namespace ImageProcessingAtom
bool CompareImage(const IImageObjectPtr otherImage) const override;
bool SaveImage(const char* filename, IImageObjectPtr alphaImage, AZStd::vector<AZStd::string>& outFilePaths) const override;
bool SaveImage(AZ::IO::SystemFileStream& out) const override;
bool SaveMipToFile(AZ::u32 mip, const AZStd::string& filename) const override;
uint32_t GetTextureMemory() const override;
EAlphaContent GetAlphaContent() const override;
@@ -79,7 +75,6 @@ namespace ImageProcessingAtom
void SetNumPersistentMips(AZ::u32 nMips) override;
void GlossFromNormals(bool hasAuthoredGloss) override;
void ConvertLegacyGloss() override;
void ClearColor(float r, float g, float b, float a) override;
//end virtual functions from IImageObject
@@ -66,13 +66,6 @@ namespace ImageProcessingAtom
bool GammaToLinearRGBA32F(bool bDeGamma);
void LinearToGamma();
// ---------------------------------------------------------------------------------
// Tools for A32B32G32R32F
void CreateHighPass(uint32 dwMipDown);
void CreateColorChart();
//convert various original cubemap layouts to new layout
bool ConvertCubemapLayout(CubemapLayoutType newLayout);
};
@@ -988,7 +988,6 @@ namespace UnitTest
ASSERT_TRUE(process->IsSucceed());
SaveImageToFile(process->GetOutputImage(), "rgb", 10);
SaveImageToFile(process->GetOutputAlphaImage(), "alpha", 10);
process->GetAppendOutputProducts(outProducts);
@@ -103,8 +103,6 @@ set(FILES
Source/Converters/ConvertPixelFormat.cpp
Source/Converters/Cubemap.h
Source/Converters/Cubemap.cpp
Source/Converters/ColorChart.cpp
Source/Converters/HighPass.cpp
Source/Converters/Histogram.cpp
Source/Converters/Histogram.h
../External/CubeMapGen/CBBoxInt32.cpp
@@ -272,6 +272,7 @@ namespace AZ
// Create and register a scene with all available feature processors
RPI::SceneDescriptor sceneDesc;
sceneDesc.m_nameId = AZ::Name("Main");
AZ::RPI::ScenePtr atomScene = RPI::Scene::CreateScene(sceneDesc);
atomScene->EnableAllFeatureProcessors();
atomScene->Activate();
@@ -153,7 +153,7 @@ struct StandardMaterialInputs
float2 m_vertexUv[UvSetCount];
float3x3 m_uvMatrix;
float m_normal;
float3 m_normal;
float3 m_tangents[UvSetCount];
float3 m_bitangents[UvSetCount];
@@ -32,7 +32,7 @@ namespace AZ
{
if (m_rtPipeline)
{
AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->RemoveRenderPipeline(m_rtPipeline->GetId());
m_rtPipeline->RemoveFromScene();
m_rtPipeline = nullptr;
}
@@ -111,8 +111,12 @@ namespace AZ
parentPass->SetSourceTexture(m_texture, RHI::Format::R8G8B8A8_UNORM);
break;
}
AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->AddRenderPipeline(m_rtPipeline);
const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("RPI"));
if (mainScene)
{
mainScene->AddRenderPipeline(m_rtPipeline);
}
}
bool LuxCoreTexture::IsIBLTexture()
@@ -70,7 +70,8 @@ namespace AZ
void InitializeSystemAssets() override;
void RegisterScene(ScenePtr scene) override;
void UnregisterScene(ScenePtr scene) override;
ScenePtr GetScene(const SceneId& sceneId) const override;
Scene* GetScene(const SceneId& sceneId) const override;
Scene* GetSceneByName(const AZ::Name& name) const override;
ScenePtr GetDefaultScene() const override;
RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) override;
Data::Asset<ShaderAsset> GetCommonShaderAssetForSrgs() const override;
@@ -13,6 +13,7 @@
#include <Atom/RPI.Public/Base.h>
#include <AzCore/Name/Name.h>
#include <AzFramework/Windowing/WindowBus.h>
namespace AZ
@@ -46,11 +47,14 @@ namespace AZ
//! Unregister a scene from RPISystem. The scene won't be simulated or rendered.
virtual void UnregisterScene(ScenePtr scene) = 0;
// [GFX TODO] to be removed when we have scene setup in AZ Core
virtual ScenePtr GetDefaultScene() const = 0;
//! Deprecated. Use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead
AZ_DEPRECATED(virtual ScenePtr GetDefaultScene() const = 0;, "This method has been deprecated. Please use GetSceneByName(name), GetSceneForEntityContextId(entityContextId) or Scene::GetSceneForEntityId(AZ::EntityId entityId) instead.");
//! Get scene by using scene id.
virtual ScenePtr GetScene(const SceneId& sceneId) const = 0;
virtual Scene* GetScene(const SceneId& sceneId) const = 0;
//! Get scene by using scene name.
virtual Scene* GetSceneByName(const AZ::Name& name) const = 0;
//! Get the render pipeline created for a window
virtual RenderPipelinePtr GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle) = 0;
@@ -80,6 +80,9 @@ namespace AZ
//! Gets the RPI::Scene for a given entityContextId.
//! May return nullptr if there is no RPI::Scene created for that entityContext.
static Scene* GetSceneForEntityContextId(AzFramework::EntityContextId entityContextId);
//! Gets the RPI::Scene for a given entityId.
static Scene* GetSceneForEntityId(AZ::EntityId entityId);
~Scene();
@@ -135,6 +138,8 @@ namespace AZ
const SceneId& GetId() const;
AZ::Name GetName() const;
//! Set default pipeline by render pipeline ID.
//! It returns true if the default render pipeline was set from the input ID.
//! If the specified render pipeline doesn't exist in this scene then it won't do anything and returns false.
@@ -245,6 +250,9 @@ namespace AZ
// The uuid to identify this scene.
SceneId m_id;
// Scene's name which is set at initialization. Can be empty
AZ::Name m_name;
bool m_activated = false;
bool m_taskGraphActive = false; // update during tick, to ensure it only changes on frame boundaries
@@ -286,13 +294,10 @@ namespace AZ
template<typename FeatureProcessorType>
FeatureProcessorType* Scene::GetFeatureProcessorForEntity(AZ::EntityId entityId)
{
// Find the entity context for the entity ID.
AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull();
AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
if (!entityContextId.IsNull())
RPI::Scene* renderScene = GetSceneForEntityId(entityId);
if (renderScene)
{
return GetFeatureProcessorForEntityContextId<FeatureProcessorType>(entityContextId);
return renderScene->GetFeatureProcessor<FeatureProcessorType>();
}
return nullptr;
};
@@ -9,6 +9,7 @@
#pragma once
#include <AzCore/Asset/AssetCommon.h>
#include <AzCore/Name/Name.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/string/string.h>
@@ -25,6 +26,9 @@ namespace AZ
//! List of feature processors which the scene will initially enable.
AZStd::vector<AZStd::string> m_featureProcessorNames;
//! A name used as scene id. It can be used to search a registered scene via RPISystemInterface::GetScene()
AZ::Name m_nameId;
};
} // namespace RPI
} // namespace AZ
@@ -699,9 +699,7 @@ namespace AZ
m_parentScene = parentScene;
AZ_Assert(m_visScene == nullptr, "IVisibilityScene already created for this RPI::Scene");
char sceneIdBuf[40] = "";
m_parentScene->GetId().ToString(sceneIdBuf);
AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", sceneIdBuf));
AZ::Name visSceneName(AZStd::string::format("RenderCullScene[%s]", m_parentScene->GetName().GetCStr()));
m_visScene = AZ::Interface<AzFramework::IVisibilitySystem>::Get()->CreateVisibilityScene(visSceneName);
#ifdef AZ_CULL_DEBUG_ENABLED
@@ -159,6 +159,11 @@ namespace AZ
AZ_Assert(false, "Scene was already registered");
return;
}
else if (!scene->GetName().IsEmpty() && scene->GetName() == sceneItem->GetName())
{
// only report a warning if there is a scene with duplicated name
AZ_Warning("RPISystem", false, "There is a registered scene with same name [%s]", scene->GetName().GetCStr());
}
}
m_scenes.push_back(scene);
@@ -177,11 +182,35 @@ namespace AZ
AZ_Assert(false, "Can't unregister scene which wasn't registered");
}
ScenePtr RPISystem::GetScene(const SceneId& sceneId) const
Scene* RPISystem::GetScene(const SceneId& sceneId) const
{
for (const auto& scene : m_scenes)
{
if (scene->GetId() == sceneId)
{
return scene.get();
}
}
return nullptr;
}
Scene* RPISystem::GetSceneByName(const AZ::Name& name) const
{
for (const auto& scene : m_scenes)
{
if (scene->GetName() == name)
{
return scene.get();
}
}
return nullptr;
}
ScenePtr RPISystem::GetDefaultScene() const
{
for (const auto& scene : m_scenes)
{
if (scene->GetName() == AZ::Name("Main"))
{
return scene;
}
@@ -189,16 +218,6 @@ namespace AZ
return nullptr;
}
ScenePtr RPISystem::GetDefaultScene() const
{
if (m_scenes.size() > 0)
{
return m_scenes[0];
}
return nullptr;
}
RenderPipelinePtr RPISystem::GetRenderPipelineForWindow(AzFramework::NativeWindowHandle windowHandle)
{
RenderPipelinePtr renderPipeline;
+22 -3
View File
@@ -45,7 +45,9 @@ namespace AZ
auto shaderAsset = RPISystemInterface::Get()->GetCommonShaderAssetForSrgs();
scene->m_srg = ShaderResourceGroup::Create(shaderAsset, sceneSrgLayout->GetName());
}
scene->m_name = sceneDescriptor.m_nameId;
return ScenePtr(scene);
}
@@ -83,10 +85,23 @@ namespace AZ
return nullptr;
}
Scene* Scene::GetSceneForEntityId(AZ::EntityId entityId)
{
// Find the entity context for the entity ID.
AzFramework::EntityContextId entityContextId = AzFramework::EntityContextId::CreateNull();
AzFramework::EntityIdContextQueryBus::EventResult(entityContextId, entityId, &AzFramework::EntityIdContextQueryBus::Events::GetOwningContextId);
if (!entityContextId.IsNull())
{
return GetSceneForEntityContextId(entityContextId);
}
return nullptr;
}
Scene::Scene()
{
m_id = Uuid::CreateRandom();
m_id = AZ::Uuid::CreateRandom();
m_cullingScene = aznew CullingScene();
SceneRequestBus::Handler::BusConnect(m_id);
m_drawFilterTagRegistry = RHI::DrawFilterTagRegistry::Create();
@@ -299,7 +314,6 @@ namespace AZ
// Force to update the lookup table since adding render pipeline would effect any pipeline states created before pass system tick
RebuildPipelineStatesLookup();
AZ_Assert(!m_id.IsNull(), "RPI::Scene needs to have a valid uuid.");
SceneNotificationBus::Event(m_id, &SceneNotification::OnRenderPipelineAdded, pipeline);
}
@@ -785,6 +799,11 @@ namespace AZ
{
return m_id;
}
AZ::Name Scene::GetName() const
{
return m_name;
}
bool Scene::SetDefaultRenderPipeline(const RenderPipelineId& pipelineId)
{
@@ -43,6 +43,7 @@ namespace AtomToolsFramework
&PreviewerFeatureProcessorProviderBus::Handler::GetRequiredFeatureProcessors, featureProcessors);
AZ::RPI::SceneDescriptor sceneDesc;
sceneDesc.m_nameId = AZ::Name("PreviewRenderer");
sceneDesc.m_featureProcessorNames.assign(featureProcessors.begin(), featureProcessors.end());
m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
@@ -279,9 +279,9 @@ namespace MaterialEditor
// reset environment
AZ::Transform iblTransform = AZ::Transform::CreateIdentity();
AZ::TransformBus::Event(m_iblEntityId, &AZ::TransformBus::Events::SetLocalTM, iblTransform);
const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity();
AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
auto skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::Render::SkyBoxFeatureProcessorInterface>(m_iblEntityId);
skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix);
if (m_behavior)
@@ -25,8 +25,7 @@ namespace MaterialEditor
m_iblEntityId,
&MaterialEditorViewportInputControllerRequestBus::Handler::GetIblEntityId);
AZ_Assert(m_iblEntityId.IsValid(), "Failed to find m_iblEntityId");
AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
m_skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
m_skyBoxFeatureProcessorInterface = AZ::RPI::Scene::GetFeatureProcessorForEntity<AZ::Render::SkyBoxFeatureProcessorInterface>(m_iblEntityId);
}
void RotateEnvironmentBehavior::TickInternal(float x, float y, float z)
@@ -67,6 +67,7 @@ namespace MaterialEditor
// Create and register a scene with all available feature processors
AZ::RPI::SceneDescriptor sceneDesc;
sceneDesc.m_nameId = AZ::Name("MaterialViewport");
m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
m_scene->EnableAllFeatureProcessors();
@@ -108,7 +108,7 @@ namespace AZ
{
m_dynamicDrawManager.reset();
AZ::RPI::ViewportContextManagerNotificationsBus::Handler::BusDisconnect();
RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get();
RPI::Scene* scene = AZ::RPI::Scene::GetSceneForEntityContextId(m_entityContextId);
// Check if scene is emptry since scene might be released already when running AtomSampleViewer
if (scene)
{
@@ -157,9 +157,9 @@ namespace AZ
void AtomBridgeSystemComponent::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
{
AZ_UNUSED(bootstrapScene);
// Make default AtomDebugDisplayViewportInterface
AZStd::shared_ptr<AtomDebugDisplayViewportInterface> mainEntityDebugDisplay = AZStd::make_shared<AtomDebugDisplayViewportInterface>(AzFramework::g_defaultSceneEntityDebugDisplayId);
AZStd::shared_ptr<AtomDebugDisplayViewportInterface> mainEntityDebugDisplay =
AZStd::make_shared<AtomDebugDisplayViewportInterface>(AzFramework::g_defaultSceneEntityDebugDisplayId, bootstrapScene);
m_activeViewportsList[AzFramework::g_defaultSceneEntityDebugDisplayId] = mainEntityDebugDisplay;
}
@@ -256,12 +256,11 @@ namespace AZ::AtomBridge
viewportContextPtr->ConnectSceneChangedHandler(m_sceneChangeHandler);
}
AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress)
AtomDebugDisplayViewportInterface::AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene)
{
ResetRenderState();
m_viewportId = defaultInstanceAddress;
m_defaultInstance = true;
RPI::Scene* scene = RPI::RPISystemInterface::Get()->GetDefaultScene().get();
InitInternal(scene, nullptr);
}
@@ -800,7 +799,8 @@ namespace AZ::AtomBridge
const float startAngle = DegToRad(startAngleDegrees);
const float stopAngle = DegToRad(sweepAngleDegrees) + startAngle;
SingleColorDynamicSizeLineHelper lines(1+static_cast<int>(sweepAngleDegrees/angularStepDegrees));
AZ::Vector3 radiusV3 = AZ::Vector3(radius);
float aspectRadius = radius / GetAspectRatio();
AZ::Vector3 radiusV3 = AZ::Vector3(aspectRadius, radius, radius);
AZ::Vector3 pos = AZ::Vector3(center.GetX(), center.GetY(), z);
CreateAxisAlignedArc(
lines,
@@ -124,7 +124,7 @@ namespace AZ::AtomBridge
AZ_RTTI(AtomDebugDisplayViewportInterface, "{09AF6A46-0100-4FBF-8F94-E6B221322D14}", AzFramework::DebugDisplayRequestBus::Handler);
explicit AtomDebugDisplayViewportInterface(AZ::RPI::ViewportContextPtr viewportContextPtr);
explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress);
explicit AtomDebugDisplayViewportInterface(uint32_t defaultInstanceAddress, RPI::Scene* scene);
~AtomDebugDisplayViewportInterface();
void ResetRenderState();
@@ -133,18 +133,6 @@ namespace AZ
typedef std::vector<FontEffect> FontEffects;
typedef FontEffects::iterator FontEffectsIterator;
struct FontPipelineStateMapKey
{
AZ::RPI::SceneId m_sceneId; // which scene pipeline state is attached to (via Render Pipeline)
AZ::RHI::DrawListTag m_drawListTag; // which render pass this pipeline draws in by default
bool operator<(const FontPipelineStateMapKey& other) const
{
return m_sceneId < other.m_sceneId
|| (m_sceneId == other.m_sceneId && m_drawListTag < other.m_drawListTag);
}
};
struct FontShaderData
{
AZ::RHI::ShaderInputNameIndex m_imageInputIndex = "m_texture";
@@ -48,11 +48,7 @@ namespace AZ
void DiffuseGlobalIlluminationComponentController::Activate(EntityId entityId)
{
AZ_UNUSED(entityId);
const RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get();
m_featureProcessor = scene->GetFeatureProcessor<DiffuseGlobalIlluminationFeatureProcessorInterface>();
m_featureProcessor = AZ::RPI::Scene::GetFeatureProcessorForEntity<DiffuseGlobalIlluminationFeatureProcessorInterface>(entityId);
OnConfigChanged();
}
@@ -79,7 +79,7 @@ namespace AZ
m_entityId = entityId;
m_dirty = true;
RPI::ScenePtr scene = RPI::RPISystemInterface::Get()->GetDefaultScene();
RPI::Scene* scene = RPI::Scene::GetSceneForEntityId(m_entityId);
if (scene)
{
AZ::RPI::SceneNotificationBus::Handler::BusConnect(scene->GetId());
@@ -357,8 +357,7 @@ namespace AZ
void DisplayMapperComponentController::OnConfigChanged()
{
// Register the configuration with the AcesDisplayMapperFeatureProcessor for this scene.
const AZ::RPI::Scene* scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene().get();
DisplayMapperFeatureProcessorInterface* fp = scene->GetFeatureProcessor<DisplayMapperFeatureProcessorInterface>();
DisplayMapperFeatureProcessorInterface* fp = AZ::RPI::Scene::GetFeatureProcessorForEntity<DisplayMapperFeatureProcessorInterface>(m_entityId);
DisplayMapperConfigurationDescriptor desc;
desc.m_operationType = m_configuration.m_displayMapperOperation;
desc.m_ldrGradingLutEnabled = m_configuration.m_ldrColorGradingLutEnabled;
@@ -48,7 +48,7 @@ namespace AZ
// CVar for toggling the display of the scene stats
int r_skinnedMeshDisplaySceneStats = 0;
// SceneId to query for the stats
RPI::SceneId m_sceneId = RPI::SceneId::CreateNull();
RPI::SceneId m_sceneId;
};
}// namespace Render
}// namespace AZ
@@ -60,6 +60,7 @@ namespace EMStudio
// Create and register a scene with all available feature processors
AZ::RPI::SceneDescriptor sceneDesc;
sceneDesc.m_nameId = AZ::Name("AnimViewport");
m_scene = AZ::RPI::Scene::CreateScene(sceneDesc);
m_scene->EnableAllFeatureProcessors();
@@ -213,8 +214,7 @@ namespace EMStudio
AZ::TransformBus::Event(m_iblEntity->GetId(), &AZ::TransformBus::Events::SetLocalTM, iblTransform);
const AZ::Matrix4x4 rotationMatrix = AZ::Matrix4x4::CreateIdentity();
AZ::RPI::ScenePtr scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
auto skyBoxFeatureProcessorInterface = scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
auto skyBoxFeatureProcessorInterface = m_scene->GetFeatureProcessor<AZ::Render::SkyBoxFeatureProcessorInterface>();
skyBoxFeatureProcessorInterface->SetCubemapRotationMatrix(rotationMatrix);
}
@@ -255,19 +255,22 @@ namespace Blast
BlastFamilyComponentRequestBus::Broadcast(
&BlastFamilyComponentRequests::FillDebugRenderBuffer, buffer, m_debugRenderMode);
// This is a system component, and thus is not associated with a specific scene, so use the default scene
// This is a system component, and thus is not associated with a specific scene, so use the bootstrap scene
// for the debug drawing
const auto defaultScene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(defaultScene);
for (DebugLine& line : buffer.m_lines)
const auto mainScene = AZ::RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("Main"));
if (mainScene)
{
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments;
drawArguments.m_verts = &line.m_p0;
drawArguments.m_vertCount = 2;
drawArguments.m_colors = &line.m_color;
drawArguments.m_colorCount = 1;
drawQueue->DrawLines(drawArguments);
auto drawQueue = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(mainScene);
for (DebugLine& line : buffer.m_lines)
{
AZ::RPI::AuxGeomDraw::AuxGeomDynamicDrawArguments drawArguments;
drawArguments.m_verts = &line.m_p0;
drawArguments.m_vertCount = 2;
drawArguments.m_colors = &line.m_color;
drawArguments.m_colorCount = 1;
drawQueue->DrawLines(drawArguments);
}
}
}
}
+6 -6
View File
@@ -65,7 +65,7 @@ CDraw2d::~CDraw2d()
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene)
void CDraw2d::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
{
// At this point the RPI is ready for use
@@ -74,16 +74,16 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc
AZ::Data::Instance<AZ::RPI::Shader> shader = AZ::RPI::LoadCriticalShader(shaderFilepath);
// Set scene to be associated with the dynamic draw context
AZ::RPI::ScenePtr scene;
AZ::RPI::Scene* scene = nullptr;
if (m_viewportContext)
{
// Use scene associated with the specified viewport context
scene = m_viewportContext->GetRenderScene();
scene = m_viewportContext->GetRenderScene().get();
}
else
{
// No viewport context specified, use default scene
scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
// No viewport context specified, use main scene
scene = bootstrapScene;
}
AZ_Assert(scene != nullptr, "Attempting to create a DynamicDrawContext for a viewport context that has not been associated with a scene yet.");
@@ -113,7 +113,7 @@ void CDraw2d::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapSc
else
{
// Render target support is disabled
m_dynamicDraw->SetOutputScope(scene.get());
m_dynamicDraw->SetOutputScope(scene);
}
m_dynamicDraw->EndInit();
+2 -2
View File
@@ -653,12 +653,12 @@ void CLyShine::OnRenderTick()
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CLyShine::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene)
void CLyShine::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
{
// Load cursor if its path was set before RPI was initialized
LoadUiCursor();
LyShinePassDataRequestBus::Handler::BusConnect(AZ::RPI::RPISystemInterface::Get()->GetDefaultScene()->GetId());
LyShinePassDataRequestBus::Handler::BusConnect(bootstrapScene->GetId());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
+7 -6
View File
@@ -52,7 +52,7 @@ bool UiRenderer::IsReady()
return m_isRPIReady;
}
void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstrapScene)
void UiRenderer::OnBootstrapSceneReady(AZ::RPI::Scene* bootstrapScene)
{
// At this point the RPI is ready for use
@@ -64,16 +64,17 @@ void UiRenderer::OnBootstrapSceneReady([[maybe_unused]] AZ::RPI::Scene* bootstra
if (m_viewportContext)
{
// Create a new scene based on the user specified viewport context
m_scene = CreateScene(m_viewportContext);
m_ownedScene = CreateScene(m_viewportContext);
m_scene = m_ownedScene.get();
}
else
{
// No viewport context specified, use default scene
m_scene = AZ::RPI::RPISystemInterface::Get()->GetDefaultScene();
m_scene = bootstrapScene;
}
// Create a dynamic draw context for UI Canvas drawing for the scene
m_dynamicDraw = CreateDynamicDrawContext(m_scene, uiShader);
m_dynamicDraw = CreateDynamicDrawContext(uiShader);
if (m_dynamicDraw)
{
@@ -93,6 +94,7 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr<AZ::RPI::ViewportCon
{
// Create a scene with the necessary feature processors
AZ::RPI::SceneDescriptor sceneDesc;
sceneDesc.m_nameId = AZ::Name("UiRenderer");
AZ::RPI::ScenePtr atomScene = AZ::RPI::Scene::CreateScene(sceneDesc);
atomScene->EnableAllFeatureProcessors(); // LYSHINE_ATOM_TODO - have a UI pipeline and enable only needed fps
@@ -116,7 +118,6 @@ AZ::RPI::ScenePtr UiRenderer::CreateScene(AZStd::shared_ptr<AZ::RPI::ViewportCon
}
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::CreateDynamicDrawContext(
AZ::RPI::ScenePtr scene,
AZ::Data::Instance<AZ::RPI::Shader> uiShader)
{
// Find the pass that renders the UI canvases after the rtt passes
@@ -144,7 +145,7 @@ AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> UiRenderer::CreateDynamicDrawContext(
else
{
// Render target support is disabled
dynamicDraw->SetOutputScope(m_scene.get());
dynamicDraw->SetOutputScope(m_scene);
}
dynamicDraw->EndInit();
+2 -2
View File
@@ -152,7 +152,6 @@ private: // member functions
//! Create a dynamic draw context for this renderer
AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> CreateDynamicDrawContext(
AZ::RPI::ScenePtr scene,
AZ::Data::Instance<AZ::RPI::Shader> uiShader);
//! Bind the global white texture for all the texture units we use
@@ -175,7 +174,8 @@ protected: // attributes
// Set by user when viewport context is not the main/default viewport
AZStd::shared_ptr<AZ::RPI::ViewportContext> m_viewportContext;
AZ::RPI::ScenePtr m_scene;
AZ::RPI::ScenePtr m_ownedScene;
AZ::RPI::Scene* m_scene = nullptr;
#ifndef _RELEASE
int m_debugTextureDataRecordLevel = 0;
@@ -102,7 +102,9 @@ namespace UnitTest
prefabBuilderComponent.Activate();
AZStd::vector<AssetBuilderSDK::JobProduct> jobProducts;
auto&& prefabDom = prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId());
// Make a copy of the template DOM, as the prefab system still owns the existing template
AzToolsFramework::Prefab::PrefabDom prefabDom;
prefabDom.CopyFrom(prefabSystemComponentInterface->FindTemplateDom(parentInstance->GetTemplateId()), prefabDom.GetAllocator(), false);
ASSERT_TRUE(prefabBuilderComponent.ProcessPrefab({AZ::Crc32("pc")}, "parent.prefab", "unused", AZ::Uuid(), prefabDom, jobProducts));
@@ -218,9 +218,10 @@ float4x4 GetObject_WorldMatrix()
float GetHeight(float2 origUv)
{
float2 uv = clamp(origUv + (ObjectSrg::m_terrainData.m_uvStep * 0.5f), 0.0f, 1.0f);
float height = 0.0f;
float2 halfStep = ObjectSrg::m_terrainData.m_uvStep * 0.5;
float2 uv = origUv * (1.0 - ObjectSrg::m_terrainData.m_uvStep) + halfStep;
float height = 0.0f;
if (o_useTerrainSmoothing)
{
float2 textureSize;
@@ -164,14 +164,17 @@ namespace Terrain
// could just make this list a prioritized list from top to bottom for any points that overlap.
for (auto& gradientId : m_configuration.m_gradientEntities)
{
// If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain
// to *not* exist at a specific point.
terrainExists = true;
if (gradientId.IsValid())
{
// If gradients ever provide bounds, or if we add a value threshold in this component, it would be possible for terrain
// to *not* exist at a specific point.
terrainExists = true;
float sample = 0.0f;
GradientSignal::GradientRequestBus::EventResult(
sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
maxSample = AZ::GetMax(maxSample, sample);
float sample = 0.0f;
GradientSignal::GradientRequestBus::EventResult(
sample, gradientId, &GradientSignal::GradientRequestBus::Events::GetValue, params);
maxSample = AZ::GetMax(maxSample, sample);
}
}
m_isRequestInProgress = false;
}
@@ -218,6 +218,12 @@ namespace Terrain
AzFramework::Terrain::TerrainDataRequestBus::BroadcastResult(
queryResolution, &AzFramework::Terrain::TerrainDataRequests::GetTerrainHeightQueryResolution);
// Take the dirty region and adjust the Z values to the world min/max so that even if the dirty region falls outside the current
// world bounds, we still update the wireframe accordingly.
AZ::Aabb dirtyRegion2D = AZ::Aabb::CreateFromMinMaxValues(
dirtyRegion.GetMin().GetX(), dirtyRegion.GetMin().GetY(), worldBounds.GetMin().GetZ(),
dirtyRegion.GetMax().GetX(), dirtyRegion.GetMax().GetY(), worldBounds.GetMax().GetZ());
// Calculate the world size of each sector. Note that this size actually ends at the last point, not the last square.
// So for example, the sector size for 3 points will go from (*--*--*) even though it will be used to draw (*--*--*--).
const float xSectorSize = (queryResolution.GetX() * SectorSizeInGridPoints);
@@ -230,7 +236,7 @@ namespace Terrain
// If we haven't cached anything before, or if the world bounds has changed, clear our cache structure and repopulate it
// with WireframeSector entries with the proper AABB sizes.
if (!m_wireframeBounds.IsValid() || !dirtyRegion.IsValid() || !m_wireframeBounds.IsClose(worldBounds))
if (!m_wireframeBounds.IsValid() || !dirtyRegion2D.IsValid() || !m_wireframeBounds.IsClose(worldBounds))
{
m_wireframeBounds = worldBounds;
@@ -266,7 +272,7 @@ namespace Terrain
// For each sector, if it overlaps with the dirty region, clear it out and recache the wireframe line data.
for (auto& sector : m_wireframeSectors)
{
if (dirtyRegion.IsValid() && !dirtyRegion.Overlaps(sector.m_aabb))
if (dirtyRegion2D.IsValid() && !dirtyRegion2D.Overlaps(sector.m_aabb))
{
continue;
}
@@ -46,6 +46,7 @@ namespace Terrain
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_4096Meters, "4 Kilometers")
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_8192Meters, "8 Kilometers")
->EnumAttribute(TerrainWorldRendererConfig::WorldSize::_16384Meters, "16 Kilometers")
->Attribute(AZ::Edit::Attributes::Visibility, false) // Keeping invisible until it's hooked up under the hood
;
}
}
@@ -417,10 +417,10 @@ namespace Terrain
m_areaData.m_rebuildSectors = false;
m_sectorData.clear();
const float xFirstPatchStart = terrainBounds.GetMin().GetX() - fmod(terrainBounds.GetMin().GetX(), GridMeters);
const float xLastPatchStart = terrainBounds.GetMax().GetX() - fmod(terrainBounds.GetMax().GetX(), GridMeters);
const float yFirstPatchStart = terrainBounds.GetMin().GetY() - fmod(terrainBounds.GetMin().GetY(), GridMeters);
const float yLastPatchStart = terrainBounds.GetMax().GetY() - fmod(terrainBounds.GetMax().GetY(), GridMeters);
const float xFirstPatchStart = AZStd::floorf(terrainBounds.GetMin().GetX() / GridMeters) * GridMeters;
const float xLastPatchStart = AZStd::floorf(terrainBounds.GetMax().GetX() / GridMeters) * GridMeters;
const float yFirstPatchStart = AZStd::floorf(terrainBounds.GetMin().GetY() / GridMeters) * GridMeters;
const float yLastPatchStart = AZStd::floorf(terrainBounds.GetMax().GetY() / GridMeters) * GridMeters;
const auto& materialAsset = m_materialInstance->GetAsset();
const auto& shaderAsset = materialAsset->GetMaterialTypeAsset()->GetShaderAssetForObjectSrg();
@@ -603,7 +603,7 @@ namespace Terrain
// For every distance doubling beyond a minDistanceForLod0, we only need half the mesh density. Each LOD
// is exactly half the resolution of the last.
const float lodForCamera = floorf(AZ::GetMax(0.0f, log2f(sectorDistance / minDistanceForLod0)));
const float lodForCamera = AZStd::floorf(AZ::GetMax(0.0f, log2f(sectorDistance / minDistanceForLod0)));
// All cameras should render the same LOD so effects like shadows are consistent.
lodChoice = AZ::GetMin(lodChoice, aznumeric_cast<uint8_t>(lodForCamera));
@@ -222,20 +222,31 @@ float TerrainSystem::GetHeightSynchronous(float x, float y, Sampler sampler, boo
float TerrainSystem::GetTerrainAreaHeight(float x, float y, bool& terrainExists) const
{
AZ::Vector3 inPosition((float)x, (float)y, m_currentSettings.m_worldBounds.GetMin().GetZ());
float height = m_currentSettings.m_worldBounds.GetMin().GetZ();
const float worldMin = m_currentSettings.m_worldBounds.GetMin().GetZ();
AZ::Vector3 inPosition(x, y, worldMin);
float height = worldMin;
terrainExists = false;
AZStd::shared_lock<AZStd::shared_mutex> lock(m_areaMutex);
for (auto& [areaId, areaBounds] : m_registeredAreas)
for (auto& [areaId, areaData] : m_registeredAreas)
{
inPosition.SetZ(areaBounds.GetMin().GetZ());
if (areaBounds.Contains(inPosition))
const float areaMin = areaData.m_areaBounds.GetMin().GetZ();
inPosition.SetZ(areaMin);
if (areaData.m_areaBounds.Contains(inPosition))
{
AZ::Vector3 outPosition;
Terrain::TerrainAreaHeightRequestBus::Event(
areaId, &Terrain::TerrainAreaHeightRequestBus::Events::GetHeight, inPosition, outPosition, terrainExists);
height = outPosition.GetZ();
if (!terrainExists)
{
// If the terrain height provider doesn't have any data, then check the area's "use ground plane" setting.
// If it's set, then create a default ground plane by saying terrain exists at the minimum height for the area.
// Otherwise, we'll set the height at the terrain world minimum and say it doesn't exist.
terrainExists = areaData.m_useGroundPlane;
height = areaData.m_useGroundPlane ? areaMin : worldMin;
}
break;
}
}
@@ -395,12 +406,12 @@ AZ::EntityId TerrainSystem::FindBestAreaEntityAtPosition(float x, float y, AZ::A
AZStd::shared_lock<AZStd::shared_mutex> lock(m_areaMutex);
// The areas are sorted into priority order: the first area that contains inPosition is the most suitable.
for (const auto& [areaId, areaBounds] : m_registeredAreas)
for (const auto& [areaId, areaData] : m_registeredAreas)
{
inPosition.SetZ(areaBounds.GetMin().GetZ());
if (areaBounds.Contains(inPosition))
inPosition.SetZ(areaData.m_areaBounds.GetMin().GetZ());
if (areaData.m_areaBounds.Contains(inPosition))
{
bounds = areaBounds;
bounds = areaData.m_areaBounds;
return areaId;
}
}
@@ -548,7 +559,12 @@ void TerrainSystem::RegisterArea(AZ::EntityId areaId)
AZStd::unique_lock<AZStd::shared_mutex> lock(m_areaMutex);
AZ::Aabb aabb = AZ::Aabb::CreateNull();
LmbrCentral::ShapeComponentRequestsBus::EventResult(aabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
m_registeredAreas[areaId] = aabb;
// Cache off whether or not this layer spawner should have a default ground plane when no other terrain height data exists.
bool useGroundPlane = false;
Terrain::TerrainSpawnerRequestBus::EventResult(useGroundPlane, areaId, &Terrain::TerrainSpawnerRequestBus::Events::GetUseGroundPlane);
m_registeredAreas[areaId] = { aabb, useGroundPlane };
m_dirtyRegion.AddAabb(aabb);
m_terrainHeightDirty = true;
m_terrainSurfacesDirty = true;
@@ -565,10 +581,10 @@ void TerrainSystem::UnregisterArea(AZ::EntityId areaId)
m_registeredAreas,
[areaId, this](const auto& item)
{
auto const& [entityId, aabb] = item;
auto const& [entityId, areaData] = item;
if (areaId == entityId)
{
m_dirtyRegion.AddAabb(aabb);
m_dirtyRegion.AddAabb(areaData.m_areaBounds);
m_terrainHeightDirty = true;
m_terrainSurfacesDirty = true;
return true;
@@ -585,10 +601,10 @@ void TerrainSystem::RefreshArea(AZ::EntityId areaId, AzFramework::Terrain::Terra
auto areaAabb = m_registeredAreas.find(areaId);
AZ::Aabb oldAabb = (areaAabb != m_registeredAreas.end()) ? areaAabb->second : AZ::Aabb::CreateNull();
AZ::Aabb oldAabb = (areaAabb != m_registeredAreas.end()) ? areaAabb->second.m_areaBounds : AZ::Aabb::CreateNull();
AZ::Aabb newAabb = AZ::Aabb::CreateNull();
LmbrCentral::ShapeComponentRequestsBus::EventResult(newAabb, areaId, &LmbrCentral::ShapeComponentRequestsBus::Events::GetEncompassingAabb);
m_registeredAreas[areaId] = newAabb;
m_registeredAreas[areaId].m_areaBounds = newAabb;
AZ::Aabb expandedAabb = oldAabb;
expandedAabb.AddAabb(newAabb);
@@ -168,7 +168,14 @@ namespace Terrain
bool m_terrainSurfacesDirty = false;
AZ::Aabb m_dirtyRegion;
// Cached data for each terrain area to use when looking up terrain data.
struct TerrainAreaData
{
AZ::Aabb m_areaBounds{ AZ::Aabb::CreateNull() };
bool m_useGroundPlane{ false };
};
mutable AZStd::shared_mutex m_areaMutex;
AZStd::map<AZ::EntityId, AZ::Aabb, TerrainLayerPriorityComparator> m_registeredAreas;
AZStd::map<AZ::EntityId, TerrainAreaData, TerrainLayerPriorityComparator> m_registeredAreas;
};
} // namespace Terrain