diff --git a/OptiScaler/NVNGX_DLSS_Dx12.cpp b/OptiScaler/NVNGX_DLSS_Dx12.cpp
index 1613fb96..febc1022 100644
--- a/OptiScaler/NVNGX_DLSS_Dx12.cpp
+++ b/OptiScaler/NVNGX_DLSS_Dx12.cpp
@@ -650,8 +650,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom
Config::Instance()->CurrentFeature != nullptr && Config::Instance()->CurrentFeature->FrameCount() > Config::Instance()->MenuInitDelay.value_or(75) &&
!ImGuiOverlayDx12::IsInitedDx12())
{
- Hooks::ContextRenderingStart();
-
auto hwnd = Util::GetProcessWindow();
HWND consoleWindow = GetConsoleWindow();
@@ -673,8 +671,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom
if (consoleAllocated)
FreeConsole();
-
- Hooks::ContextRenderingStop();
}
if (handleId < 1000000)
@@ -701,13 +697,10 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom
// Check window recreation
if (Config::Instance()->OverlayMenu.value_or(true) && ImGuiOverlayDx12::IsInitedDx12())
{
- Hooks::ContextRenderingStart();
-
HWND currentHandle = Util::GetProcessWindow();
+
if (ImGuiOverlayDx12::Handle() != currentHandle)
ImGuiOverlayDx12::ReInitDx12(currentHandle);
-
- Hooks::ContextRenderingStop();
}
if (InCallback)
@@ -813,7 +806,6 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom
Config::Instance()->CurrentFeature = nullptr;
- Hooks::ContextRenderingStop();
Hooks::ContextEvaluateStop(nullptr, false);
}
else
@@ -969,17 +961,13 @@ NVSDK_NGX_API NVSDK_NGX_Result NVSDK_NGX_D3D12_EvaluateFeature(ID3D12GraphicsCom
Config::Instance()->CurrentFeature = deviceContext;
- if (deviceContext->Name() != "DLSSD")
- Hooks::ContextRenderingStart();
-
bool evalResult = deviceContext->Evaluate(InCmdList, InParameters);
- if (deviceContext->Name() != "DLSSD")
- Hooks::ContextEvaluateStop(InCmdList, true);
-
if (Config::Instance()->OverlayMenu.value_or(true))
ImGuiOverlayDx12::CaptureQueue(InCmdList);
+ Hooks::ContextEvaluateStop(InCmdList, true);
+
LOG_TRACE("done: {0:X}", (UINT)evalResult);
if (evalResult)
diff --git a/OptiScaler/OptiScaler.vcxproj b/OptiScaler/OptiScaler.vcxproj
index 4805ca3e..7603c4ff 100644
--- a/OptiScaler/OptiScaler.vcxproj
+++ b/OptiScaler/OptiScaler.vcxproj
@@ -82,7 +82,7 @@
$(SolutionDir)external\vulkan\include;$(SolutionDir)external\nvngx_dlss_sdk;$(SolutionDir)external\xess\inc\xess;$(SolutionDir)external\FidelityFX-SDK\ffx-api\include\ffx_api;$(SolutionDir)external\simpleini;$(SolutionDir)external\unordered_dense\include;$(SolutionDir)external\spdlog\include;$(IncludePath)
$(ProjectDir)fsr2\lib;$(ProjectDir)fsr2_212\lib;$(ProjectDir)vulkan;$(ProjectDir)d3dx;$(ProjectDir)detours;$(SolutionDir)external\xess\lib;$(LibraryPath)
dxgi
- D:\Folders\Games\SteamLibrary\steamapps\common\Horizon Zero Dawn\
+ D:\Folders\Games\Deep Rock Galactic\FSD\Binaries\Win64\
.\x64\Debug
@@ -212,7 +212,12 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\
+
+
+
+
+
@@ -237,7 +242,6 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\
-
@@ -256,7 +260,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\
-
+
@@ -300,7 +304,12 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\
+
+
+
+
+
@@ -319,7 +328,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\
-
+
diff --git a/OptiScaler/enums/Enums.h b/OptiScaler/enums/Enums.h
new file mode 100644
index 00000000..67987981
--- /dev/null
+++ b/OptiScaler/enums/Enums.h
@@ -0,0 +1,10 @@
+#pragma once
+
+enum SwapchainSource
+{
+ Unknown,
+ Dx12,
+ SL,
+ FSR3_Mod,
+ FSR3_Native
+};
diff --git a/OptiScaler/hooks/Dx12_Hooks.cpp b/OptiScaler/hooks/Dx12_Hooks.cpp
index f3c99f53..2b91829f 100644
--- a/OptiScaler/hooks/Dx12_Hooks.cpp
+++ b/OptiScaler/hooks/Dx12_Hooks.cpp
@@ -1,17 +1,16 @@
#include "Dx12_Hooks.h"
-#include "../pch.h"
#include "../Config.h"
#include "../detours/detours.h"
// Menu Hooks
-typedef void(*PFN_ExecuteCommandLists)(ID3D12CommandQueue*, UINT, ID3D12CommandList* const*);
-typedef ULONG(*PFN_Release)(IUnknown*);
typedef HRESULT(*PFN_CreateCommandQueue)(ID3D12Device* This, const D3D12_COMMAND_QUEUE_DESC* pDesc, REFIID riid, void** ppCommandQueue);
+typedef void(*PFN_ExecuteCommandLists)(ID3D12CommandQueue*, UINT, ID3D12CommandList* const*);
+typedef ULONG(*PFN_CommandQueueRelease)(IUnknown*);
static PFN_D3D12_CREATE_DEVICE o_D3D12CreateDevice = nullptr;
static PFN_CreateCommandQueue o_CreateCommandQueue = nullptr;
-static PFN_Release o_CommandQueueRelease = nullptr;
+static PFN_CommandQueueRelease o_CommandQueueRelease = nullptr;
static PFN_ExecuteCommandLists o_ExecuteCommandLists = nullptr;
// Sampler stuff for MipLodBias and Anisotropic Filtering
@@ -26,13 +25,20 @@ static PFN_SetRootSignature o_SetGraphicRootSignature = nullptr;
static ID3D12RootSignature* rootSigCompute = nullptr;
static ID3D12RootSignature* rootSigGraphic = nullptr;
-static bool contextRendering = false;
-static ULONGLONG computeTime = 0;
-static ULONGLONG graphTime = 0;
-static ULONGLONG lastEvalTime = 0;
-static uint64_t evaluateStart;
+static uint64_t computeRSTime = 0;
+static uint64_t graphRSTime = 0;
+static uint64_t lastEvalTime = 0;
+static uint64_t evalStartTime = 0;
static std::mutex sigatureMutex;
+static void HookToCommandList(ID3D12GraphicsCommandList* InCmdList);
+static void HookToDevice(ID3D12Device* InDevice);
+
+// Commnad list & queue
+static std::function commandQueueReleaseCallback = nullptr;
+static std::function executeCommandListCallback = nullptr;
+
+
static int64_t GetTicks()
{
LARGE_INTEGER ticks;
@@ -43,16 +49,14 @@ static int64_t GetTicks()
return ticks.QuadPart;
}
-static void HookToCommandList(ID3D12GraphicsCommandList* InCmdList);
-static void HookToDevice(ID3D12Device* InDevice);
-
static void hkSetComputeRootSignature(ID3D12GraphicsCommandList* commandList, ID3D12RootSignature* pRootSignature)
{
- if (!contextRendering && commandList != nullptr && pRootSignature != nullptr)
+ if (Config::Instance()->RestoreComputeSignature.value_or(false) &&
+ commandList != nullptr && pRootSignature != nullptr && (lastEvalTime == 0 || lastEvalTime == evalStartTime))
{
sigatureMutex.lock();
rootSigCompute = pRootSignature;
- computeTime = GetTicks();
+ computeRSTime = GetTicks();
sigatureMutex.unlock();
}
@@ -61,11 +65,12 @@ static void hkSetComputeRootSignature(ID3D12GraphicsCommandList* commandList, ID
static void hkSetGraphicRootSignature(ID3D12GraphicsCommandList* commandList, ID3D12RootSignature* pRootSignature)
{
- if (!contextRendering && commandList != nullptr && pRootSignature != nullptr)
+ if (Config::Instance()->RestoreGraphicSignature.value_or(false) &&
+ commandList != nullptr && pRootSignature != nullptr && (lastEvalTime == 0 || lastEvalTime == evalStartTime))
{
sigatureMutex.lock();
rootSigGraphic = pRootSignature;
- graphTime = GetTicks();
+ graphRSTime = GetTicks();
sigatureMutex.unlock();
}
@@ -122,7 +127,7 @@ static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDes
return o_CreateSampler(device, &newDesc, DestDescriptor);
}
-static HRESULT WINAPI hkD3D12CreateDevice(IUnknown* pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid, void** ppDevice)
+static HRESULT hkD3D12CreateDevice(IUnknown* pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid, void** ppDevice)
{
auto result = o_D3D12CreateDevice(pAdapter, MinimumFeatureLevel, riid, ppDevice);
@@ -137,50 +142,25 @@ static HRESULT WINAPI hkD3D12CreateDevice(IUnknown* pAdapter, D3D_FEATURE_LEVEL
return result;
}
-static void WINAPI hkExecuteCommandLists(ID3D12CommandQueue* pCommandQueue, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
+static void hkExecuteCommandLists(ID3D12CommandQueue* pCommandQueue, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
{
- // TODO: Continue from here to Dx12 Overlay Menu stuff
- //
- //if (_cqDx12 == nullptr && _dlssCommandList != nullptr)
- //{
- // // trying to find command list for dlss,
- // // it should be native dx12 cq
- // for (size_t i = 0; i < NumCommandLists; i++)
- // {
- // if (ppCommandLists[i] == _dlssCommandList)
- // {
- // LOG_INFO("new _cqDx12: {0:X}", (ULONG64)pCommandQueue);
- // _cqDx12 = pCommandQueue;
- // break;
- // }
- // }
- //}
+ if (executeCommandListCallback != nullptr)
+ executeCommandListCallback(pCommandQueue, NumCommandLists, ppCommandLists);
return o_ExecuteCommandLists(pCommandQueue, NumCommandLists, ppCommandLists);
}
-static ULONG WINAPI hkCommandQueueRelease(IUnknown* This)
+static ULONG hkCommandQueueRelease(IUnknown* This)
{
auto result = o_CommandQueueRelease(This);
- // TODO: Continue from here to Dx12 Overlay Menu stuff
-
- //if (result == 0)
- //{
- // if (This == _cqDx12)
- // _cqDx12 = nullptr;
- // else if (This == _cqFsr3Mod)
- // _cqFsr3Mod = nullptr;
- // else if (This == _cqFsr3Native)
- // _cqFsr3Native = nullptr;
- // else if (This == _cqSL)
- // _cqSL = nullptr;
- //}
+ if (commandQueueReleaseCallback != nullptr)
+ commandQueueReleaseCallback(This);
return result;
}
-static HRESULT WINAPI hkCreateCommandQueue(ID3D12Device* This, const D3D12_COMMAND_QUEUE_DESC* pDesc, REFIID riid, void** ppCommandQueue)
+static HRESULT hkCreateCommandQueue(ID3D12Device* This, const D3D12_COMMAND_QUEUE_DESC* pDesc, REFIID riid, void** ppCommandQueue)
{
auto result = o_CreateCommandQueue(This, pDesc, riid, ppCommandQueue);
@@ -189,7 +169,7 @@ static HRESULT WINAPI hkCreateCommandQueue(ID3D12Device* This, const D3D12_COMMA
auto commandQueue = (ID3D12CommandQueue*)*ppCommandQueue;
PVOID* pVTable = *(PVOID**)commandQueue;
- o_CommandQueueRelease = (PFN_Release)pVTable[2];
+ o_CommandQueueRelease = (PFN_CommandQueueRelease)pVTable[2];
o_ExecuteCommandLists = (PFN_ExecuteCommandLists)pVTable[10];
if (o_ExecuteCommandLists != nullptr || o_CommandQueueRelease != nullptr)
@@ -326,7 +306,7 @@ void Hooks::DetachDx12Hooks()
void Hooks::ContextEvaluateStart()
{
- evaluateStart = GetTicks();
+ evalStartTime = GetTicks();
}
void Hooks::ContextEvaluateStop(ID3D12GraphicsCommandList* InCmdList, bool InRestore)
@@ -335,38 +315,35 @@ void Hooks::ContextEvaluateStop(ID3D12GraphicsCommandList* InCmdList, bool InRes
{
sigatureMutex.lock();
- if (Config::Instance()->RestoreComputeSignature.value_or(false) && computeTime != 0 && computeTime > lastEvalTime && computeTime <= evaluateStart && rootSigCompute != nullptr)
+ if (Config::Instance()->RestoreComputeSignature.value_or(false) && computeRSTime != 0 &&
+ computeRSTime > lastEvalTime && computeRSTime <= evalStartTime && rootSigCompute != nullptr)
{
LOG_TRACE("restore orgComputeRootSig: {0:X}", (UINT64)rootSigCompute);
o_SetComputeRootSignature(InCmdList, rootSigCompute);
}
- else
+ else if (Config::Instance()->RestoreComputeSignature.value_or(false))
+
{
- if (Config::Instance()->RestoreComputeSignature.value_or(false))
- {
- LOG_TRACE("orgComputeRootSig lastEvalTime: {0}", lastEvalTime);
- LOG_TRACE("orgComputeRootSig computeTime: {0}", computeTime);
- LOG_TRACE("orgComputeRootSig evaluateStart: {0}", evaluateStart);
- }
+ LOG_TRACE("orgComputeRootSig lastEvalTime: {0}", lastEvalTime);
+ LOG_TRACE("orgComputeRootSig computeRSTime: {0}", computeRSTime);
+ LOG_TRACE("orgComputeRootSig evalStartTime: {0}", evalStartTime);
}
- if (Config::Instance()->RestoreGraphicSignature.value_or(false) && graphTime != 0 && graphTime > lastEvalTime && graphTime <= evaluateStart && rootSigGraphic != nullptr)
+ if (Config::Instance()->RestoreGraphicSignature.value_or(false) &&
+ graphRSTime != 0 && graphRSTime > lastEvalTime && graphRSTime <= evalStartTime && rootSigGraphic != nullptr)
{
LOG_TRACE("restore orgGraphicRootSig: {0:X}", (UINT64)rootSigGraphic);
o_SetGraphicRootSignature(InCmdList, rootSigGraphic);
}
- else
+ else if (Config::Instance()->RestoreGraphicSignature.value_or(false))
{
- if (Config::Instance()->RestoreGraphicSignature.value_or(false))
- {
- LOG_TRACE("orgGraphicRootSig lastEvalTime: {0}", lastEvalTime);
- LOG_TRACE("orgGraphicRootSig computeTime: {0}", graphTime);
- LOG_TRACE("orgGraphicRootSig evaluateStart: {0}", evaluateStart);
- }
+
+ LOG_TRACE("orgGraphicRootSig lastEvalTime: {0}", lastEvalTime);
+ LOG_TRACE("orgGraphicRootSig computeRSTime: {0}", graphRSTime);
+ LOG_TRACE("orgGraphicRootSig evalStartTime: {0}", evalStartTime);
}
- contextRendering = false;
- lastEvalTime = evaluateStart;
+ lastEvalTime = evalStartTime;
rootSigCompute = nullptr;
rootSigGraphic = nullptr;
@@ -375,12 +352,17 @@ void Hooks::ContextEvaluateStop(ID3D12GraphicsCommandList* InCmdList, bool InRes
}
}
-void Hooks::ContextRenderingStart()
+bool Hooks::IsDeviceCaptured()
{
- contextRendering = true;
+ return o_D3D12CreateDevice != nullptr;
}
-void Hooks::ContextRenderingStop()
+void Hooks::SetCommandQueueReleaseCallback(std::function InCallback)
{
- contextRendering = false;
-}
\ No newline at end of file
+ commandQueueReleaseCallback = InCallback;
+}
+
+void Hooks::SetExecuteCommandListCallback(std::function InCallback)
+{
+ executeCommandListCallback = InCallback;
+}
diff --git a/OptiScaler/hooks/Dx12_Hooks.h b/OptiScaler/hooks/Dx12_Hooks.h
index 6f670841..81a5661f 100644
--- a/OptiScaler/hooks/Dx12_Hooks.h
+++ b/OptiScaler/hooks/Dx12_Hooks.h
@@ -1,4 +1,5 @@
#pragma once
+#include "../pch.h"
#include
@@ -10,6 +11,8 @@ namespace Hooks
void ContextEvaluateStart();
void ContextEvaluateStop(ID3D12GraphicsCommandList* InCmdList, bool InRestore);
- void ContextRenderingStart();
- void ContextRenderingStop();
+ bool IsDeviceCaptured();
+
+ void SetCommandQueueReleaseCallback(std::function InCallback);
+ void SetExecuteCommandListCallback(std::function InCallback);
}
\ No newline at end of file
diff --git a/OptiScaler/hooks/Dxgi_Hooks.cpp b/OptiScaler/hooks/Dxgi_Hooks.cpp
index 5c1056e8..6b24a0a4 100644
--- a/OptiScaler/hooks/Dxgi_Hooks.cpp
+++ b/OptiScaler/hooks/Dxgi_Hooks.cpp
@@ -1,16 +1,24 @@
#include "Dxgi_Hooks.h"
-#include "../pch.h"
#include "../exports/Dxgi.h"
#include "../detours/detours.h"
-typedef HRESULT(WINAPI* PFN_CREATE_DXGI_FACTORY)(REFIID riid, _COM_Outptr_ void** ppFactory);
-typedef HRESULT(WINAPI* PFN_CREATE_DXGI_FACTORY_2)(UINT Flags, REFIID riid, _COM_Outptr_ void** ppFactory);
+typedef HRESULT(*PFN_CreateSwapChain)(IDXGIFactory*, IUnknown*, DXGI_SWAP_CHAIN_DESC*, IDXGISwapChain**);
+typedef HRESULT(*PFN_CreateSwapChainForHwnd)(IDXGIFactory*, IUnknown*, HWND, const DXGI_SWAP_CHAIN_DESC1*, const DXGI_SWAP_CHAIN_FULLSCREEN_DESC*, IDXGIOutput*, IDXGISwapChain1**);
+typedef HRESULT(*PFN_CreateSwapChainForCoreWindow)(IDXGIFactory*, IUnknown*, IUnknown*, const DXGI_SWAP_CHAIN_DESC1*, IDXGIOutput*, IDXGISwapChain1**);
+typedef HRESULT(*PFN_CreateSwapChainForComposition)(IDXGIFactory*, IUnknown*, const DXGI_SWAP_CHAIN_DESC1*, IDXGIOutput*, IDXGISwapChain1**);
static PFN_CREATE_DXGI_FACTORY o_CreateDxgiFactory = nullptr;
static PFN_CREATE_DXGI_FACTORY o_CreateDxgiFactory1 = nullptr;
static PFN_CREATE_DXGI_FACTORY_2 o_CreateDxgiFactory2 = nullptr;
+static PFN_CreateSwapChain o_CreateSwapChain = nullptr;
+static PFN_CreateSwapChainForHwnd o_CreateSwapChainForHwnd = nullptr;
+static PFN_CreateSwapChainForComposition o_CreateSwapChainForComposition = nullptr;
+static PFN_CreateSwapChainForCoreWindow o_CreateSwapChainForCoreWindow = nullptr;
+
+static std::function createSwapChainCallback = nullptr;
+
void Hooks::AttachDxgiHooks()
{
if (o_CreateDxgiFactory != nullptr || o_CreateDxgiFactory1 != nullptr || o_CreateDxgiFactory2 != nullptr)
diff --git a/OptiScaler/hooks/Dxgi_Hooks.h b/OptiScaler/hooks/Dxgi_Hooks.h
index 0abd7281..713b7ead 100644
--- a/OptiScaler/hooks/Dxgi_Hooks.h
+++ b/OptiScaler/hooks/Dxgi_Hooks.h
@@ -1,7 +1,14 @@
#pragma once
+#include "../pch.h"
+#include "../enums/Enums.h"
+
+#include
namespace Hooks
{
void AttachDxgiHooks();
void DetachDxgiHooks();
+
+ void DxgiClean(std::function);
+ void DxgiPresent(std::function);
}
diff --git a/OptiScaler/imgui/wrapped_swapchain.cpp b/OptiScaler/hooks/proxies/Wrapped_SwapChain.cpp
similarity index 75%
rename from OptiScaler/imgui/wrapped_swapchain.cpp
rename to OptiScaler/hooks/proxies/Wrapped_SwapChain.cpp
index 82753534..6e0fb49e 100644
--- a/OptiScaler/imgui/wrapped_swapchain.cpp
+++ b/OptiScaler/hooks/proxies/Wrapped_SwapChain.cpp
@@ -1,17 +1,19 @@
-#include "wrapped_swapchain.h"
+#include "Wrapped_SwapChain.h"
// Used RenderDoc's wrapped object as referance
// https://github.com/baldurk/renderdoc/blob/v1.x/renderdoc/driver/dxgi/dxgi_wrapped.cpp
-WrappedIDXGISwapChain4::WrappedIDXGISwapChain4(IDXGISwapChain* real,
- std::function renderTrig,
- std::function renderTrig1,
- std::function clearTrig) : m_pReal(real), RenderTrig(renderTrig), RenderTrig1(renderTrig1), ClearTrig(clearTrig), m_iRefcount(1)
+WrappedIDXGISwapChain4::WrappedIDXGISwapChain4(IDXGISwapChain* InRealSwapChain,
+ std::function* InPresentTrig,
+ std::function* InPresentTrig1,
+ std::function* InClearTrig,
+ HWND* InMenuHandle) : m_pReal(InRealSwapChain), PresentTrig(InPresentTrig), PresentTrig1(InPresentTrig1),
+ ClearTrig(InClearTrig), m_iRefcount(1), menuHandle(InMenuHandle)
{
- real->QueryInterface(__uuidof(IDXGISwapChain1), (void**)&m_pReal1);
- real->QueryInterface(__uuidof(IDXGISwapChain2), (void**)&m_pReal2);
- real->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&m_pReal3);
- real->QueryInterface(__uuidof(IDXGISwapChain4), (void**)&m_pReal4);
+ m_pReal->QueryInterface(IID_PPV_ARGS(&m_pReal1));
+ m_pReal->QueryInterface(IID_PPV_ARGS(&m_pReal2));
+ m_pReal->QueryInterface(IID_PPV_ARGS(&m_pReal3));
+ m_pReal->QueryInterface(IID_PPV_ARGS(&m_pReal4));
}
WrappedIDXGISwapChain4::~WrappedIDXGISwapChain4()
@@ -115,8 +117,8 @@ HRESULT WrappedIDXGISwapChain4::ResizeBuffers(UINT BufferCount, UINT Width, UINT
{
LOG_FUNC();
- if (ClearTrig != nullptr)
- ClearTrig(false);
+ if (*ClearTrig != nullptr)
+ (*ClearTrig)(false);
HRESULT ret = m_pReal->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags);
@@ -134,8 +136,8 @@ HRESULT WrappedIDXGISwapChain4::ResizeBuffers1(UINT BufferCount, UINT Width, UIN
{
LOG_FUNC();
- if (ClearTrig != nullptr)
- ClearTrig(false);
+ if (*ClearTrig != nullptr)
+ (*ClearTrig)(false);
HRESULT ret = m_pReal3->ResizeBuffers1(BufferCount, Width, Height, Format, SwapChainFlags, pCreationNodeMask, ppPresentQueue);
return ret;
@@ -145,8 +147,8 @@ HRESULT WrappedIDXGISwapChain4::SetFullscreenState(BOOL Fullscreen, IDXGIOutput*
{
LOG_FUNC();
- if (ClearTrig != nullptr)
- ClearTrig(true);
+ if (*ClearTrig != nullptr)
+ (*ClearTrig)(true);
return m_pReal->SetFullscreenState(Fullscreen, pTarget);
}
@@ -171,16 +173,16 @@ HRESULT WrappedIDXGISwapChain4::GetDevice(REFIID riid, void** ppDevice)
HRESULT WrappedIDXGISwapChain4::Present(UINT SyncInterval, UINT Flags)
{
- if (RenderTrig != nullptr && m_pReal3 != nullptr)
- RenderTrig(m_pReal3, SyncInterval, Flags);
+ if (*PresentTrig != nullptr && m_pReal3 != nullptr)
+ (*PresentTrig)(m_pReal3, SyncInterval, Flags);
return m_pReal->Present(SyncInterval, Flags);
}
HRESULT WrappedIDXGISwapChain4::Present1(UINT SyncInterval, UINT Flags, const DXGI_PRESENT_PARAMETERS* pPresentParameters)
{
- if (RenderTrig1 != nullptr && m_pReal3 != nullptr)
- RenderTrig1(m_pReal3, SyncInterval, Flags, pPresentParameters);
+ if (*PresentTrig1 != nullptr && m_pReal3 != nullptr)
+ (*PresentTrig1)(m_pReal3, SyncInterval, Flags, pPresentParameters);
return m_pReal1->Present1(SyncInterval, Flags, pPresentParameters);
}
diff --git a/OptiScaler/imgui/wrapped_swapchain.h b/OptiScaler/hooks/proxies/Wrapped_SwapChain.h
similarity index 89%
rename from OptiScaler/imgui/wrapped_swapchain.h
rename to OptiScaler/hooks/proxies/Wrapped_SwapChain.h
index a5af50cc..cd68297c 100644
--- a/OptiScaler/imgui/wrapped_swapchain.h
+++ b/OptiScaler/hooks/proxies/Wrapped_SwapChain.h
@@ -1,7 +1,7 @@
#pragma once
-#include "../pch.h"
-#include "dxgi1_6.h"
-#include "imgui_overlay_base.h"
+#include "../../pch.h"
+
+#include
class WrappedIDXGISwapChain4 : public IDXGISwapChain4
{
@@ -11,18 +11,20 @@ class WrappedIDXGISwapChain4 : public IDXGISwapChain4
IDXGISwapChain3* m_pReal3 = nullptr;
IDXGISwapChain4* m_pReal4 = nullptr;
- std::function RenderTrig = nullptr;
- std::function RenderTrig1 = nullptr;
- std::function ClearTrig = nullptr;
+ HWND* menuHandle = nullptr;
+
+ std::function* PresentTrig = nullptr;
+ std::function* PresentTrig1 = nullptr;
+ std::function* ClearTrig = nullptr;
unsigned int m_iRefcount;
public:
-
- WrappedIDXGISwapChain4(IDXGISwapChain* real,
- std::function renderTrig,
- std::function renderTrig1,
- std::function clearTrig);
+ WrappedIDXGISwapChain4(IDXGISwapChain* InRealSwapChain,
+ std::function* InPresentTrig,
+ std::function* InPresentTrig1,
+ std::function* InClearTrig,
+ HWND* InMenuHandle);
virtual ~WrappedIDXGISwapChain4();
@@ -36,15 +38,15 @@ public:
ULONG STDMETHODCALLTYPE Release()
{
- unsigned int ret = InterlockedDecrement(&m_iRefcount);
+ auto ret = InterlockedDecrement(&m_iRefcount);
if (ret == 0)
{
HWND hwnd = nullptr;
m_pReal1->GetHwnd(&hwnd);
- if (ClearTrig != nullptr && hwnd == ImGuiOverlayBase::Handle())
- ClearTrig(true);
+ if (*ClearTrig != nullptr && hwnd == *menuHandle)
+ (*ClearTrig)(true);
delete this;
}
diff --git a/OptiScaler/imgui/ImTerm/misc.hpp b/OptiScaler/imgui/ImTerm/misc.hpp
new file mode 100644
index 00000000..8a7d3c5d
--- /dev/null
+++ b/OptiScaler/imgui/ImTerm/misc.hpp
@@ -0,0 +1,253 @@
+#ifndef IMTERM_MISC_HPP
+#define IMTERM_MISC_HPP
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Copyright C 2019, Lucas Lazare ///
+/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation ///
+/// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, ///
+/// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software ///
+/// is furnished to do so, subject to the following conditions: ///
+/// ///
+/// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ///
+/// ///
+/// The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the ///
+/// warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or ///
+/// copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, ///
+/// arising from, out of or in connection with the software or the use or other dealings in the Software. ///
+/// ///
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+#include
+#include
+#include
+#include
+
+namespace misc {
+
+ // std::identity is c++20
+ struct identity {
+ template
+ constexpr T&& operator()(T&& t) const {
+ return std::forward(t);
+ }
+ };
+
+ namespace details {
+ struct structured_void {};
+ inline structured_void no_value{};
+
+ template
+ struct non_void {
+ using type = T;
+ };
+ template <>
+ struct non_void {
+ using type = structured_void;
+ };
+ }
+ // type T if T is non void, details::structured void otherwise
+ template
+ using non_void_t = typename details::non_void::type;
+
+
+ // Returns the length of the given byte string, at most buffer_size
+ constexpr unsigned int strnlen(const char* beg, unsigned int buffer_size) {
+ unsigned int len = 0;
+ while (len < buffer_size && beg[len] != '\0') {
+ ++len;
+ }
+ return len;
+ }
+
+ // std::is_sorted is not constexpr pre C++20
+ template ())>>>
+ constexpr bool is_sorted(ForwardIt it, EndIt last, Comparator&& comp = {}) {
+ if (it == last) {
+ return true;
+ }
+
+ for (ForwardIt next = std::next(it) ; next != last ; ++next, ++it) {
+ if (comp(*next, *it)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // returns the length of the longest element of the list, minimum 0
+ template
+ constexpr auto max_size(ForwardIt it, EndIt last, SizeExtractor&& size_of) -> decltype(size_of(*it)){
+ using size_type = decltype(size_of(*it));
+ size_type max_size = 0u;
+ while (it != last) {
+ size_type current_size = size_of(*it++);
+ if (current_size > max_size) {
+ max_size = current_size;
+ }
+ }
+ return max_size;
+ }
+
+ // copies until it reaches the end of any of the two collections
+ template
+ constexpr void copy(ForwardIt src_beg, ForwardIt src_end, OutputIt dest_beg, OutputIt dest_end) {
+ while(src_beg != src_end && dest_beg != dest_end) {
+ *dest_beg++ = *src_beg++;
+ }
+ }
+
+ // same as misc::copy, but in reversed order
+ template
+ constexpr void copy_backward(BidirIt1 src_beg, BidirIt1 src_end, BidirIt2 dest_beg, BidirIt2 dest_end) {
+ auto copy_length = std::distance(src_beg, src_end);
+ auto avail_length = std::distance(dest_beg, dest_end);
+ if (avail_length < copy_length) {
+ std::advance(src_end, avail_length - copy_length);
+ } else {
+ std::advance(dest_end, copy_length - avail_length);
+ }
+ while(src_beg != src_end && dest_beg != dest_end) {
+ *--dest_end = *--src_end;
+ }
+ }
+
+ // Returns new end of dest collection
+ // ignores the n first values of the destination
+ template
+ constexpr RandomAccessIt erase_insert(ForwardIt src_beg, ForwardIt src_end, RandomAccessIt dest_beg, RandomAccessIt dest_end, RandomAccessIt dest_max, unsigned int n) {
+ n = std::min(static_cast(std::distance(dest_beg, dest_end)), n);
+ auto copy_length = static_cast(std::distance(src_beg, src_end));
+ auto avail_length = static_cast(std::distance(dest_end, dest_max)) + n;
+
+ if (copy_length <= avail_length) {
+ misc::copy_backward(dest_beg + n, dest_end, dest_beg + copy_length, dest_end + copy_length);
+ misc::copy(src_beg, src_end, dest_beg, dest_beg + copy_length);
+ return dest_end + copy_length - n;
+
+ } else {
+ std::advance(src_beg, copy_length - avail_length);
+ copy_length = avail_length;
+ misc::copy_backward(dest_beg + n, dest_end, dest_beg + copy_length, dest_end + copy_length);
+ misc::copy(src_beg, src_end, dest_beg, dest_beg + copy_length);
+ return dest_end + copy_length - n;
+ }
+ }
+
+ // returns the last element in the range [begin, end) that is equal to val, returns end if there is no such element
+ template
+ constexpr ForwardIterator find_last(ForwardIterator begin, ForwardIterator end, const ValueType& val) {
+ auto rend = std::reverse_iterator(begin);
+ auto rbegin = std::reverse_iterator(end);
+ auto search = std::find(rbegin, rend, val);
+ if (search == rend) {
+ return end;
+ }
+ return std::prev(search.base());
+ }
+
+ // Returns an iterator to the first character that has no a space after him
+ template
+ constexpr ForwardIterator find_terminating_word(ForwardIterator begin, ForwardIterator end, SpaceDetector&& is_space_pred) {
+ auto rend = std::reverse_iterator(begin);
+ auto rbegin = std::reverse_iterator(end);
+
+ int sp_size = 0;
+ auto is_space = [&sp_size, &is_space_pred, &end] (char c) {
+ sp_size = is_space_pred(std::string_view{&c, static_cast(&*std::prev(end) - &c)});
+ return sp_size > 0;
+ };
+
+ auto search = std::find_if(rbegin, rend, is_space);
+ if (search == rend) {
+ return begin;
+ }
+ ForwardIterator it = std::prev(search.base());
+ it += sp_size;
+ return it;
+ }
+
+ constexpr bool success(std::errc ec) {
+ return ec == std::errc{};
+ }
+
+ // Search any element starting by "prefix" in the sorted collection formed by [c_beg, c_end)
+ // str_ext must map dectype(*c_beg) to std::string_view
+ // transform is whatever transformation you want to do to the matching elements.
+ template
+ auto prefix_search(std::string_view prefix, ForwardIt c_beg, ForwardIt c_end,
+ StrExtractor&& str_ext = {}, Transform&& transform = {}) -> std::vector> {
+
+ auto lower = std::lower_bound(c_beg, c_end, prefix);
+ auto higher = std::upper_bound(lower, c_end, prefix, [&str_ext](std::string_view pre, const auto& element) {
+ std::string_view val = str_ext(element);
+ return pre.substr(0, std::min(val.size(), pre.size())) < val.substr(0, std::min(val.size(), pre.size()));
+ });
+
+ std::vector> ans;
+ std::transform(lower, higher, std::back_inserter(ans), std::forward(transform));
+ return ans;
+ }
+
+ // returns an iterator to the first element starting by "prefix"
+ // is_space is a predicate returning a value greater than 0 if a given string_view starts by a space and 0 otherwise
+ // str_ext is an unary functor maping decltype(*beg) to std::string_view
+ template
+ ForwardIt find_first_prefixed(std::string_view prefix, ForwardIt beg, ForwardIt end, IsSpace&& is_space, StrExtractor&& str_ext = {}) {
+ // std::string_view::start_with is C++20
+ auto start_with = [&](std::string_view str, std::string_view pr) {
+ std::string_view::size_type idx = 0;
+ int space_count{};
+ while (idx < str.size() && (space_count = is_space(str.substr(idx))) > 0) {
+ idx += space_count;
+ }
+ return (str.size() - idx) >= pr.size() ? str.substr(idx, pr.size()) == pr : false;
+ };
+ while (beg != end) {
+ if (start_with(str_ext(*beg), prefix)) {
+ return beg;
+ }
+ ++beg;
+ }
+ return beg;
+ }
+
+
+ namespace details {
+ template typename Op, typename... Args>
+ struct detector : std::false_type {
+ using type = std::is_same;
+ };
+
+ template typename Op, typename... Args>
+ struct detector>, Op, Args...> : std::true_type {
+ using type = Op;
+ };
+ }
+
+ template typename Op, typename... Args>
+ using is_detected = typename details::detector;
+
+ template typename Op, typename... Args>
+ using is_detected_t = typename is_detected ::type;
+
+ // compile time function detection, return type agnostic
+ template typename Op, typename... Args>
+ constexpr bool is_detected_v = is_detected::value;
+
+ // compile time function detection
+ template typename Op, typename ReturnType, typename... Args>
+ constexpr bool is_detected_with_return_type_v = std::is_same_v, ReturnType>;
+
+ // dummy mutex
+ struct no_mutex {
+ constexpr no_mutex() noexcept = default;
+ constexpr void lock() {}
+ constexpr void unlock() {}
+ constexpr bool try_lock() { return true; }
+ };
+}
+
+#endif //IMTERM_MISC_HPP
diff --git a/OptiScaler/imgui/ImTerm/terminal.hpp b/OptiScaler/imgui/ImTerm/terminal.hpp
new file mode 100644
index 00000000..a4e38cd3
--- /dev/null
+++ b/OptiScaler/imgui/ImTerm/terminal.hpp
@@ -0,0 +1,485 @@
+#ifndef IMTERM_TERMINAL_HPP
+#define IMTERM_TERMINAL_HPP
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Copyright C 2019, Lucas Lazare ///
+/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation ///
+/// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, ///
+/// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software ///
+/// is furnished to do so, subject to the following conditions: ///
+/// ///
+/// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ///
+/// ///
+/// The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the ///
+/// warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or ///
+/// copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, ///
+/// arising from, out of or in connection with the software or the use or other dealings in the Software. ///
+/// ///
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "utils.hpp"
+#include "misc.hpp"
+
+#ifdef IMTERM_USE_FMT
+#include "fmt/format.h"
+#endif
+
+namespace ImTerm {
+
+ // checking that you can use a given class as a TerminalHelper
+ // giving human-friendlier error messages than just letting the compiler explode
+ namespace details {
+ template
+ struct assert_wellformed {
+
+ template
+ using find_commands_by_prefix_method_v1 =
+ decltype(std::declval().find_commands_by_prefix(std::declval()));
+
+ template
+ using find_commands_by_prefix_method_v2 =
+ decltype(std::declval().find_commands_by_prefix(std::declval(),
+ std::declval()));
+
+ template
+ using list_commands_method = decltype(std::declval().list_commands());
+
+ template
+ using format_method = decltype(std::declval().format(std::declval(), std::declval()));
+
+ static_assert(
+ misc::is_detected_with_return_type_v, TerminalHelper>,
+ "TerminalHelper should implement the method 'std::vector find_command_by_prefix(std::string_view)'. "
+ "See term::terminal_helper_example for reference");
+ static_assert(
+ misc::is_detected_with_return_type_v, TerminalHelper>,
+ "TerminalHelper should implement the method 'std::vector find_command_by_prefix(const char*, const char*)'. "
+ "See term::terminal_helper_example for reference");
+ static_assert(
+ misc::is_detected_with_return_type_v, TerminalHelper>,
+ "TerminalHelper should implement the method 'std::vector list_commands()'. "
+ "See term::terminal_helper_example for reference");
+ static_assert(
+ misc::is_detected_with_return_type_v, TerminalHelper>,
+ "TerminalHelper should implement the method 'std::optional format(std::string, term::message::type)'. "
+ "See term::terminal_helper_example for reference");
+ };
+ }
+
+ template
+ class terminal {
+ using buffer_type = std::array;
+ using small_buffer_type = std::array;
+ public:
+ using value_type = misc::non_void_t;
+ using command_type = command_t>;
+ using command_type_cref = std::reference_wrapper;
+ using argument_type = argument_t;
+
+ using terminal_helper_is_valid = details::assert_wellformed;
+
+ inline static const std::vector DEFAULT_ORDER = {config_panels::clearbutton,
+ config_panels::autoscroll, config_panels::autowrap, config_panels::long_filter, config_panels::loglevel};
+
+ // You shall call this constructor you used a non void value_type
+ template >>
+ explicit terminal(value_type& arg_value, const char * window_name_ = "terminal", int base_width_ = 900,
+ int base_height_ = 200, std::shared_ptr th = std::make_shared())
+ : terminal(arg_value, window_name_, base_width_, base_height_, std::move(th), terminal_helper_is_valid{}) {}
+
+
+ // You shall call this constructor you used a void value_type
+ template >>
+ explicit terminal(const char * window_name_ = "terminal", int base_width_ = 900,
+ int base_height_ = 200, std::shared_ptr th = std::make_shared())
+ : terminal(misc::details::no_value, window_name_, base_width_, base_height_, std::move(th), terminal_helper_is_valid{}) {}
+
+ // Returns the underlying terminal helper
+ std::shared_ptr get_terminal_helper() {
+ return m_t_helper;
+ }
+
+ // shows the terminal. Call at each frame (in a more ImGui style, this would be something like ImGui::terminal(....);
+ // returns true if the terminal thinks it should still be displayed next frame, false if it thinks it should be hidden
+ // return value is true except if a command required a close, or if the "escape" key was pressed.
+ bool show(const std::vector& panels_order = DEFAULT_ORDER) noexcept;
+
+ // returns the command line history
+ const std::vector& get_history() const noexcept {
+ return m_command_history;
+ }
+
+ // if invoked, the next call to "show" will return false
+ void set_should_close() noexcept {
+ m_close_request = true;
+ }
+
+ // clears all theme's optionals
+ void reset_colors() noexcept;
+
+ // returns current theme
+ struct theme& theme() {
+ return m_colors;
+ }
+
+ // set whether the autocompletion OSD should be above/under the text input, or if it should be disabled
+ void set_autocomplete_pos(position p) {
+ m_autocomplete_pos = p;
+ }
+
+ // returns current autocompletion position
+ position get_autocomplete_pos() const {
+ return m_autocomplete_pos;
+ }
+
+#ifdef IMTERM_USE_FMT
+ // logs a colorless text to the message panel
+ // added as terminal message with info severity
+ template
+ void add_formatted(const char* fmt, Args&&... args) {
+ add_text(fmt::format(fmt, std::forward(args)...));
+ }
+
+ // logs a colorless text to the message panel
+ // added as terminal message with warn severity
+ template
+ void add_formatted_err(const char* fmt, Args&&... args) {
+ add_text_err(fmt::format(fmt, std::forward(args)...));
+ }
+#endif
+
+ // logs a text to the message panel
+ // added as terminal message with info severity
+ void add_text(std::string str, unsigned int color_beg, unsigned int color_end);
+
+ // logs a text to the message panel, color spans from color_beg to the end of the message
+ // added as terminal message with info severity
+ void add_text(std::string str, unsigned int color_beg) {
+ add_text(str, color_beg, static_cast(str.size()));
+ }
+
+ // logs a colorless text to the message panel
+ // added as a terminal message with info severity,
+ void add_text(std::string str) {
+ add_text(str, 0, 0);
+ }
+
+ // logs a text to the message panel
+ // added as terminal message with warn severity
+ void add_text_err(std::string str, unsigned int color_beg, unsigned int color_end);
+
+ // logs a text to the message panel, color spans from color_beg to the end of the message
+ // added as terminal message with warn severity
+ void add_text_err(std::string str, unsigned int color_beg) {
+ add_text_err(str, color_beg, static_cast(str.size()));
+ }
+
+ // logs a colorless text to the message panel
+ // added as terminal message with warn severity
+ void add_text_err(std::string str) {
+ add_text_err(str, 0, 0);
+ }
+
+ // logs a message to the message panel
+ void add_message(const message& msg) {
+ add_message(message{msg});
+ }
+ void add_message(message&& msg);
+
+ // clears the message panel
+ void clear();
+
+ message::severity::severity_t log_level() noexcept {
+ return static_cast(m_level + static_cast(m_lowest_log_level_val));
+ }
+
+ void log_level(message::severity::severity_t new_level) noexcept {
+ if (m_lowest_log_level_val > new_level) {
+ set_min_log_level(new_level);
+ }
+ m_level = new_level - m_lowest_log_level_val;
+ }
+
+ // returns the text used to label the button that clears the message panel
+ // set it to an empty optional if you don't want the button to be displayed
+ std::optional& clear_text() noexcept {
+ return m_clear_text;
+ }
+
+ // returns the text used to label the checkbox enabling or disabling message panel auto scrolling
+ // set it to an empty optional if you don't want the checkbox to be displayed
+ std::optional& autoscroll_text() noexcept {
+ return m_autoscroll_text;
+ }
+
+ // returns the text used to label the checkbox enabling or disabling message panel text auto wrap
+ // set it to an empty optional if you don't want the checkbox to be displayed
+ std::optional& autowrap_text() noexcept {
+ return m_autowrap_text;
+ }
+
+ // returns the text used to label the drop down list used to select the minimum severity to be displayed
+ // set it to an empty optional if you don't want the drop down list to be displayed
+ std::optional& log_level_text() noexcept {
+ return m_log_level_text;
+ }
+
+ // returns the text used to label the text input used to filter out logs
+ // set it to an empty optional if you don't want the filter to be displayed
+ std::optional& filter_hint() noexcept {
+ return m_filter_hint;
+ }
+
+ // allows you to set the text in the log_level drop down list
+ // the std::string_view/s are copied, so you don't need to manage their life-time
+ // set log_level_text() to an empty optional if you want to disable the drop down list
+ void set_level_list_text(std::string_view trace_str, std::string_view debug_str, std::string_view info_str,
+ std::string_view warn_str, std::string_view err_str, std::string_view critical_str, std::string_view none_str);
+
+ // sets the maximum verbosity a user can set in the terminal with the log_level drop down list
+ // for instance, if you pass 'info', the user will be able to select 'info','warning','error', 'critical', and 'none',
+ // but will never be able to view 'trace' and 'debug' messages
+ void set_min_log_level(message::severity::severity_t level);
+
+ // Adds custom flags to the terminal window
+ void set_flags(ImGuiWindowFlags flags) noexcept {
+ m_flags = flags;
+ }
+
+ // Sets the maximum number of saved messages
+ void set_max_log_len(std::vector::size_type max_size);
+
+ // Sets the size of the terminal
+ void set_size(unsigned int x, unsigned int y) noexcept {
+ set_width(x);
+ set_height(y);
+ }
+
+ void set_size(ImVec2 sz) noexcept {
+ assert(sz.x >= 0);
+ assert(sz.y >= 0);
+ set_size(static_cast(sz.x), static_cast(sz.y));
+ }
+
+ void set_width(unsigned int x) noexcept {
+ m_base_width = x;
+ m_update_width = true;
+ }
+
+ void set_height(unsigned int y) noexcept {
+ m_base_height = y;
+ m_update_height = true;
+ }
+
+ // Get last window size
+ ImVec2 get_size() const noexcept {
+ return m_current_size;
+ }
+
+ // Allows / disallow resize on a given axis
+ void allow_x_resize() noexcept {
+ m_allow_x_resize = true;
+ }
+
+ void allow_y_resize() noexcept {
+ m_allow_y_resize = true;
+ }
+ void disallow_x_resize() noexcept {
+ m_allow_x_resize = false;
+ }
+
+ void disallow_y_resize() noexcept {
+ m_allow_y_resize = false;
+ }
+ void set_x_resize_allowance(bool allowed) noexcept {
+ m_allow_x_resize = allowed;
+ }
+
+ void set_y_resize_allowance(bool allowed) noexcept {
+ m_allow_y_resize = allowed;
+ }
+
+ // executes a statement, simulating user input
+ // returns false if given string is too long to be interpreted
+ // if true is returned, any text inputed by the user is overridden
+ bool execute(std::string_view str) noexcept {
+ if (str.size() <= m_command_buffer.size()) {
+ std::copy(str.begin(), str.end(), m_command_buffer.begin());
+ m_buffer_usage = str.size();
+ call_command();
+ m_buffer_usage = 0;
+ m_command_buffer[0] = '\0';
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ explicit terminal(value_type& arg_value, const char * window_name_, int base_width_, int base_height_, std::shared_ptr th, terminal_helper_is_valid&&);
+
+ void try_log(std::string_view str, message::type type);
+
+ void compute_text_size() noexcept;
+
+ void display_settings_bar(const std::vector& panels_order) noexcept;
+
+ void display_messages() noexcept;
+
+ void display_command_line() noexcept;
+
+ // displaying command_line itself
+ void show_input_text() noexcept;
+
+ void handle_unfocus() noexcept;
+
+ void show_autocomplete() noexcept;
+
+ void call_command() noexcept;
+
+ void push_message(message&&);
+
+ std::optional resolve_history_reference(std::string_view str, bool& modified) const noexcept;
+
+ std::pair resolve_history_references(std::string_view str, bool& modified) const;
+
+
+ static int command_line_callback_st(ImGuiInputTextCallbackData * data) noexcept;
+
+ int command_line_callback(ImGuiInputTextCallbackData * data) noexcept;
+
+ static int try_push_style(ImGuiCol col, const std::optional& color) {
+ if (color) {
+ ImGui::PushStyleColor(col, *color);
+ return 1;
+ }
+ return 0;
+ }
+
+ static int try_push_style(ImGuiCol col, const std::optional& color) {
+ if (color) {
+ ImGui::PushStyleColor(col, color->imv4());
+ return 1;
+ }
+ return 0;
+ }
+
+
+ int is_space(std::string_view str) const;
+
+ bool is_digit(char c) const;
+
+ unsigned long get_length(std::string_view str) const;
+
+ // Returns a vector containing each element that were space separated
+ // Returns an empty optional if a '"' char was not matched with a closing '"',
+ // except if ignore_non_match was set to true
+ std::optional> split_by_space(std::string_view in, bool ignore_non_match = false) const;
+
+ inline void try_lock()
+ {
+ while (m_flag.test_and_set(std::memory_order_seq_cst)) {}
+ }
+
+ inline void try_unlock()
+ {
+ m_flag.clear(std::memory_order_seq_cst);
+ }
+
+ ////////////
+
+ value_type& m_argument_value;
+ mutable std::shared_ptr m_t_helper;
+
+ bool m_should_show_next_frame{true};
+ bool m_close_request{false};
+
+ const char * const m_window_name;
+ ImGuiWindowFlags m_flags{ImGuiWindowFlags_None};
+
+ int m_base_width;
+ int m_base_height;
+ bool m_update_width{true};
+ bool m_update_height{true};
+
+ bool m_allow_x_resize{true};
+ bool m_allow_y_resize{true};
+
+ ImVec2 m_current_size{0.f, 0.f};
+
+ struct theme m_colors{};
+
+ // configuration
+ bool m_autoscroll{true}; // TODO: accessors
+ bool m_autowrap{true}; // TODO: accessors
+ std::vector::size_type m_last_size{0u};
+ int m_level{message::severity::trace}; // TODO: accessors
+#ifdef IMTERM_ENABLE_REGEX
+ bool m_regex_search{true}; // TODO: accessors, button
+#endif
+
+ std::optional m_autoscroll_text;
+ std::optional m_clear_text;
+ std::optional m_log_level_text;
+ std::optional m_autowrap_text;
+ std::optional m_filter_hint;
+ std::string m_level_list_text{};
+ const char* m_longest_log_level{nullptr}; // points to the longest log level, in m_level_list_text
+ const char* m_lowest_log_level{nullptr}; // points to the lowest log level possible, in m_level_list_text
+ message::severity::severity_t m_lowest_log_level_val{message::severity::trace};
+
+ small_buffer_type m_log_text_filter_buffer{};
+ small_buffer_type::size_type m_log_text_filter_buffer_usage{0u};
+
+
+ // message panel variables
+ unsigned long m_last_flush_at_history{0u}; // for the [-n] indicator on command line
+ bool m_flush_bit{false};
+ std::vector m_logs{};
+ std::vector::size_type m_max_log_len{5'000}; // TODO: command
+ std::vector::size_type m_current_log_oldest_idx{0};
+
+
+ // command line variables
+ buffer_type m_command_buffer{};
+ buffer_type::size_type m_buffer_usage{0u}; // max accessible: command_buffer[buffer_usage - 1]
+ // (buffer_usage might be 0 for empty string)
+ buffer_type::size_type m_previous_buffer_usage{0u};
+ bool m_should_take_focus{false};
+
+ ImGuiID m_previously_active_id{0u};
+ ImGuiID m_input_text_id{0u};
+
+ // autocompletion
+ std::vector m_current_autocomplete{};
+ std::vector m_current_autocomplete_strings{};
+ std::string_view m_autocomlete_separator{" | "};
+ position m_autocomplete_pos{position::down};
+ bool m_command_entered{false};
+
+ // command line: completion using history
+ std::string m_command_line_backup{};
+ std::string_view m_command_line_backup_prefix{};
+ std::vector m_command_history{};
+ std::optional::iterator> m_current_history_selection{};
+
+ bool m_ignore_next_textinput{false};
+ bool m_has_focus{false};
+
+ std::atomic_flag m_flag;
+ };
+}
+
+#include "terminal.tpp"
+
+#undef IMTERM_FMT_INCLUDED
+
+#endif //IMTERM_TERMINAL_HPP
diff --git a/OptiScaler/imgui/ImTerm/terminal.tpp b/OptiScaler/imgui/ImTerm/terminal.tpp
new file mode 100644
index 00000000..7a9b2853
--- /dev/null
+++ b/OptiScaler/imgui/ImTerm/terminal.tpp
@@ -0,0 +1,1602 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/// ///
+/// Copyright C 2019, Lucas Lazare ///
+/// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation ///
+/// files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, ///
+/// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software ///
+/// is furnished to do so, subject to the following conditions: ///
+/// ///
+/// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ///
+/// ///
+/// The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the ///
+/// warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or ///
+/// copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, ///
+/// arising from, out of or in connection with the software or the use or other dealings in the Software. ///
+/// ///
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include
+#include
+#include
+#include
+#include
+#include