/* * 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 #include #include #include #include #include #include #include #include #include #include #ifdef AZ_PROFILE_TELEMETRY #include #endif #include #include #include #include #include #include #include #include namespace AtomSampleViewer { namespace Utils { AZ::RHI::Ptr GetRHIDevice() { using namespace AZ; auto* rhiSystem = RHI::RHISystemInterface::Get(); AZ_Assert(rhiSystem, "Failed to retrieve rpi system."); return rhiSystem->GetDevice(); } bool AssetEntryNameGetter(void* data, int index, const char** outName) { const AssetEntry* assetEntries = reinterpret_cast(data); *outName = assetEntries[index].m_name.c_str(); return true; } void ToggleRadTMCapture() { #ifdef AZ_PROFILE_TELEMETRY using namespace RADTelemetry; using MaskType = AZ::Debug::ProfileCategoryPrimitiveType; // Set all the category bits "below" Detailed by default static const MaskType defaultCaptureMask = AZ_PROFILE_CAT_TO_RAD_CAPFLAGS(FirstDetailedCategory) - 1; static const char* s_telemetryAddress = "127.0.0.1"; static int32_t s_telemetryPort = 4719; static MaskType s_telemetryCaptureMask = defaultCaptureMask; static int32_t s_memCaptureEnabled = 0; ProfileTelemetryRequestBus::Broadcast(&ProfileTelemetryRequestBus::Events::SetAddress, s_telemetryAddress, s_telemetryPort); const MaskType fullCaptureMask = s_telemetryCaptureMask | (s_memCaptureEnabled ? AZ_PROFILE_CAT_TO_RAD_CAPFLAGS(MemoryReserved) : 0); ProfileTelemetryRequestBus::Broadcast(&ProfileTelemetryRequestBus::Events::SetCaptureMask, fullCaptureMask); ProfileTelemetryRequestBus::Broadcast(&ProfileTelemetryRequestBus::Events::ToggleEnabled); #endif // AZ_PROFILE_TELEMETRY } DefaultIBL::~DefaultIBL() { Reset(); } void DefaultIBL::PreloadAssets() { const constexpr char* DiffuseAssetPath = "textures/sampleenvironment/examplespecularhdr_cm_ibldiffuse.dds.streamingimage"; const constexpr char* SpecularAssetPath = "textures/sampleenvironment/examplespecularhdr_cm_iblspecular.dds.streamingimage"; auto assertTraceLevel = AZ::RPI::AssetUtils::TraceLevel::Assert; if (!m_diffuseImageAsset.IsReady()) { m_diffuseImageAsset = AZ::RPI::AssetUtils::GetAssetByProductPath(DiffuseAssetPath, assertTraceLevel); m_diffuseImageAsset.QueueLoad(); m_diffuseImageAsset.BlockUntilLoadComplete(); } if (!m_specularImageAsset.IsReady()) { m_specularImageAsset = AZ::RPI::AssetUtils::GetAssetByProductPath(SpecularAssetPath, assertTraceLevel); m_specularImageAsset.QueueLoad(); m_specularImageAsset.BlockUntilLoadComplete(); } } void DefaultIBL::Init(AZ::RPI::Scene* scene) { PreloadAssets(); m_featureProcessor = scene->GetFeatureProcessor(); AZ_Assert(m_featureProcessor, "Unabled to find ImageBasedLightFeatureProcessorInterface on scene."); m_featureProcessor->SetDiffuseImage(m_diffuseImageAsset); m_featureProcessor->SetSpecularImage(m_specularImageAsset); } void DefaultIBL::SetExposure(float exposure) { m_featureProcessor->SetExposure(exposure); } void DefaultIBL::Reset() { if (m_featureProcessor) { m_featureProcessor->Reset(); m_featureProcessor = nullptr; } } void ResizeClientArea(uint32_t width, uint32_t height) { AzFramework::NativeWindowHandle windowHandle = nullptr; AzFramework::WindowSystemRequestBus::BroadcastResult( windowHandle, &AzFramework::WindowSystemRequestBus::Events::GetDefaultWindowHandle); AzFramework::WindowSize clientAreaSize = {width, height}; AzFramework::WindowRequestBus::Event(windowHandle, &AzFramework::WindowRequestBus::Events::ResizeClientArea, clientAreaSize); AzFramework::WindowSize newWindowSize; AzFramework::WindowRequestBus::EventResult(newWindowSize, windowHandle, &AzFramework::WindowRequests::GetClientAreaSize); AZ_Error("ResizeClientArea", newWindowSize.m_width == width && newWindowSize.m_height == height, "Requested window resize to %ux%u but got %ux%u. This display resolution is too low or desktop scaling is too high.", width, height, newWindowSize.m_width, newWindowSize.m_height); } bool SupportsToggleFullScreenOfDefaultWindow() { return AzFramework::NativeWindow::CanToggleFullScreenStateOfDefaultWindow(); } void ToggleFullScreenOfDefaultWindow() { AzFramework::NativeWindow::ToggleFullScreenStateOfDefaultWindow(); } void ReportScriptableAction(const char* formatStr, ...) { va_list args; va_start(args, formatStr); ScriptRepeaterRequestBus::Broadcast(&ScriptRepeaterRequests::ReportScriptableAction, AZStd::string::format_arg(formatStr, args)); va_end(args); } AZ::Data::Instance GetSolidColorCubemap(uint32_t color) { constexpr uint32_t width = 4; constexpr uint32_t height = 4; AZStd::string assetName = AZStd::string::format("SolidColorBackground_%u", color); AZ::Data::AssetId assetId = AZ::Uuid::CreateName(assetName.c_str()); // Check for existing image of the same color AZ::Data::Instance existingImage = AZ::Data::InstanceDatabase::Instance().Find(AZ::Data::InstanceId::CreateFromAssetId(assetId)); if (existingImage) { return existingImage; } // Build a new cubemap. AZ::RHI::Size imageSize = AZ::RHI::Size(width, height, 1); const uint32_t pixelSize = sizeof(uint32_t); const uint32_t pixelDataSize = width * height * pixelSize; AZStd::array pixels; for (uint32_t& pixelColor : pixels) { pixelColor = color; } // Create a new streaming image AZ::RPI::StreamingImageAssetCreator imageCreator; imageCreator.Begin(assetId); int32_t arraySize = 6; AZ::RHI::Format format = AZ::RHI::Format::R8G8B8A8_UNORM_SRGB; AZ::RHI::ImageBindFlags bindFlag = AZ::RHI::ImageBindFlags::ShaderRead; AZ::RHI::ImageDescriptor imageDesc = AZ::RHI::ImageDescriptor::Create2DArray(bindFlag, width, height, static_cast(arraySize), format); imageDesc.m_mipLevels = 1; imageDesc.m_isCubemap = true; imageCreator.SetImageDescriptor(imageDesc); imageCreator.SetImageViewDescriptor(AZ::RHI::ImageViewDescriptor::CreateCubemap()); // Create the mip chain AZ::RPI::ImageMipChainAssetCreator mipChainCreator; assetId.m_subId = 1; mipChainCreator.Begin(assetId, 1, 6); uint32_t pitch = width * pixelSize; AZ::RHI::ImageSubresourceLayout layout; layout.m_bytesPerImage = pixelDataSize; layout.m_rowCount = layout.m_bytesPerImage / pitch; layout.m_size = AZ::RHI::Size(width, height, 1); layout.m_bytesPerRow = pitch; mipChainCreator.BeginMip(layout); for (uint32_t i = 0; i < 6; ++i) { mipChainCreator.AddSubImage(pixels.data(), pixelDataSize); } mipChainCreator.EndMip(); AZ::Data::Asset mipChainAsset; mipChainCreator.End(mipChainAsset); imageCreator.AddMipChainAsset(*mipChainAsset); // Finalize streaming image asset AZ::Data::Asset imageAsset; imageCreator.End(imageAsset); return AZ::RPI::StreamingImage::FindOrCreate(imageAsset); } AZStd::string ResolvePath(const AZStd::string& path) { char resolvedPath[AZ_MAX_PATH_LEN] = {0}; AZ::IO::FileIOBase::GetInstance()->ResolvePath(path.c_str(), resolvedPath, AZ_MAX_PATH_LEN); return resolvedPath; } bool IsFileUnderFolder(AZStd::string filePath, AZStd::string folder) { AzFramework::StringFunc::Path::Normalize(filePath); AzFramework::StringFunc::Path::Normalize(folder); AZStd::to_lower(filePath.begin(), filePath.end()); AZStd::to_lower(folder.begin(), folder.end()); auto relativePath = AZ::IO::FixedMaxPath(filePath.c_str()).LexicallyRelative(folder.c_str()); if (!relativePath.empty() && !relativePath.Native().starts_with("..")) { return true; } return false; } } // namespace Utils } // namespace AtomSampleViewer