From 3332ad1248cbff5841498c487edb4808f0ce08a3 Mon Sep 17 00:00:00 2001 From: Alexey Date: Mon, 23 Dec 2024 10:23:22 +0300 Subject: [PATCH] [CKPE] - Com multithread patch; - DX11 added fMipLODBias option for mipmaps; SSE: - Remove lock render frame; - Fixed 1.5.73 novysc patch; SF: - Added archive patch, load .ba2's with plugins (limit .ba2's 0xfc); --- .../Core/D3D11Proxy.cpp | 15 +- .../Core/D3D11Proxy.h | 2 + .../Core/Engine.cpp | 2 + .../Core/EngineSFPatches.cpp | 4 +- ...reation Kit Platform Extended Core.vcxproj | 6 +- ...Kit Platform Extended Core.vcxproj.filters | 21 +- .../Editor API/SF/BSResourceArchive2SF.cpp | 41 +- .../Editor API/SF/BSResourceArchive2SF.h | 23 +- .../Patches/ComPatch.cpp | 84 ++ .../Patches/ComPatch.h | 41 + .../Patches/D3D11Patch.cpp | 2 +- .../Patches/RenderWindow60FPS.cpp | 9 +- .../Patches/SF/BSArchiveManagerModdedSF.cpp | 70 +- .../Patches/SF/BSArchiveManagerModdedSF.h | 4 +- .../SF/RemoveUselessResizeInDialogs.cpp | 74 - .../Patches/SF/RemoveUselessResizeInDialogs.h | 41 - .../Patches/Windows/SSE/RenderWindow.cpp | 11 +- .../Version/build_version.txt | Bin 12 -> 12 bytes .../Version/resource_version2.h | Bin 2004 -> 2004 bytes Database/FO4/1_10_162_0/Com.relb | 4 + ...nKitPlatformExtended_FO4_1_10_162.database | Bin 41516 -> 41573 bytes Database/FO4/1_10_982_3/Com.relb | 4 + ...itPlatformExtended_FO4_1_10_982_3.database | Bin 26015 -> 26072 bytes .../SF/1_14_74_0/BSArchiveManagerModded.relb | 17 +- Database/SF/1_14_74_0/Com.relb | 4 + ...nKitPlatformExtended_SF_1_14_74_0.database | Bin 17161 -> 17367 bytes Database/SSE/1_5_73/Com.relb | 4 + ...ionKitPlatformExtended_SSE_1_5_73.database | Bin 9923 -> 9992 bytes Database/SSE/1_5_73/RenderWindow60FPS.relb | 8 +- Database/SSE/1_6_1130/Com.relb | 4 + ...nKitPlatformExtended_SSE_1_6_1130.database | Bin 10207 -> 10276 bytes Database/SSE/1_6_1130/RenderWindow60FPS.relb | 6 +- Database/SSE/1_6_1378_1/Com.relb | 4 + ...itPlatformExtended_SSE_1_6_1378_1.database | Bin 47685 -> 47766 bytes .../SSE/1_6_1378_1/RenderWindow60FPS.relb | 6 +- .../DirectXTex/include/ScreenGrab11.h | 46 + Dependencies/DirectXTex/src/ScreenGrab11.cpp | 1261 +++++++++++++++++ Stuffs/FO4/CreationKitPlatformExtended.ini | 3 + Stuffs/SSE/CreationKitPlatformExtended.ini | 3 + 39 files changed, 1583 insertions(+), 241 deletions(-) create mode 100644 Creation Kit Platform Extended Core/Patches/ComPatch.cpp create mode 100644 Creation Kit Platform Extended Core/Patches/ComPatch.h delete mode 100644 Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.cpp delete mode 100644 Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.h create mode 100644 Database/FO4/1_10_162_0/Com.relb create mode 100644 Database/FO4/1_10_982_3/Com.relb create mode 100644 Database/SF/1_14_74_0/Com.relb create mode 100644 Database/SSE/1_5_73/Com.relb create mode 100644 Database/SSE/1_6_1130/Com.relb create mode 100644 Database/SSE/1_6_1378_1/Com.relb create mode 100644 Dependencies/DirectXTex/include/ScreenGrab11.h create mode 100644 Dependencies/DirectXTex/src/ScreenGrab11.cpp diff --git a/Creation Kit Platform Extended Core/Core/D3D11Proxy.cpp b/Creation Kit Platform Extended Core/Core/D3D11Proxy.cpp index 5ffdfe23..c97637af 100644 --- a/Creation Kit Platform Extended Core/Core/D3D11Proxy.cpp +++ b/Creation Kit Platform Extended Core/Core/D3D11Proxy.cpp @@ -15,6 +15,8 @@ namespace CreationKitPlatformExtended m_Device->GetImmediateContext2(&temp); m_ContextProxy = new D3D11DeviceContextProxy(temp); + m_MipLODBias = std::min(3.f, std::max(-3.f, + _READ_OPTION_FLOAT("Graphics", "fMipLODBias", 0.f))); } D3D11DeviceProxy::D3D11DeviceProxy(ID3D11Device2 *Device) @@ -25,6 +27,8 @@ namespace CreationKitPlatformExtended m_Device->GetImmediateContext2(&temp); m_ContextProxy = new D3D11DeviceContextProxy(temp); + m_MipLODBias = std::min(3.f, std::max(-3.f, + _READ_OPTION_FLOAT("Graphics", "fMipLODBias", 0.f))); } HRESULT STDMETHODCALLTYPE D3D11DeviceProxy::QueryInterface(REFIID riid, void **ppvObj) @@ -165,6 +169,15 @@ namespace CreationKitPlatformExtended HRESULT STDMETHODCALLTYPE D3D11DeviceProxy::CreateRasterizerState(const D3D11_RASTERIZER_DESC *pRasterizerDesc, ID3D11RasterizerState **ppRasterizerState) { + if (pRasterizerDesc) + { + auto RasterizerDesc = const_cast(pRasterizerDesc); + RasterizerDesc->AntialiasedLineEnable = true; + RasterizerDesc->MultisampleEnable = true; + + return m_Device->CreateRasterizerState(RasterizerDesc, ppRasterizerState); + } + return m_Device->CreateRasterizerState(pRasterizerDesc, ppRasterizerState); } @@ -174,7 +187,7 @@ namespace CreationKitPlatformExtended { auto SamplerDesc = const_cast(pSamplerDesc); - SamplerDesc->MipLODBias = 0.0f; // mipmap level bias value + SamplerDesc->MipLODBias = m_MipLODBias; // mipmap level bias value SamplerDesc->MinLOD = 0.0f; // alternative minimum mipmap level SamplerDesc->MaxLOD = D3D11_FLOAT32_MAX; // alternative maximum mipmap level } diff --git a/Creation Kit Platform Extended Core/Core/D3D11Proxy.h b/Creation Kit Platform Extended Core/Core/D3D11Proxy.h index 6fd7223c..ceebfbc9 100644 --- a/Creation Kit Platform Extended Core/Core/D3D11Proxy.h +++ b/Creation Kit Platform Extended Core/Core/D3D11Proxy.h @@ -12,6 +12,8 @@ namespace CreationKitPlatformExtended ID3D11Device2* m_Device; D3D11DeviceContextProxy* m_ContextProxy; + float m_MipLODBias; + D3D11DeviceProxy(ID3D11Device* Device); D3D11DeviceProxy(ID3D11Device2* Device); diff --git a/Creation Kit Platform Extended Core/Core/Engine.cpp b/Creation Kit Platform Extended Core/Core/Engine.cpp index 010de730..9e3037a4 100644 --- a/Creation Kit Platform Extended Core/Core/Engine.cpp +++ b/Creation Kit Platform Extended Core/Core/Engine.cpp @@ -41,6 +41,7 @@ #include "Patches/PapyrusEditorLimit.h" #include "Patches/UIHotkeys.h" #include "Patches/D3D11Patch.h" +#include "Patches/ComPatch.h" #include "Experimental/RuntimeOptimization.h" @@ -211,6 +212,7 @@ namespace CreationKitPlatformExtended new CreationKitPlatformExtended::Patches::UIThemePatchAdditional(), new CreationKitPlatformExtended::Patches::PapyrusEditorLimitPatch(), new CreationKitPlatformExtended::Patches::D3D11Patch(), + new CreationKitPlatformExtended::Patches::ComPatch(), _Theme, _ClassicTheme, INICacheData, diff --git a/Creation Kit Platform Extended Core/Core/EngineSFPatches.cpp b/Creation Kit Platform Extended Core/Core/EngineSFPatches.cpp index 93722191..17efaf0a 100644 --- a/Creation Kit Platform Extended Core/Core/EngineSFPatches.cpp +++ b/Creation Kit Platform Extended Core/Core/EngineSFPatches.cpp @@ -14,12 +14,12 @@ #include "Patches/SF/RTDynamicCastCrash.h" #include "Patches/SF/OptimizationLoadSF.h" #include "Patches/SF/RemoveUselessMessagesSF.h" -#include "Patches/SF/RemoveUselessResizeInDialogs.h" #include "Patches/SF/RemoveThreadDpi.h" #include "Patches/SF/LoadMaterialsQSplash.h" #include "Patches/SF/FixQuoteCmdLineSF.h" #include "Patches/SF/AllowSaveESMandMasterESPSF.h" #include "Patches/SF/BSResourceLooseFilesPatchSF.h" +#include "Patches/SF/BSArchiveManagerModdedSF.h" #include "Patches/Windows/SF/DataWindowSF.h" #include "Patches/Windows/SF/AboutWindowSF.h" @@ -48,12 +48,12 @@ namespace CreationKitPlatformExtended new Patches::RTDynamicCastCrashPatch(), new Patches::OptimizationLoadPatch(), new Patches::RemoveUselessMessagesPatch(), - //new Patches::RemoveUselessResizeInDialogsPatch(), new Patches::RemoveThreadDpiPatch(), new Patches::LoadMaterialsQSplashPatch(), new Patches::FixQuoteCmdLinePatch(), new Patches::AllowSaveESMandMasterESPPatch(), new Patches::BSResourceLooseFilesPatch(), + new Patches::BSArchiveManagerModdedPatch(), new Patches::DataWindow(), new Patches::AboutWindow(), diff --git a/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj b/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj index eff2b7ee..37103d92 100644 --- a/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj +++ b/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj @@ -130,6 +130,7 @@ + @@ -202,6 +203,7 @@ + @@ -270,7 +272,6 @@ - @@ -437,6 +438,7 @@ + @@ -608,6 +610,7 @@ + @@ -676,7 +679,6 @@ - diff --git a/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj.filters b/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj.filters index bb0cd93c..2f19a920 100644 --- a/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj.filters +++ b/Creation Kit Platform Extended Core/Creation Kit Platform Extended Core.vcxproj.filters @@ -865,9 +865,6 @@ Patches\FO4 - - Patches\SF - Patches\SF @@ -904,6 +901,12 @@ Patches\FO4 + + Patches + + + Dependecies\DirectXTexUtils + @@ -990,6 +993,9 @@ {8c0ce81a-d9eb-4a96-ac96-1e14a1e870cb} + + {af8e5418-ce4f-476e-819d-01125a452f54} + @@ -2161,9 +2167,6 @@ Patches\FO4 - - Patches\SF - Patches\SF @@ -2200,6 +2203,12 @@ Patches\FO4 + + Patches + + + Dependecies\DirectXTexUtils + diff --git a/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.cpp b/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.cpp index 93f80423..36208b66 100644 --- a/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.cpp +++ b/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.cpp @@ -13,11 +13,8 @@ namespace CreationKitPlatformExtended { using namespace CreationKitPlatformExtended::Core; - BGSFileSelectorDialog::RegisterArchiveFileCallback* lpArchiveFileCallback = nullptr; - namespace BSResource { - LocationTree* lpArchiveTree = nullptr; uintptr_t pointer_Archive2_sub1 = 0; uintptr_t pointer_Archive2_sub2 = 0; Array g_arrayArchivesAvailable; @@ -101,41 +98,35 @@ namespace CreationKitPlatformExtended fileSizeStr.Format("%d Byte", fileSize); } - Archive2::EResultError Archive2::HKLoadArchive(void* arrayDataList, LooseFileStream*& resFile, - void* Unk1, uint32_t Unk2) + uint32_t Archive2::HKLoadArchive(const char* fileName, __int64 unknown01, + __int64 unknown02, __int64 unknown03, __int64 unknown04, __int64 unknown05, + __int64 unknown06, __int64 unknown07) { - auto fileName = resFile->FileName->Get(true); - AssertMsg(fileName, "There is no name of the load archive"); - - BSString filePath, fileSizeStr; - filePath.Format("%s%s%s", resFile->AppPath->Get(true), resFile->DataPath->Get(true), fileName); - AssertMsgVa(BSString::Utils::FileExists(filePath), "Can't found file %s", *filePath); - - uint64_t fileSize = 0; - WIN32_FILE_ATTRIBUTE_DATA fileData; - ZeroMemory(&fileData, sizeof(WIN32_FILE_ATTRIBUTE_DATA)); - if (GetFileAttributesExA(*filePath, GetFileExInfoStandard, &fileData)) - fileSize = (uint64_t)fileData.nFileSizeLow | ((uint64_t)fileData.nFileSizeHigh << 32); + if (!fileName) + return 0; - auto resultNo = EC_NONE; + AssertMsg(fileName, "There is no name of the load archive"); - if (_stricmp(fileName, "Fallout4 - Shaders.ba2")) // skip load Fallout4 - Shaders.ba2 + BSString filePath = BSString::Utils::GetDataPath() + fileName, fileSizeStr; + if (BSString::Utils::FileExists(filePath)) { + unsigned int fileSize = 0; + WIN32_FILE_ATTRIBUTE_DATA fileData; + if (GetFileAttributesExA(*filePath, GetFileExInfoStandard, &fileData)) + fileSize = (uint64_t)fileData.nFileSizeLow | ((uint64_t)fileData.nFileSizeHigh << 32); + GetFileSizeStr(fileSize, fileSizeStr); _CONSOLE("Load an archive file \"%s\" (%s)...", fileName, *fileSizeStr); - - resultNo = fastCall - (pointer_Archive2_sub1, arrayDataList, resFile, Unk1, Unk2); - AssertMsgVa(resultNo == EC_NONE, "Failed load an archive file %s", fileName); } - return resultNo; + return fastCall(pointer_Archive2_sub1, fileName, unknown01, + unknown02, unknown03, unknown04, unknown05, unknown06, unknown07); } void Archive2::LoadArchive(const char* fileName) { if (BSString::Utils::FileExists(BSString::Utils::GetDataPath() + fileName)) - fastCall(pointer_Archive2_sub2, fileName, &lpArchiveTree, &lpArchiveFileCallback); + fastCall(pointer_Archive2_sub2, fileName, 0, 0); } bool Archive2::IsAvailableForLoad(const char* fileName) diff --git a/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.h b/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.h index 629236d8..98db8cc0 100644 --- a/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.h +++ b/Creation Kit Platform Extended Core/Editor API/SF/BSResourceArchive2SF.h @@ -15,33 +15,16 @@ namespace CreationKitPlatformExtended { namespace Starfield { - class BGSFileSelectorDialog - { - public: - class RegisterArchiveFileCallback - {}; - }; - - extern BGSFileSelectorDialog::RegisterArchiveFileCallback* lpArchiveFileCallback; - namespace BSResource { - class LocationTree - {}; - - extern LocationTree* lpArchiveTree; - class Archive2 { - public: - enum EResultError : uint32_t - { - EC_NONE = 0, - }; public: static void Initialize(); static void GetFileSizeStr(uint64_t fileSize, BSString& fileSizeStr); - static EResultError HKLoadArchive(void* arrayDataList, LooseFileStream*& resFile, void* Unk1, uint32_t Unk2); + static uint32_t HKLoadArchive(const char* fileName, __int64 unknown01, + __int64 unknown02, __int64 unknown03, __int64 unknown04, __int64 unknown05, + __int64 unknown06, __int64 unknown07); static void LoadArchive(const char* fileName); static bool IsAvailableForLoad(const char* fileName); }; diff --git a/Creation Kit Platform Extended Core/Patches/ComPatch.cpp b/Creation Kit Platform Extended Core/Patches/ComPatch.cpp new file mode 100644 index 00000000..9788343e --- /dev/null +++ b/Creation Kit Platform Extended Core/Patches/ComPatch.cpp @@ -0,0 +1,84 @@ +// Copyright © 2023-2024 aka perchik71. All rights reserved. +// Contacts: +// License: https://www.gnu.org/licenses/gpl-3.0.html + +#include "Core/Engine.h" +#include "Editor API/EditorUI.h" +#include "ComPatch.h" + +namespace CreationKitPlatformExtended +{ + namespace Patches + { + using namespace CreationKitPlatformExtended::EditorAPI; + + ComPatch::ComPatch() : Module(GlobalEnginePtr) + {} + + bool ComPatch::HasOption() const + { + return false; + } + + bool ComPatch::HasCanRuntimeDisabled() const + { + return false; + } + + const char* ComPatch::GetOptionName() const + { + return nullptr; + } + + const char* ComPatch::GetName() const + { + return "COM"; + } + + bool ComPatch::HasDependencies() const + { + return false; + } + + Array ComPatch::GetDependencies() const + { + return {}; + } + + bool ComPatch::QueryFromPlatform(EDITOR_EXECUTABLE_TYPE eEditorCurrentVersion, + const char* lpcstrPlatformRuntimeVersion) const + { + return true; + } + + bool ComPatch::Activate(const Relocator* lpRelocator, + const RelocationDatabaseItem* lpRelocationDatabaseItem) + { + if (lpRelocationDatabaseItem->Version() == 1) + { + PatchIAT(HKCoInitializeEx, "COMBASE.DLL", "CoInitializeEx"); + PatchIAT(HKCoInitialize, "OLE32.DLL", "CoInitialize"); + + return true; + } + + return false; + } + + bool ComPatch::Shutdown(const Relocator* lpRelocator, + const RelocationDatabaseItem* lpRelocationDatabaseItem) + { + return false; + } + + HRESULT ComPatch::HKCoInitialize(LPVOID pvReserved) + { + return CoInitializeEx(pvReserved, COINITBASE_MULTITHREADED); + } + + HRESULT ComPatch::HKCoInitializeEx(LPVOID pvReserved, DWORD dwCoInit) + { + return CoInitializeEx(pvReserved, COINITBASE_MULTITHREADED); + } + } +} \ No newline at end of file diff --git a/Creation Kit Platform Extended Core/Patches/ComPatch.h b/Creation Kit Platform Extended Core/Patches/ComPatch.h new file mode 100644 index 00000000..a2fc079c --- /dev/null +++ b/Creation Kit Platform Extended Core/Patches/ComPatch.h @@ -0,0 +1,41 @@ +// Copyright © 2023-2024 aka perchik71. All rights reserved. +// Contacts: +// License: https://www.gnu.org/licenses/gpl-3.0.html + +#pragma once + +#include "Core/Module.h" +#include "Core/Relocator.h" +#include "Core/RelocationDatabase.h" + +namespace CreationKitPlatformExtended +{ + namespace Patches + { + using namespace CreationKitPlatformExtended::Core; + + class ComPatch : public Module + { + public: + ComPatch(); + + virtual bool HasOption() const; + virtual bool HasCanRuntimeDisabled() const; + virtual const char* GetOptionName() const; + virtual const char* GetName() const; + virtual bool HasDependencies() const; + virtual Array GetDependencies() const; + + static HRESULT HKCoInitialize(LPVOID pvReserved); + static HRESULT HKCoInitializeEx(LPVOID pvReserved, DWORD dwCoInit); + protected: + virtual bool QueryFromPlatform(EDITOR_EXECUTABLE_TYPE eEditorCurrentVersion, + const char* lpcstrPlatformRuntimeVersion) const; + virtual bool Activate(const Relocator* lpRelocator, const RelocationDatabaseItem* lpRelocationDatabaseItem); + virtual bool Shutdown(const Relocator* lpRelocator, const RelocationDatabaseItem* lpRelocationDatabaseItem); + private: + ComPatch(const ComPatch&) = default; + ComPatch& operator=(const ComPatch&) = default; + }; + } +} \ No newline at end of file diff --git a/Creation Kit Platform Extended Core/Patches/D3D11Patch.cpp b/Creation Kit Platform Extended Core/Patches/D3D11Patch.cpp index e6b9e036..c6dd41cd 100644 --- a/Creation Kit Platform Extended Core/Patches/D3D11Patch.cpp +++ b/Creation Kit Platform Extended Core/Patches/D3D11Patch.cpp @@ -148,7 +148,7 @@ namespace CreationKitPlatformExtended SwapChainDesc->BufferDesc.RefreshRate.Numerator = 60; SwapChainDesc->BufferDesc.RefreshRate.Denominator = (UINT)_READ_OPTION_BOOL("CreationKit", "bRenderWindowVSync", true); - + // // From MSDN: // diff --git a/Creation Kit Platform Extended Core/Patches/RenderWindow60FPS.cpp b/Creation Kit Platform Extended Core/Patches/RenderWindow60FPS.cpp index ce3fadc9..4fd58f61 100644 --- a/Creation Kit Platform Extended Core/Patches/RenderWindow60FPS.cpp +++ b/Creation Kit Platform Extended Core/Patches/RenderWindow60FPS.cpp @@ -53,7 +53,7 @@ namespace CreationKitPlatformExtended const RelocationDatabaseItem* lpRelocationDatabaseItem) { auto verPatch = lpRelocationDatabaseItem->Version(); - if (verPatch == 2) + if ((verPatch == 1) || (verPatch == 2)) { // // Force render window to draw at 60fps (SetTimer(10ms)) @@ -65,6 +65,13 @@ namespace CreationKitPlatformExtended // no VSync lpRelocator->Patch(_RELDATA_RAV(1), { 0x33, 0xD2, 0x90 }); + if (verPatch == 1) + { + // Remove lock framerate + lpRelocator->Patch(_RELDATA_RAV(2), { 0xEB }); + lpRelocator->Patch(_RELDATA_RAV(3), { 0xEB }); + } + return true; } diff --git a/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.cpp b/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.cpp index 9f9efcd0..6f445478 100644 --- a/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.cpp +++ b/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.cpp @@ -28,9 +28,8 @@ namespace CreationKitPlatformExtended { bool IsLoaded; Array g_SelectedFilesArray; + uintptr_t pointer_BSArchiveManagerModded_sub = 0; - // - //uintptr_t pointer_BSArchiveManagerModded_sub = 0; // //uint8_t supportedBA2Version = 8; @@ -84,42 +83,26 @@ namespace CreationKitPlatformExtended if (verPatch == 1) { - lpArchiveFileCallback = (BGSFileSelectorDialog::RegisterArchiveFileCallback*)_RELDATA_ADDR(0); - BSResource::lpArchiveTree = (BSResource::LocationTree*)_RELDATA_ADDR(1); - EditorAPI::Starfield::BSResource::pointer_Archive2_sub2 = _RELDATA_ADDR(2); - - //EditorAPI::Fallout4::BSResource::pointer_Archive2_sub1 = _RELDATA_ADDR(6); - // - //EditorAPI::Fallout4::BSResource::Archive2::Initialize(); - - //if (verPatch == 1) - // // Первая версия патча для 1.10.162.0 - // lpRelocator->DetourCall(_RELDATA_RAV(1), - // (uintptr_t)&EditorAPI::Fallout4::BSResource::Archive2::HKLoadArchive); - //else - // lpRelocator->DetourCall(_RELDATA_RAV(1), - // (uintptr_t)&EditorAPI::Fallout4::BSResource::Archive2::HKLoadArchiveEx); - - //lpRelocator->DetourCall(_RELDATA_RAV(2), (uintptr_t)&LoadTesFile); - //lpRelocator->DetourJump(_RELDATA_RAV(3), (uintptr_t)&LoadTesFileFinal); - - //pointer_BSArchiveManagerModded_sub = _RELDATA_ADDR(4); - - //ScopeRelocator text; - - //// Пропуск загрузки архивов, что не имеют отношения к загружаемому моду, но является предыдущей работой - //lpRelocator->Patch(_RELDATA_RAV(5), { 0xC3 }); - - //// Исключение из списков архив шейдеров - //lpRelocator->PatchStringRef(_RELDATA_RAV(8), szArchiveList); - //lpRelocator->PatchStringRef(_RELDATA_RAV(9), szArchiveList2); - - //// Так как разница между первой и 8 версией лишь, то что был удалён GNF формат для PlayStation. - //// То очевидно, 8 версии с GNF форматом просто не будет, то вполне безопасно, открывать любые версии архивы. - //if (verPatch == 1) - // // Первая версия патча для 1.10.162.0 - // lpRelocator->Patch(_RELDATA_RAV(7), &supportedBA2Version, 1); - + EditorAPI::Starfield::BSResource::pointer_Archive2_sub2 = _RELDATA_ADDR(0); + EditorAPI::Starfield::BSResource::Archive2::Initialize(); + + // Удаление пролога (ловушка занимает 5 байт и повредит прыжок) + lpRelocator->PatchNop(_RELDATA_RAV(1), 9); + // Ловушка на загрузку архивов + EditorAPI::Starfield::BSResource::pointer_Archive2_sub1 = + lpRelocator->DetourFunctionClass(_RELDATA_RAV(1), + (uintptr_t)&EditorAPI::Starfield::BSResource::Archive2::HKLoadArchive); + + lpRelocator->DetourCall(_RELDATA_RAV(2), (uintptr_t)&LoadTesFile); + lpRelocator->DetourCall(_RELDATA_RAV(3), (uintptr_t)&LoadTesFileFinal); + pointer_BSArchiveManagerModded_sub = _RELDATA_ADDR(4); + + // Пропуск загрузки архивов, что не имеют отношения к загружаемому моду, но является предыдущей работой + // Так же используется для загрузки архивов самим СК, так что душим это. + lpRelocator->Patch(_RELDATA_RAV(5), { 0xC3 }); + // Вырезать EditorDataFilesLoaded.txt + lpRelocator->Patch(_RELDATA_RAV(6), { 0xEB }); + return true; } @@ -139,14 +122,14 @@ namespace CreationKitPlatformExtended void BSArchiveManagerModdedPatch::AttachBA2File(LPCSTR _filename) { - /*if (EditorAPI::Fallout4::BSResource::Archive2::IsAvailableForLoad(_filename)) + if (EditorAPI::Starfield::BSResource::Archive2::IsAvailableForLoad(_filename)) goto attach_ba2; return; attach_ba2: - EditorAPI::Fallout4::BSResource::Archive2::LoadArchive(_filename);*/ + EditorAPI::Starfield::BSResource::Archive2::LoadArchive(_filename); } - void BSArchiveManagerModdedPatch::LoadTesFile(const TESFile* load_file) + void BSArchiveManagerModdedPatch::LoadTesFile(const TESFile* load_file, __int8 unknown) { IsLoaded = false; // Sometimes duplicated @@ -169,12 +152,11 @@ namespace CreationKitPlatformExtended AttachBA2File(*(sname + " - Main.ba2")); AttachBA2File(*(sname + " - Textures.ba2")); - //((void(__fastcall*)(const TESFile*))pointer_BSArchiveManagerModded_sub)(load_file); + fastCall(pointer_BSArchiveManagerModded_sub, load_file, unknown); } - void BSArchiveManagerModdedPatch::LoadTesFileFinal(HWND hWnd, UINT uMsg, LPARAM lParam, WPARAM wParam) + void BSArchiveManagerModdedPatch::LoadTesFileFinal() { - //EditorUI::HKSendMessageA(hWnd, uMsg, lParam, wParam); g_SelectedFilesArray.clear(); IsLoaded = true; } diff --git a/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.h b/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.h index 94e231d8..5d8f1a2d 100644 --- a/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.h +++ b/Creation Kit Platform Extended Core/Patches/SF/BSArchiveManagerModdedSF.h @@ -32,8 +32,8 @@ namespace CreationKitPlatformExtended virtual Array GetDependencies() const; static void AttachBA2File(LPCSTR _filename); - static void LoadTesFile(const TESFile* load_file); - static void LoadTesFileFinal(HWND hWnd, UINT uMsg, LPARAM lParam, WPARAM wParam); + static void LoadTesFile(const TESFile* load_file, __int8 unknown); + static void LoadTesFileFinal(); static bool HasLoaded(); protected: virtual bool QueryFromPlatform(EDITOR_EXECUTABLE_TYPE eEditorCurrentVersion, diff --git a/Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.cpp b/Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.cpp deleted file mode 100644 index b61bbb12..00000000 --- a/Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright © 2023-2024 aka perchik71. All rights reserved. -// Contacts: -// License: https://www.gnu.org/licenses/gpl-3.0.html - -#include "Core/Engine.h" -#include "RemoveUselessResizeInDialogs.h" - -namespace CreationKitPlatformExtended -{ - namespace Patches - { - namespace Starfield - { - RemoveUselessResizeInDialogsPatch::RemoveUselessResizeInDialogsPatch() : Module(GlobalEnginePtr) - {} - - bool RemoveUselessResizeInDialogsPatch::HasOption() const - { - return false; - } - - bool RemoveUselessResizeInDialogsPatch::HasCanRuntimeDisabled() const - { - return false; - } - - const char* RemoveUselessResizeInDialogsPatch::GetOptionName() const - { - return nullptr; - } - - const char* RemoveUselessResizeInDialogsPatch::GetName() const - { - return "Remove Useless Resize In Dialogs"; - } - - bool RemoveUselessResizeInDialogsPatch::HasDependencies() const - { - return false; - } - - Array RemoveUselessResizeInDialogsPatch::GetDependencies() const - { - return {}; - } - - bool RemoveUselessResizeInDialogsPatch::QueryFromPlatform(EDITOR_EXECUTABLE_TYPE eEditorCurrentVersion, - const char* lpcstrPlatformRuntimeVersion) const - { - return eEditorCurrentVersion >= EDITOR_EXECUTABLE_TYPE::EDITOR_STARFIELD_1_14_70_0; - } - - bool RemoveUselessResizeInDialogsPatch::Activate(const Relocator* lpRelocator, - const RelocationDatabaseItem* lpRelocationDatabaseItem) - { - if (lpRelocationDatabaseItem->Version() == 1) - { - for (uint32_t i = 0; i < lpRelocationDatabaseItem->Count(); i++) - lpRelocator->PatchNop(_RELDATA_RAV(i), 6); - - return true; - } - - return false; - } - - bool RemoveUselessResizeInDialogsPatch::Shutdown(const Relocator* lpRelocator, - const RelocationDatabaseItem* lpRelocationDatabaseItem) - { - return false; - } - } - } -} \ No newline at end of file diff --git a/Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.h b/Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.h deleted file mode 100644 index bd7fb65e..00000000 --- a/Creation Kit Platform Extended Core/Patches/SF/RemoveUselessResizeInDialogs.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright © 2023-2024 aka perchik71. All rights reserved. -// Contacts: -// License: https://www.gnu.org/licenses/gpl-3.0.html - -#pragma once - -#include "Core/Module.h" -#include "Core/Relocator.h" -#include "Core/RelocationDatabase.h" - -namespace CreationKitPlatformExtended -{ - namespace Patches - { - namespace Starfield - { - using namespace CreationKitPlatformExtended::Core; - - class RemoveUselessResizeInDialogsPatch : public Module - { - public: - RemoveUselessResizeInDialogsPatch(); - - virtual bool HasOption() const; - virtual bool HasCanRuntimeDisabled() const; - virtual const char* GetOptionName() const; - virtual const char* GetName() const; - virtual bool HasDependencies() const; - virtual Array GetDependencies() const; - protected: - virtual bool QueryFromPlatform(EDITOR_EXECUTABLE_TYPE eEditorCurrentVersion, - const char* lpcstrPlatformRuntimeVersion) const; - virtual bool Activate(const Relocator* lpRelocator, const RelocationDatabaseItem* lpRelocationDatabaseItem); - virtual bool Shutdown(const Relocator* lpRelocator, const RelocationDatabaseItem* lpRelocationDatabaseItem); - private: - RemoveUselessResizeInDialogsPatch(const RemoveUselessResizeInDialogsPatch&) = default; - RemoveUselessResizeInDialogsPatch& operator=(const RemoveUselessResizeInDialogsPatch&) = default; - }; - } - } -} \ No newline at end of file diff --git a/Creation Kit Platform Extended Core/Patches/Windows/SSE/RenderWindow.cpp b/Creation Kit Platform Extended Core/Patches/Windows/SSE/RenderWindow.cpp index e56cc175..b49a0fef 100644 --- a/Creation Kit Platform Extended Core/Patches/Windows/SSE/RenderWindow.cpp +++ b/Creation Kit Platform Extended Core/Patches/Windows/SSE/RenderWindow.cpp @@ -7,6 +7,7 @@ #include "RenderWindow.h" #include "MainWindow.h" #include "Editor API/SSE/BGSRenderWindow.h" +#include "Patches/D3D11Patch.h" namespace CreationKitPlatformExtended { @@ -38,12 +39,12 @@ namespace CreationKitPlatformExtended bool RenderWindow::HasDependencies() const { - return false; + return true; } Array RenderWindow::GetDependencies() const { - return {}; + return { "D3D11 Patch" }; } bool RenderWindow::QueryFromPlatform(EDITOR_EXECUTABLE_TYPE eEditorCurrentVersion, @@ -89,9 +90,11 @@ namespace CreationKitPlatformExtended GlobalRegistratorWindowPtr->RegisterMajor(Hwnd, "RenderWindow"); GlobalRenderWindowPtr->m_hWnd = Hwnd; GlobalRenderWindowPtr->_BlockInputMessage = true; - return CallWindowProc(GlobalRenderWindowPtr->GetOldWndProc(), Hwnd, Message, wParam, lParam); + + return CallWindowProc(GlobalRenderWindowPtr->GetOldWndProc(), + Hwnd, Message, wParam, lParam); } - ////// Fix WHITE area (Eats my eyes at startup) (only 1.6.1130) + ////// Fix WHITE area (Eats my eyes at startup) (only 1.6.1130 or newer) else if (Message == WM_PAINT) { PAINTSTRUCT ps; diff --git a/Creation Kit Platform Extended Core/Version/build_version.txt b/Creation Kit Platform Extended Core/Version/build_version.txt index 12eb1596c32850d42f087c550a1ade6f44395f2c..4556a7f3df90e140f90fad05de1b8dd6f295eba8 100644 GIT binary patch literal 12 TcmezW&yvBE!H|KMfr|kE96AED literal 12 RcmezW&yv9e2zeQ}7yukZ0=57E diff --git a/Creation Kit Platform Extended Core/Version/resource_version2.h b/Creation Kit Platform Extended Core/Version/resource_version2.h index 9998e6f0ca4c94047b2768fb6453664e33033a44..9c5985d4020eedcc60a03b37dc1befd2c90000a6 100644 GIT binary patch delta 28 kcmcb@e}#X;17>zp1_K6O2Cm7B%+ix1Sfw`0uy;24e \ No newline at end of file diff --git a/Database/FO4/1_10_162_0/CreationKitPlatformExtended_FO4_1_10_162.database b/Database/FO4/1_10_162_0/CreationKitPlatformExtended_FO4_1_10_162.database index 89902697718377928a86af5eac181ae32f28e072..71d59171d8272426e1260d308f5a2591184a68ab 100644 GIT binary patch delta 54 zcmZ2;gz4!KrU?p+{u>p;1qCe`Ab=4_F*7*(`%YGD65#=fu`xKj>gQ)**jymEX956Q CTns4y delta 19 bcmaEQglWwYrU?p+ej63T1vhUL+%f?GQ?UpT diff --git a/Database/FO4/1_10_982_3/Com.relb b/Database/FO4/1_10_982_3/Com.relb new file mode 100644 index 00000000..e06d4a79 --- /dev/null +++ b/Database/FO4/1_10_982_3/Com.relb @@ -0,0 +1,4 @@ +COM +1 +extended +0 0 \ No newline at end of file diff --git a/Database/FO4/1_10_982_3/CreationKitPlatformExtended_FO4_1_10_982_3.database b/Database/FO4/1_10_982_3/CreationKitPlatformExtended_FO4_1_10_982_3.database index 91c5d11a446400d06b08cccede982f6f237e4900..d20dbdd38ed054ebb4b1906934f8af9f69850b58 100644 GIT binary patch delta 49 zcmbP#n(@YI#t90Hfg2Ttxdkj4Ab=4_F*7*(Pkyf}Iyo+sjb%bm5dUT^?$Rg#GII;> delta 19 bcmca{nsNSV#t90H0UH&Cxi{x>XGZ}5PTU6Z diff --git a/Database/SF/1_14_74_0/BSArchiveManagerModded.relb b/Database/SF/1_14_74_0/BSArchiveManagerModded.relb index 2a5b451c..e5f59f76 100644 --- a/Database/SF/1_14_74_0/BSArchiveManagerModded.relb +++ b/Database/SF/1_14_74_0/BSArchiveManagerModded.relb @@ -1,15 +1,10 @@ BSArchiveManager Modded 1 extended -86BD578 0 -923AFB8 0 +5F10C50 0 5F01BA0 0 -2432233 0 4C8D05????????418D57B2488D0D????????E8????????0FB78D5C01000085DB75??440FB7C94C8D4550488D542430488D4D20 -8537CC 64 E8????????85C074??4C8D4678B90E000000488D15????????E8????????488B -6A87C2 0 -851B50 72 4053554881EC88000000488BD9C744242067030000488D4C244041B0014C8D0D???????? -8405E0 64 48895C240855488DAC2480FDFFFF4881EC8003000033C04C8D4540488D956001 -243C400 64 48896C242056574155415641574883EC3033ED498BF14D8BF84C8BEA488BF944 -0 0 -3ADD2C0 0 -3ADD1A0 0 \ No newline at end of file +B7BF1E 0 +B1EF0B 0 +B5FA30 0 +B70B10 0 +B1EDAC 0 \ No newline at end of file diff --git a/Database/SF/1_14_74_0/Com.relb b/Database/SF/1_14_74_0/Com.relb new file mode 100644 index 00000000..e06d4a79 --- /dev/null +++ b/Database/SF/1_14_74_0/Com.relb @@ -0,0 +1,4 @@ +COM +1 +extended +0 0 \ No newline at end of file diff --git a/Database/SF/1_14_74_0/CreationKitPlatformExtended_SF_1_14_74_0.database b/Database/SF/1_14_74_0/CreationKitPlatformExtended_SF_1_14_74_0.database index 43116515ea408b1f46ba358b1831c24ed0c8ce8e..53664d0fb08010bddd8595042ed7a707cabc2108 100644 GIT binary patch delta 192 zcmeBdW4zwZI6;9?d!u4FTm4i92w((K;tWo~jz!5CnPsWIiFt|XsYMFD`6(%>DM3C? zE=)iL8BoRSKstcuBP$z&g7|7~28IRFAAoEJFk5c_b_O \ No newline at end of file diff --git a/Database/SSE/1_5_73/CreationKitPlatformExtended_SSE_1_5_73.database b/Database/SSE/1_5_73/CreationKitPlatformExtended_SSE_1_5_73.database index ca32f1b6527053660154c46cc288e8e962eee95e..8d293844256164a1689104b76934acdcbb49116a 100644 GIT binary patch delta 109 zcmX@?+u=7sfw5$x;&NtvO9lvF1X9cl&i=kZK29!7K#l@LoB<>O0&ENlGrln|-p4G> p83qwyV4QqhPH{3PACKsXZ~8!Wc{|Pnb^3$JnjPmi|CKw&4gf8s7jFOn delta 49 zcmeD1JM23_fw6d_;&SHAj4a=zIK3DkfN7Gv;^ZB&Je()K=`%7g{J*egvy=QWb^vdU B4^037 diff --git a/Database/SSE/1_5_73/RenderWindow60FPS.relb b/Database/SSE/1_5_73/RenderWindow60FPS.relb index 69f30dab..eff0b43c 100644 --- a/Database/SSE/1_5_73/RenderWindow60FPS.relb +++ b/Database/SSE/1_5_73/RenderWindow60FPS.relb @@ -1,4 +1,6 @@ Render Window 60 FPS -2 -012FF6C8 -2BCD0FF \ No newline at end of file +1 +12FF6C8 +2CFB86E +2CFB84F +2CFB87C \ No newline at end of file diff --git a/Database/SSE/1_6_1130/Com.relb b/Database/SSE/1_6_1130/Com.relb new file mode 100644 index 00000000..e06d4a79 --- /dev/null +++ b/Database/SSE/1_6_1130/Com.relb @@ -0,0 +1,4 @@ +COM +1 +extended +0 0 \ No newline at end of file diff --git a/Database/SSE/1_6_1130/CreationKitPlatformExtended_SSE_1_6_1130.database b/Database/SSE/1_6_1130/CreationKitPlatformExtended_SSE_1_6_1130.database index 550f14de8c3c8b68b904afe54a45451cefca6878..790fe52c20f1dfd64b7ec33a8c29aefa69fe21a2 100644 GIT binary patch delta 109 zcmccbza(IS0%OHS#a?E8O9lvF1X9cl&i=kZK29!7K#l@LoB<>O0&EN)e6KNYUc!7! pnllU{#K1VYU0!iArwEV82^lS*!v7cc0JWBYN#2W__sA=A0036g7HR+h delta 49 zcmZ1yaNmD|0%Q3`#a`yk&zUbsb9ymA0Mq0H@`{sJaPn}RkkMjfVEBJwGoyks2LOqt B4pIOB diff --git a/Database/SSE/1_6_1130/RenderWindow60FPS.relb b/Database/SSE/1_6_1130/RenderWindow60FPS.relb index ad9970d1..e19e64ef 100644 --- a/Database/SSE/1_6_1130/RenderWindow60FPS.relb +++ b/Database/SSE/1_6_1130/RenderWindow60FPS.relb @@ -1,4 +1,6 @@ Render Window 60 FPS -2 +1 12A1CC8 -2BCD0FF \ No newline at end of file +2BCD0FF +2BCD074 +2BCD10D \ No newline at end of file diff --git a/Database/SSE/1_6_1378_1/Com.relb b/Database/SSE/1_6_1378_1/Com.relb new file mode 100644 index 00000000..e06d4a79 --- /dev/null +++ b/Database/SSE/1_6_1378_1/Com.relb @@ -0,0 +1,4 @@ +COM +1 +extended +0 0 \ No newline at end of file diff --git a/Database/SSE/1_6_1378_1/CreationKitPlatformExtended_SSE_1_6_1378_1.database b/Database/SSE/1_6_1378_1/CreationKitPlatformExtended_SSE_1_6_1378_1.database index 5591f908c81652351f57daf6d5ea0aa09537bb6e..2c3dae247c08683079248b17ce86b20e3d3562b6 100644 GIT binary patch delta 108 zcmX^5g=yMXrU?p+qD=T@G{D%1L88dRPGRjAB7z{JLopax>^g|LC*o3~BtR|WuMj32lF delta 57 zcmbRCmFeggrU?p+Wg8Wn1UKIi^lst2!~g+IlMSXRa;|{$qNYt`3CQrb*~~t@Ul{-t CK@h9} diff --git a/Database/SSE/1_6_1378_1/RenderWindow60FPS.relb b/Database/SSE/1_6_1378_1/RenderWindow60FPS.relb index 6792d142..38b1171b 100644 --- a/Database/SSE/1_6_1378_1/RenderWindow60FPS.relb +++ b/Database/SSE/1_6_1378_1/RenderWindow60FPS.relb @@ -1,5 +1,7 @@ Render Window 60 FPS -2 +1 extended 12D1FD8 130 32000000BA01000000488B842460010000488B4808FF15????????F30F1005????????F30F11442420F30F101D????????F30F1015????????F30F100D???????? -2C099AF 0 \ No newline at end of file +2C099AF 0 +2C09924 0 +2C099BD 0 \ No newline at end of file diff --git a/Dependencies/DirectXTex/include/ScreenGrab11.h b/Dependencies/DirectXTex/include/ScreenGrab11.h new file mode 100644 index 00000000..0c448873 --- /dev/null +++ b/Dependencies/DirectXTex/include/ScreenGrab11.h @@ -0,0 +1,46 @@ +//-------------------------------------------------------------------------------------- +// File: ScreenGrab11.h +// +// Function for capturing a 2D texture and saving it to a file (aka a 'screenshot' +// when used on a Direct3D 11 Render Target). +// +// Note these functions are useful as a light-weight runtime screen grabber. For +// full-featured texture capture, DDS writer, and texture processing pipeline, +// see the 'Texconv' sample and the 'DirectXTex' library. +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + +#pragma once + +#include + +#if defined(NTDDI_WIN10_FE) || defined(__MINGW32__) +#include +#else +#include +#endif + +#include + + +namespace DirectX +{ + HRESULT __cdecl SaveDDSTextureToFile( + _In_ ID3D11DeviceContext* pContext, + _In_ ID3D11Resource* pSource, + _In_z_ const wchar_t* fileName) noexcept; + + HRESULT __cdecl SaveWICTextureToFile( + _In_ ID3D11DeviceContext* pContext, + _In_ ID3D11Resource* pSource, + _In_ REFGUID guidContainerFormat, + _In_z_ const wchar_t* fileName, + _In_opt_ const GUID* targetFormat = nullptr, + _In_opt_ std::function setCustomProps = nullptr, + _In_ bool forceSRGB = false); +} diff --git a/Dependencies/DirectXTex/src/ScreenGrab11.cpp b/Dependencies/DirectXTex/src/ScreenGrab11.cpp new file mode 100644 index 00000000..75645a33 --- /dev/null +++ b/Dependencies/DirectXTex/src/ScreenGrab11.cpp @@ -0,0 +1,1261 @@ +//-------------------------------------------------------------------------------------- +// File: ScreenGrab11.cpp +// +// Function for capturing a 2D texture and saving it to a file (aka a 'screenshot' +// when used on a Direct3D Render Target). +// +// Note these functions are useful as a light-weight runtime screen grabber. For +// full-featured texture capture, DDS writer, and texture processing pipeline, +// see the 'Texconv' sample and the 'DirectXTex' library. +// +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + +// Does not capture 1D textures or 3D textures (volume maps) + +// Does not capture mipmap chains, only the top-most texture level is saved + +// For 2D array textures and cubemaps, it captures only the first image in the array + +#include "ScreenGrab11.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef _MSC_VER +// Off by default warnings +#pragma warning(disable : 4619 4616 4061 4062 4623 4626 5027) +// C4619/4616 #pragma warning warnings +// C4061 enumerator 'x' in switch of enum 'y' is not explicitly handled by a case label +// C4062 enumerator 'x' in switch of enum 'y' is not handled +// C4623 default constructor was implicitly defined as deleted +// C4626 assignment operator was implicitly defined as deleted +// C5027 move assignment operator was implicitly defined as deleted +#endif + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wcovered-switch-default" +#pragma clang diagnostic ignored "-Wswitch-enum" +#endif + +using Microsoft::WRL::ComPtr; + +//-------------------------------------------------------------------------------------- +// Macros +//-------------------------------------------------------------------------------------- +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \ + ((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 )) +#endif /* defined(MAKEFOURCC) */ + +//-------------------------------------------------------------------------------------- +// DDS file structure definitions +// +// See DDS.h in the 'Texconv' sample and the 'DirectXTex' library +//-------------------------------------------------------------------------------------- +namespace +{ +#pragma pack(push,1) + +#define DDS_MAGIC 0x20534444 // "DDS " + + struct DDS_PIXELFORMAT + { + uint32_t size; + uint32_t flags; + uint32_t fourCC; + uint32_t RGBBitCount; + uint32_t RBitMask; + uint32_t GBitMask; + uint32_t BBitMask; + uint32_t ABitMask; + }; + +#define DDS_FOURCC 0x00000004 // DDPF_FOURCC +#define DDS_RGB 0x00000040 // DDPF_RGB +#define DDS_RGBA 0x00000041 // DDPF_RGB | DDPF_ALPHAPIXELS +#define DDS_LUMINANCE 0x00020000 // DDPF_LUMINANCE +#define DDS_LUMINANCEA 0x00020001 // DDPF_LUMINANCE | DDPF_ALPHAPIXELS +#define DDS_ALPHA 0x00000002 // DDPF_ALPHA +#define DDS_BUMPDUDV 0x00080000 // DDPF_BUMPDUDV + +#define DDS_HEADER_FLAGS_TEXTURE 0x00001007 // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT +#define DDS_HEADER_FLAGS_MIPMAP 0x00020000 // DDSD_MIPMAPCOUNT +#define DDS_HEADER_FLAGS_PITCH 0x00000008 // DDSD_PITCH +#define DDS_HEADER_FLAGS_LINEARSIZE 0x00080000 // DDSD_LINEARSIZE + +#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE + + struct DDS_HEADER + { + uint32_t size; + uint32_t flags; + uint32_t height; + uint32_t width; + uint32_t pitchOrLinearSize; + uint32_t depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags + uint32_t mipMapCount; + uint32_t reserved1[11]; + DDS_PIXELFORMAT ddspf; + uint32_t caps; + uint32_t caps2; + uint32_t caps3; + uint32_t caps4; + uint32_t reserved2; + }; + + struct DDS_HEADER_DXT10 + { + DXGI_FORMAT dxgiFormat; + uint32_t resourceDimension; + uint32_t miscFlag; // see D3D11_RESOURCE_MISC_FLAG + uint32_t arraySize; + uint32_t reserved; + }; + +#pragma pack(pop) + + const DDS_PIXELFORMAT DDSPF_DXT1 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_DXT3 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_DXT5 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_BC4_UNORM = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_BC4_SNORM = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_BC5_UNORM = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_BC5_SNORM = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_R8G8_B8G8 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_G8R8_G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_YUY2 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_A8R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; + + const DDS_PIXELFORMAT DDSPF_X8R8G8B8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0 }; + + const DDS_PIXELFORMAT DDSPF_A8B8G8R8 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; + + const DDS_PIXELFORMAT DDSPF_G16R16 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x0000ffff, 0xffff0000, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_R5G6B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0 }; + + const DDS_PIXELFORMAT DDSPF_A1R5G5B5 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 }; + + const DDS_PIXELFORMAT DDSPF_A4R4G4B4 = + { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 }; + + const DDS_PIXELFORMAT DDSPF_L8 = + { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_L16 = + { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_A8L8 = + { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0, 0, 0xff00 }; + + const DDS_PIXELFORMAT DDSPF_A8 = + { sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0, 0, 0, 0xff }; + + const DDS_PIXELFORMAT DDSPF_V8U8 = + { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0 }; + + const DDS_PIXELFORMAT DDSPF_Q8W8V8U8 = + { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; + + const DDS_PIXELFORMAT DDSPF_V16U16 = + { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0 }; + + // DXGI_FORMAT_R10G10B10A2_UNORM should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue + + // This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat) + const DDS_PIXELFORMAT DDSPF_DX10 = + { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 }; + + //----------------------------------------------------------------------------- + struct handle_closer { void operator()(HANDLE h) noexcept { if (h) CloseHandle(h); } }; + + using ScopedHandle = std::unique_ptr; + + inline HANDLE safe_handle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; } + + class auto_delete_file + { + public: + auto_delete_file(HANDLE hFile) noexcept : m_handle(hFile) {} + ~auto_delete_file() + { + if (m_handle) + { + FILE_DISPOSITION_INFO info = {}; + info.DeleteFile = TRUE; + std::ignore = SetFileInformationByHandle(m_handle, FileDispositionInfo, &info, sizeof(info)); + } + } + + auto_delete_file(const auto_delete_file&) = delete; + auto_delete_file& operator=(const auto_delete_file&) = delete; + + auto_delete_file(const auto_delete_file&&) = delete; + auto_delete_file& operator=(const auto_delete_file&&) = delete; + + void clear() noexcept { m_handle = nullptr; } + + private: + HANDLE m_handle; + }; + + class auto_delete_file_wic + { + public: + auto_delete_file_wic(ComPtr& hFile, const wchar_t* szFile) noexcept : m_filename(szFile), m_handle(hFile) {} + ~auto_delete_file_wic() + { + if (m_filename) + { + m_handle.Reset(); + DeleteFileW(m_filename); + } + } + + auto_delete_file_wic(const auto_delete_file_wic&) = delete; + auto_delete_file_wic& operator=(const auto_delete_file_wic&) = delete; + + auto_delete_file_wic(const auto_delete_file_wic&&) = delete; + auto_delete_file_wic& operator=(const auto_delete_file_wic&&) = delete; + + void clear() noexcept { m_filename = nullptr; } + + private: + const wchar_t* m_filename; + ComPtr& m_handle; + }; + + //-------------------------------------------------------------------------------------- + // Return the BPP for a particular format + //-------------------------------------------------------------------------------------- + size_t BitsPerPixel(_In_ DXGI_FORMAT fmt) noexcept + { + switch (fmt) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return 128; + + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return 96; + + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + case DXGI_FORMAT_Y416: + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + return 64; + + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + case DXGI_FORMAT_AYUV: + case DXGI_FORMAT_Y410: + case DXGI_FORMAT_YUY2: + return 32; + + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + return 24; + + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_A8P8: + case DXGI_FORMAT_B4G4R4A4_UNORM: + return 16; + + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_420_OPAQUE: + case DXGI_FORMAT_NV11: + return 12; + + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + return 8; + + case DXGI_FORMAT_R1_UNORM: + return 1; + + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + return 4; + + default: + return 0; + } + } + + + //-------------------------------------------------------------------------------------- + // Determines if the format is block compressed + //-------------------------------------------------------------------------------------- + bool IsCompressed(_In_ DXGI_FORMAT fmt) noexcept + { + switch (fmt) + { + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + return true; + + default: + return false; + } + } + + + //-------------------------------------------------------------------------------------- + // Get surface information for a particular format + //-------------------------------------------------------------------------------------- + HRESULT GetSurfaceInfo( + _In_ size_t width, + _In_ size_t height, + _In_ DXGI_FORMAT fmt, + _Out_opt_ size_t* outNumBytes, + _Out_opt_ size_t* outRowBytes, + _Out_opt_ size_t* outNumRows) noexcept + { + uint64_t numBytes = 0; + uint64_t rowBytes = 0; + uint64_t numRows = 0; + + bool bc = false; + bool packed = false; + bool planar = false; + size_t bpe = 0; + switch (fmt) + { + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + bc = true; + bpe = 8; + break; + + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + bc = true; + bpe = 16; + break; + + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_YUY2: + packed = true; + bpe = 4; + break; + + case DXGI_FORMAT_Y210: + case DXGI_FORMAT_Y216: + packed = true; + bpe = 8; + break; + + case DXGI_FORMAT_NV12: + case DXGI_FORMAT_420_OPAQUE: + planar = true; + bpe = 2; + break; + + case DXGI_FORMAT_P010: + case DXGI_FORMAT_P016: + planar = true; + bpe = 4; + break; + + default: + break; + } + + if (bc) + { + uint64_t numBlocksWide = 0; + if (width > 0) + { + numBlocksWide = std::max(1u, (uint64_t(width) + 3u) / 4u); + } + uint64_t numBlocksHigh = 0; + if (height > 0) + { + numBlocksHigh = std::max(1u, (uint64_t(height) + 3u) / 4u); + } + rowBytes = numBlocksWide * bpe; + numRows = numBlocksHigh; + numBytes = rowBytes * numBlocksHigh; + } + else if (packed) + { + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numRows = uint64_t(height); + numBytes = rowBytes * height; + } + else if (fmt == DXGI_FORMAT_NV11) + { + rowBytes = ((uint64_t(width) + 3u) >> 2) * 4u; + numRows = uint64_t(height) * 2u; // Direct3D makes this simplifying assumption, although it is larger than the 4:1:1 data + numBytes = rowBytes * numRows; + } + else if (planar) + { + rowBytes = ((uint64_t(width) + 1u) >> 1) * bpe; + numBytes = (rowBytes * uint64_t(height)) + ((rowBytes * uint64_t(height) + 1u) >> 1); + numRows = height + ((uint64_t(height) + 1u) >> 1); + } + else + { + const size_t bpp = BitsPerPixel(fmt); + if (!bpp) + return E_INVALIDARG; + + rowBytes = (uint64_t(width) * bpp + 7u) / 8u; // round up to nearest byte + numRows = uint64_t(height); + numBytes = rowBytes * height; + } + + #if defined(_M_IX86) || defined(_M_ARM) || defined(_M_HYBRID_X86_ARM64) + static_assert(sizeof(size_t) == 4, "Not a 32-bit platform!"); + if (numBytes > UINT32_MAX || rowBytes > UINT32_MAX || numRows > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + #else + static_assert(sizeof(size_t) == 8, "Not a 64-bit platform!"); + #endif + + if (outNumBytes) + { + *outNumBytes = static_cast(numBytes); + } + if (outRowBytes) + { + *outRowBytes = static_cast(rowBytes); + } + if (outNumRows) + { + *outNumRows = static_cast(numRows); + } + + return S_OK; + } + + + //-------------------------------------------------------------------------------------- + DXGI_FORMAT EnsureNotTypeless(DXGI_FORMAT fmt) noexcept + { + // Assumes UNORM or FLOAT; doesn't use UINT or SINT + switch (fmt) + { + case DXGI_FORMAT_R32G32B32A32_TYPELESS: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case DXGI_FORMAT_R32G32B32_TYPELESS: return DXGI_FORMAT_R32G32B32_FLOAT; + case DXGI_FORMAT_R16G16B16A16_TYPELESS: return DXGI_FORMAT_R16G16B16A16_UNORM; + case DXGI_FORMAT_R32G32_TYPELESS: return DXGI_FORMAT_R32G32_FLOAT; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: return DXGI_FORMAT_R10G10B10A2_UNORM; + case DXGI_FORMAT_R8G8B8A8_TYPELESS: return DXGI_FORMAT_R8G8B8A8_UNORM; + case DXGI_FORMAT_R16G16_TYPELESS: return DXGI_FORMAT_R16G16_UNORM; + case DXGI_FORMAT_R32_TYPELESS: return DXGI_FORMAT_R32_FLOAT; + case DXGI_FORMAT_R8G8_TYPELESS: return DXGI_FORMAT_R8G8_UNORM; + case DXGI_FORMAT_R16_TYPELESS: return DXGI_FORMAT_R16_UNORM; + case DXGI_FORMAT_R8_TYPELESS: return DXGI_FORMAT_R8_UNORM; + case DXGI_FORMAT_BC1_TYPELESS: return DXGI_FORMAT_BC1_UNORM; + case DXGI_FORMAT_BC2_TYPELESS: return DXGI_FORMAT_BC2_UNORM; + case DXGI_FORMAT_BC3_TYPELESS: return DXGI_FORMAT_BC3_UNORM; + case DXGI_FORMAT_BC4_TYPELESS: return DXGI_FORMAT_BC4_UNORM; + case DXGI_FORMAT_BC5_TYPELESS: return DXGI_FORMAT_BC5_UNORM; + case DXGI_FORMAT_B8G8R8A8_TYPELESS: return DXGI_FORMAT_B8G8R8A8_UNORM; + case DXGI_FORMAT_B8G8R8X8_TYPELESS: return DXGI_FORMAT_B8G8R8X8_UNORM; + case DXGI_FORMAT_BC7_TYPELESS: return DXGI_FORMAT_BC7_UNORM; + default: return fmt; + } + } + + + //-------------------------------------------------------------------------------------- + HRESULT CaptureTexture( + _In_ ID3D11DeviceContext* pContext, + _In_ ID3D11Resource* pSource, + D3D11_TEXTURE2D_DESC& desc, + ComPtr& pStaging) noexcept + { + if (!pContext || !pSource) + return E_INVALIDARG; + + D3D11_RESOURCE_DIMENSION resType = D3D11_RESOURCE_DIMENSION_UNKNOWN; + pSource->GetType(&resType); + + if (resType != D3D11_RESOURCE_DIMENSION_TEXTURE2D) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + ComPtr pTexture; + HRESULT hr = pSource->QueryInterface(IID_ID3D11Texture2D, reinterpret_cast(pTexture.GetAddressOf())); + if (FAILED(hr)) + return hr; + + assert(pTexture); + + pTexture->GetDesc(&desc); + + ComPtr d3dDevice; + pContext->GetDevice(d3dDevice.GetAddressOf()); + + if (desc.SampleDesc.Count > 1) + { + // MSAA content must be resolved before being copied to a staging texture + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + + ComPtr pTemp; + hr = d3dDevice->CreateTexture2D(&desc, nullptr, pTemp.GetAddressOf()); + if (FAILED(hr)) + return hr; + + assert(pTemp); + + const DXGI_FORMAT fmt = EnsureNotTypeless(desc.Format); + + UINT support = 0; + hr = d3dDevice->CheckFormatSupport(fmt, &support); + if (FAILED(hr)) + return hr; + + if (!(support & D3D11_FORMAT_SUPPORT_MULTISAMPLE_RESOLVE)) + return E_FAIL; + + for (UINT item = 0; item < desc.ArraySize; ++item) + { + for (UINT level = 0; level < desc.MipLevels; ++level) + { + const UINT index = D3D11CalcSubresource(level, item, desc.MipLevels); + pContext->ResolveSubresource(pTemp.Get(), index, pSource, index, fmt); + } + } + + desc.BindFlags = 0; + desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + hr = d3dDevice->CreateTexture2D(&desc, nullptr, pStaging.ReleaseAndGetAddressOf()); + if (FAILED(hr)) + return hr; + + assert(pStaging); + + pContext->CopyResource(pStaging.Get(), pTemp.Get()); + } + else if ((desc.Usage == D3D11_USAGE_STAGING) && (desc.CPUAccessFlags & D3D11_CPU_ACCESS_READ)) + { + // Handle case where the source is already a staging texture we can use directly + pStaging = pTexture; + } + else + { + // Otherwise, create a staging texture from the non-MSAA source + desc.BindFlags = 0; + desc.MiscFlags &= D3D11_RESOURCE_MISC_TEXTURECUBE; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + desc.Usage = D3D11_USAGE_STAGING; + + hr = d3dDevice->CreateTexture2D(&desc, nullptr, pStaging.ReleaseAndGetAddressOf()); + if (FAILED(hr)) + return hr; + + assert(pStaging); + + pContext->CopyResource(pStaging.Get(), pSource); + } + + return S_OK; + } + + //-------------------------------------------------------------------------------------- + bool g_WIC2 = false; + + BOOL WINAPI InitializeWICFactory(PINIT_ONCE, PVOID, PVOID* ifactory) noexcept + { + #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) + HRESULT hr = CoCreateInstance( + CLSID_WICImagingFactory2, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory2), + ifactory + ); + + if (SUCCEEDED(hr)) + { + // WIC2 is available on Windows 10, Windows 8.x, and Windows 7 SP1 with KB 2670838 installed + g_WIC2 = true; + return TRUE; + } + else + { + hr = CoCreateInstance( + CLSID_WICImagingFactory1, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + ifactory + ); + return SUCCEEDED(hr) ? TRUE : FALSE; + } + #else + return SUCCEEDED(CoCreateInstance( + CLSID_WICImagingFactory, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + ifactory)) ? TRUE : FALSE; + #endif + } + + IWICImagingFactory* GetWIC() noexcept + { + static INIT_ONCE s_initOnce = INIT_ONCE_STATIC_INIT; + + IWICImagingFactory* factory = nullptr; + if (!InitOnceExecuteOnce(&s_initOnce, + InitializeWICFactory, + nullptr, + reinterpret_cast(&factory))) + { + return nullptr; + } + + return factory; + } +} // anonymous namespace + + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT DirectX::SaveDDSTextureToFile( + ID3D11DeviceContext* pContext, + ID3D11Resource* pSource, + const wchar_t* fileName) noexcept +{ + if (!fileName) + return E_INVALIDARG; + + D3D11_TEXTURE2D_DESC desc = {}; + ComPtr pStaging; + HRESULT hr = CaptureTexture(pContext, pSource, desc, pStaging); + if (FAILED(hr)) + return hr; + + // Create file +#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) + ScopedHandle hFile(safe_handle(CreateFile2(fileName, + GENERIC_WRITE | DELETE, 0, CREATE_ALWAYS, nullptr))); +#else + ScopedHandle hFile(safe_handle(CreateFileW(fileName, + GENERIC_WRITE | DELETE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))); +#endif + if (!hFile) + return HRESULT_FROM_WIN32(GetLastError()); + + auto_delete_file delonfail(hFile.get()); + + // Setup header + constexpr size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10); + uint8_t fileHeader[MAX_HEADER_SIZE] = {}; + + *reinterpret_cast(&fileHeader[0]) = DDS_MAGIC; + + auto header = reinterpret_cast(&fileHeader[0] + sizeof(uint32_t)); + size_t headerSize = sizeof(uint32_t) + sizeof(DDS_HEADER); + header->size = sizeof(DDS_HEADER); + header->flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_MIPMAP; + header->height = desc.Height; + header->width = desc.Width; + header->mipMapCount = 1; + header->caps = DDS_SURFACE_FLAGS_TEXTURE; + + // Try to use a legacy .DDS pixel format for better tools support, otherwise fallback to 'DX10' header extension + DDS_HEADER_DXT10* extHeader = nullptr; + switch (desc.Format) + { + case DXGI_FORMAT_R8G8B8A8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R16G16_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_G16R16, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R16_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_L16, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_L8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_A8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8_B8G8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_R8G8_B8G8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_G8R8_G8B8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_G8R8_G8B8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC1_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC2_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DXT3, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC3_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DXT5, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC4_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC4_SNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC5_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_BC5_SNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_B5G6R5_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8_SNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_V8U8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R8G8B8A8_SNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_Q8W8V8U8, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_R16G16_SNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_V16U16, sizeof(DDS_PIXELFORMAT)); break; + case DXGI_FORMAT_B8G8R8A8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.1 + case DXGI_FORMAT_B8G8R8X8_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.1 + case DXGI_FORMAT_YUY2: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.2 + case DXGI_FORMAT_B4G4R4A4_UNORM: memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT)); break; // DXGI 1.2 + + // Legacy D3DX formats using D3DFMT enum value as FourCC + case DXGI_FORMAT_R32G32B32A32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 116; break; // D3DFMT_A32B32G32R32F + case DXGI_FORMAT_R16G16B16A16_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 113; break; // D3DFMT_A16B16G16R16F + case DXGI_FORMAT_R16G16B16A16_UNORM: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 36; break; // D3DFMT_A16B16G16R16 + case DXGI_FORMAT_R16G16B16A16_SNORM: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 110; break; // D3DFMT_Q16W16V16U16 + case DXGI_FORMAT_R32G32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 115; break; // D3DFMT_G32R32F + case DXGI_FORMAT_R16G16_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 112; break; // D3DFMT_G16R16F + case DXGI_FORMAT_R32_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 114; break; // D3DFMT_R32F + case DXGI_FORMAT_R16_FLOAT: header->ddspf.size = sizeof(DDS_PIXELFORMAT); header->ddspf.flags = DDS_FOURCC; header->ddspf.fourCC = 111; break; // D3DFMT_R16F + + case DXGI_FORMAT_AI44: + case DXGI_FORMAT_IA44: + case DXGI_FORMAT_P8: + case DXGI_FORMAT_A8P8: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + + default: + memcpy_s(&header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT)); + + headerSize += sizeof(DDS_HEADER_DXT10); + extHeader = reinterpret_cast(fileHeader + sizeof(uint32_t) + sizeof(DDS_HEADER)); + extHeader->dxgiFormat = desc.Format; + extHeader->resourceDimension = D3D11_RESOURCE_DIMENSION_TEXTURE2D; + extHeader->arraySize = 1; + break; + } + + size_t rowPitch, slicePitch, rowCount; + hr = GetSurfaceInfo(desc.Width, desc.Height, desc.Format, &slicePitch, &rowPitch, &rowCount); + if (FAILED(hr)) + return hr; + + if (rowPitch > UINT32_MAX || slicePitch > UINT32_MAX) + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + + if (IsCompressed(desc.Format)) + { + header->flags |= DDS_HEADER_FLAGS_LINEARSIZE; + header->pitchOrLinearSize = static_cast(slicePitch); + } + else + { + header->flags |= DDS_HEADER_FLAGS_PITCH; + header->pitchOrLinearSize = static_cast(rowPitch); + } + + // Setup pixels + std::unique_ptr pixels(new (std::nothrow) uint8_t[slicePitch]); + if (!pixels) + return E_OUTOFMEMORY; + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = pContext->Map(pStaging.Get(), 0, D3D11_MAP_READ, 0, &mapped); + if (FAILED(hr)) + return hr; + + auto sptr = static_cast(mapped.pData); + if (!sptr) + { + pContext->Unmap(pStaging.Get(), 0); + return E_POINTER; + } + + uint8_t* dptr = pixels.get(); + + const size_t msize = std::min(rowPitch, mapped.RowPitch); + for (size_t h = 0; h < rowCount; ++h) + { + memcpy_s(dptr, rowPitch, sptr, msize); + sptr += mapped.RowPitch; + dptr += rowPitch; + } + + pContext->Unmap(pStaging.Get(), 0); + + // Write header & pixels + DWORD bytesWritten; + if (!WriteFile(hFile.get(), fileHeader, static_cast(headerSize), &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != headerSize) + return E_FAIL; + + if (!WriteFile(hFile.get(), pixels.get(), static_cast(slicePitch), &bytesWritten, nullptr)) + return HRESULT_FROM_WIN32(GetLastError()); + + if (bytesWritten != slicePitch) + return E_FAIL; + + delonfail.clear(); + + return S_OK; +} + +//-------------------------------------------------------------------------------------- +_Use_decl_annotations_ +HRESULT DirectX::SaveWICTextureToFile( + ID3D11DeviceContext* pContext, + ID3D11Resource* pSource, + REFGUID guidContainerFormat, + const wchar_t* fileName, + const GUID* targetFormat, + std::function setCustomProps, + bool forceSRGB) +{ + if (!fileName) + return E_INVALIDARG; + + D3D11_TEXTURE2D_DESC desc = {}; + ComPtr pStaging; + HRESULT hr = CaptureTexture(pContext, pSource, desc, pStaging); + if (FAILED(hr)) + return hr; + + // Determine source format's WIC equivalent + WICPixelFormatGUID pfGuid = {}; + bool sRGB = forceSRGB; + switch (desc.Format) + { + case DXGI_FORMAT_R32G32B32A32_FLOAT: pfGuid = GUID_WICPixelFormat128bppRGBAFloat; break; + case DXGI_FORMAT_R16G16B16A16_FLOAT: pfGuid = GUID_WICPixelFormat64bppRGBAHalf; break; + case DXGI_FORMAT_R16G16B16A16_UNORM: pfGuid = GUID_WICPixelFormat64bppRGBA; break; + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102XR; break; // DXGI 1.1 + case DXGI_FORMAT_R10G10B10A2_UNORM: pfGuid = GUID_WICPixelFormat32bppRGBA1010102; break; + case DXGI_FORMAT_B5G5R5A1_UNORM: pfGuid = GUID_WICPixelFormat16bppBGRA5551; break; + case DXGI_FORMAT_B5G6R5_UNORM: pfGuid = GUID_WICPixelFormat16bppBGR565; break; + case DXGI_FORMAT_R32_FLOAT: pfGuid = GUID_WICPixelFormat32bppGrayFloat; break; + case DXGI_FORMAT_R16_FLOAT: pfGuid = GUID_WICPixelFormat16bppGrayHalf; break; + case DXGI_FORMAT_R16_UNORM: pfGuid = GUID_WICPixelFormat16bppGray; break; + case DXGI_FORMAT_R8_UNORM: pfGuid = GUID_WICPixelFormat8bppGray; break; + case DXGI_FORMAT_A8_UNORM: pfGuid = GUID_WICPixelFormat8bppAlpha; break; + + case DXGI_FORMAT_R8G8B8A8_UNORM: + pfGuid = GUID_WICPixelFormat32bppRGBA; + break; + + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + pfGuid = GUID_WICPixelFormat32bppRGBA; + sRGB = true; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM: // DXGI 1.1 + pfGuid = GUID_WICPixelFormat32bppBGRA; + break; + + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: // DXGI 1.1 + pfGuid = GUID_WICPixelFormat32bppBGRA; + sRGB = true; + break; + + case DXGI_FORMAT_B8G8R8X8_UNORM: // DXGI 1.1 + pfGuid = GUID_WICPixelFormat32bppBGR; + break; + + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: // DXGI 1.1 + pfGuid = GUID_WICPixelFormat32bppBGR; + sRGB = true; + break; + + default: + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + + auto pWIC = GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ComPtr stream; + hr = pWIC->CreateStream(stream.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = stream->InitializeFromFilename(fileName, GENERIC_WRITE); + if (FAILED(hr)) + return hr; + + auto_delete_file_wic delonfail(stream, fileName); + + ComPtr encoder; + hr = pWIC->CreateEncoder(guidContainerFormat, nullptr, encoder.GetAddressOf()); + if (FAILED(hr)) + return hr; + + hr = encoder->Initialize(stream.Get(), WICBitmapEncoderNoCache); + if (FAILED(hr)) + return hr; + + ComPtr frame; + ComPtr props; + hr = encoder->CreateNewFrame(frame.GetAddressOf(), props.GetAddressOf()); + if (FAILED(hr)) + return hr; + + if (targetFormat && memcmp(&guidContainerFormat, &GUID_ContainerFormatBmp, sizeof(WICPixelFormatGUID)) == 0 && g_WIC2) + { + // Opt-in to the WIC2 support for writing 32-bit Windows BMP files with an alpha channel + PROPBAG2 option = {}; + option.pstrName = const_cast(L"EnableV5Header32bppBGRA"); + + VARIANT varValue; + varValue.vt = VT_BOOL; + varValue.boolVal = VARIANT_TRUE; + std::ignore = props->Write(1, &option, &varValue); + } + + if (setCustomProps) + { + setCustomProps(props.Get()); + } + + hr = frame->Initialize(props.Get()); + if (FAILED(hr)) + return hr; + + hr = frame->SetSize(desc.Width, desc.Height); + if (FAILED(hr)) + return hr; + + hr = frame->SetResolution(72, 72); + if (FAILED(hr)) + return hr; + + // Pick a target format + WICPixelFormatGUID targetGuid = {}; + if (targetFormat) + { + targetGuid = *targetFormat; + } + else + { + // Screenshots don't typically include the alpha channel of the render target + switch (desc.Format) + { + #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) || defined(_WIN7_PLATFORM_UPDATE) + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + if (g_WIC2) + { + targetGuid = GUID_WICPixelFormat96bppRGBFloat; + } + else + { + targetGuid = GUID_WICPixelFormat24bppBGR; + } + break; + #endif + + case DXGI_FORMAT_R16G16B16A16_UNORM: targetGuid = GUID_WICPixelFormat48bppBGR; break; + case DXGI_FORMAT_B5G5R5A1_UNORM: targetGuid = GUID_WICPixelFormat16bppBGR555; break; + case DXGI_FORMAT_B5G6R5_UNORM: targetGuid = GUID_WICPixelFormat16bppBGR565; break; + + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_A8_UNORM: + targetGuid = GUID_WICPixelFormat8bppGray; + break; + + default: + targetGuid = GUID_WICPixelFormat24bppBGR; + break; + } + } + + hr = frame->SetPixelFormat(&targetGuid); + if (FAILED(hr)) + return hr; + + if (targetFormat && memcmp(targetFormat, &targetGuid, sizeof(WICPixelFormatGUID)) != 0) + { + // Requested output pixel format is not supported by the WIC codec + return E_FAIL; + } + + // Encode WIC metadata + ComPtr metawriter; + if (SUCCEEDED(frame->GetMetadataQueryWriter(metawriter.GetAddressOf()))) + { + PROPVARIANT value; + PropVariantInit(&value); + + value.vt = VT_LPSTR; + value.pszVal = const_cast("DirectXTK"); + + if (memcmp(&guidContainerFormat, &GUID_ContainerFormatPng, sizeof(GUID)) == 0) + { + // Set Software name + std::ignore = metawriter->SetMetadataByName(L"/tEXt/{str=Software}", &value); + + // Set sRGB chunk + if (sRGB) + { + value.vt = VT_UI1; + value.bVal = 0; + std::ignore = metawriter->SetMetadataByName(L"/sRGB/RenderingIntent", &value); + } + else + { + // add gAMA chunk with gamma 1.0 + value.vt = VT_UI4; + value.uintVal = 100000; // gama value * 100,000 -- i.e. gamma 1.0 + std::ignore = metawriter->SetMetadataByName(L"/gAMA/ImageGamma", &value); + + // remove sRGB chunk which is added by default. + std::ignore = metawriter->RemoveMetadataByName(L"/sRGB/RenderingIntent"); + } + } + else + { + // Set Software name + std::ignore = metawriter->SetMetadataByName(L"System.ApplicationName", &value); + + if (sRGB) + { + // Set EXIF Colorspace of sRGB + value.vt = VT_UI2; + value.uiVal = 1; + std::ignore = metawriter->SetMetadataByName(L"System.Image.ColorSpace", &value); + } + } + } + + D3D11_MAPPED_SUBRESOURCE mapped; + hr = pContext->Map(pStaging.Get(), 0, D3D11_MAP_READ, 0, &mapped); + if (FAILED(hr)) + return hr; + + const uint64_t imageSize = uint64_t(mapped.RowPitch) * uint64_t(desc.Height); + if (imageSize > UINT32_MAX) + { + pContext->Unmap(pStaging.Get(), 0); + return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW); + } + + if (memcmp(&targetGuid, &pfGuid, sizeof(WICPixelFormatGUID)) != 0) + { + // Conversion required to write + ComPtr source; + hr = pWIC->CreateBitmapFromMemory(desc.Width, desc.Height, + pfGuid, + mapped.RowPitch, static_cast(imageSize), + static_cast(mapped.pData), source.GetAddressOf()); + if (FAILED(hr)) + { + pContext->Unmap(pStaging.Get(), 0); + return hr; + } + + ComPtr FC; + hr = pWIC->CreateFormatConverter(FC.GetAddressOf()); + if (FAILED(hr)) + { + pContext->Unmap(pStaging.Get(), 0); + return hr; + } + + BOOL canConvert = FALSE; + hr = FC->CanConvert(pfGuid, targetGuid, &canConvert); + if (FAILED(hr) || !canConvert) + { + pContext->Unmap(pStaging.Get(), 0); + return E_UNEXPECTED; + } + + hr = FC->Initialize(source.Get(), targetGuid, WICBitmapDitherTypeNone, nullptr, 0, WICBitmapPaletteTypeMedianCut); + if (FAILED(hr)) + { + pContext->Unmap(pStaging.Get(), 0); + return hr; + } + + WICRect rect = { 0, 0, static_cast(desc.Width), static_cast(desc.Height) }; + hr = frame->WriteSource(FC.Get(), &rect); + } + else + { + // No conversion required + hr = frame->WritePixels(desc.Height, + mapped.RowPitch, static_cast(imageSize), + static_cast(mapped.pData)); + } + + pContext->Unmap(pStaging.Get(), 0); + + if (FAILED(hr)) + return hr; + + hr = frame->Commit(); + if (FAILED(hr)) + return hr; + + hr = encoder->Commit(); + if (FAILED(hr)) + return hr; + + delonfail.clear(); + + return S_OK; +} diff --git a/Stuffs/FO4/CreationKitPlatformExtended.ini b/Stuffs/FO4/CreationKitPlatformExtended.ini index f1b36e88..8e00373b 100644 --- a/Stuffs/FO4/CreationKitPlatformExtended.ini +++ b/Stuffs/FO4/CreationKitPlatformExtended.ini @@ -62,6 +62,9 @@ nGenerationVersion=0 [Animation] bSkipAnimationBuildData=false ; Skips animation data generation, significantly speeds up loading, however, if you are working with animation, it should be disabled. +[Graphics] +fMipLODBias=-1.3 ; Force set mipmap level bias value (value must be [-3.0 : 3.0] where there is less than 0.0, the further away the 0 mipmap is). + [FaceGen] bDisableExportDDS=false ; Prevent tint export as DDS bDisableExportTGA=true ; Prevent tint export as TGA diff --git a/Stuffs/SSE/CreationKitPlatformExtended.ini b/Stuffs/SSE/CreationKitPlatformExtended.ini index 89d986f1..70fabf64 100644 --- a/Stuffs/SSE/CreationKitPlatformExtended.ini +++ b/Stuffs/SSE/CreationKitPlatformExtended.ini @@ -54,6 +54,9 @@ bOverlapsGenerateONAM=true ; (Only version 1.6.1130 or newer) Replaces the ge ; BALTIC_CHARSET 186 nCharset=1 +[Graphics] +fMipLODBias=-1.3 ; Force set mipmap level bias value (value must be [-3.0 : 3.0] where there is less than 0.0, the further away the 0 mipmap is). + [FaceGen] bDisableAutoFaceGen=true ; Prevent facegen data from being created on plugin save bDisableExportDDS=false ; Prevent tint export as DDS