mirror of
https://github.com/optiscaler/OptiScaler.git
synced 2026-08-28 00:56:48 +00:00
stash
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
<IncludePath>$(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)</IncludePath>
|
||||
<LibraryPath>$(ProjectDir)fsr2\lib;$(ProjectDir)fsr2_212\lib;$(ProjectDir)vulkan;$(ProjectDir)d3dx;$(ProjectDir)detours;$(SolutionDir)external\xess\lib;$(LibraryPath)</LibraryPath>
|
||||
<TargetName>dxgi</TargetName>
|
||||
<OutDir>D:\Folders\Games\SteamLibrary\steamapps\common\Horizon Zero Dawn\</OutDir>
|
||||
<OutDir>D:\Folders\Games\Deep Rock Galactic\FSD\Binaries\Win64\</OutDir>
|
||||
<IntDir>.\x64\Debug</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -212,7 +212,12 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
|
||||
<ClInclude Include="exports\Winhttp.h" />
|
||||
<ClInclude Include="exports\Wininet.h" />
|
||||
<ClInclude Include="exports\Winmm.h" />
|
||||
<ClInclude Include="hooks\Dx12_Hooks.h" />
|
||||
<ClInclude Include="hooks\Dxgi_Hooks.h" />
|
||||
<ClInclude Include="enums\Enums.h" />
|
||||
<ClInclude Include="hooks\LoadLibrary_Hooks.h" />
|
||||
<ClInclude Include="hooks\NvApi_Hooks.h" />
|
||||
<ClInclude Include="hooks\Nvngx_Hooks.h" />
|
||||
<ClInclude Include="hooks\Vulkan_Hooks.h" />
|
||||
<ClInclude Include="Working_Mode.h" />
|
||||
<ClInclude Include="output_scaling\OS_Common.h" />
|
||||
@@ -237,7 +242,6 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
|
||||
<ClInclude Include="backends\IFeature.h" />
|
||||
<ClInclude Include="backends\IFeature_Vk.h" />
|
||||
<ClInclude Include="detours\detours.h" />
|
||||
<ClInclude Include="dllmain.h" />
|
||||
<ClInclude Include="imgui\imgui\imconfig.h" />
|
||||
<ClInclude Include="imgui\imgui\imgui.h" />
|
||||
<ClInclude Include="imgui\imgui\imgui_impl_dx11.h" />
|
||||
@@ -256,7 +260,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
|
||||
<ClInclude Include="imgui\imgui_overlay_dx11.h" />
|
||||
<ClInclude Include="imgui\imgui_overlay_dx12.h" />
|
||||
<ClInclude Include="imgui\imgui_overlay_vk.h" />
|
||||
<ClInclude Include="imgui\wrapped_swapchain.h" />
|
||||
<ClInclude Include="hooks\proxies\Wrapped_SwapChain.h" />
|
||||
<ClInclude Include="Logger.h" />
|
||||
<ClInclude Include="NVNGX_Parameter.h" />
|
||||
<ClInclude Include="NVNGX_Proxy.h" />
|
||||
@@ -300,7 +304,12 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
|
||||
<ClCompile Include="backends\fsr2\FSR2Feature_Dx12.cpp" />
|
||||
<ClCompile Include="backends\fsr2\FSR2Feature_Vk.cpp" />
|
||||
<ClCompile Include="backends\IFeature_Dx12.cpp" />
|
||||
<ClCompile Include="exports\Dxgi.cpp" />
|
||||
<ClCompile Include="hooks\Dx12_Hooks.cpp" />
|
||||
<ClCompile Include="hooks\Dxgi_Hooks.cpp" />
|
||||
<ClCompile Include="hooks\LoadLibrary_Hooks.cpp" />
|
||||
<ClCompile Include="hooks\NvApi_Hooks.cpp" />
|
||||
<ClCompile Include="hooks\Nvngx_Hooks.cpp" />
|
||||
<ClCompile Include="hooks\Vulkan_Hooks.cpp" />
|
||||
<ClCompile Include="Working_Mode.cpp" />
|
||||
<ClCompile Include="imgui\imgui\imgui.cpp" />
|
||||
@@ -319,7 +328,7 @@ copy $(SolutionDir)nvngx.ini $(SolutionDir)x64\Release\a\</Command>
|
||||
<ClCompile Include="imgui\imgui_overlay_dx11.cpp" />
|
||||
<ClCompile Include="imgui\imgui_overlay_dx12.cpp" />
|
||||
<ClCompile Include="imgui\imgui_overlay_vk.cpp" />
|
||||
<ClCompile Include="imgui\wrapped_swapchain.cpp" />
|
||||
<ClCompile Include="hooks\proxies\Wrapped_SwapChain.cpp" />
|
||||
<ClCompile Include="Logger.cpp" />
|
||||
<ClCompile Include="NVNGX.cpp" />
|
||||
<ClCompile Include="NVNGX_DLSS_Dx11.cpp" />
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
enum SwapchainSource
|
||||
{
|
||||
Unknown,
|
||||
Dx12,
|
||||
SL,
|
||||
FSR3_Mod,
|
||||
FSR3_Native
|
||||
};
|
||||
@@ -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<ULONG(IUnknown*)> commandQueueReleaseCallback = nullptr;
|
||||
static std::function<void(ID3D12CommandQueue*, UINT, ID3D12CommandList* const*)> 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<ULONG(IUnknown*)> InCallback)
|
||||
{
|
||||
contextRendering = false;
|
||||
}
|
||||
commandQueueReleaseCallback = InCallback;
|
||||
}
|
||||
|
||||
void Hooks::SetExecuteCommandListCallback(std::function<void(ID3D12CommandQueue*, UINT, ID3D12CommandList* const*)> InCallback)
|
||||
{
|
||||
executeCommandListCallback = InCallback;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "../pch.h"
|
||||
|
||||
#include <d3d12.h>
|
||||
|
||||
@@ -10,6 +11,8 @@ namespace Hooks
|
||||
void ContextEvaluateStart();
|
||||
void ContextEvaluateStop(ID3D12GraphicsCommandList* InCmdList, bool InRestore);
|
||||
|
||||
void ContextRenderingStart();
|
||||
void ContextRenderingStop();
|
||||
bool IsDeviceCaptured();
|
||||
|
||||
void SetCommandQueueReleaseCallback(std::function<ULONG(IUnknown*)> InCallback);
|
||||
void SetExecuteCommandListCallback(std::function<void(ID3D12CommandQueue*, UINT, ID3D12CommandList* const*)> InCallback);
|
||||
}
|
||||
@@ -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<void> createSwapChainCallback = nullptr;
|
||||
|
||||
void Hooks::AttachDxgiHooks()
|
||||
{
|
||||
if (o_CreateDxgiFactory != nullptr || o_CreateDxgiFactory1 != nullptr || o_CreateDxgiFactory2 != nullptr)
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
#pragma once
|
||||
#include "../pch.h"
|
||||
#include "../enums/Enums.h"
|
||||
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
namespace Hooks
|
||||
{
|
||||
void AttachDxgiHooks();
|
||||
void DetachDxgiHooks();
|
||||
|
||||
void DxgiClean(std::function<void(SwapchainSource, bool)>);
|
||||
void DxgiPresent(std::function<void(SwapchainSource, IDXGISwapChain3*, UINT)>);
|
||||
}
|
||||
|
||||
+21
-19
@@ -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<HRESULT(IDXGISwapChain3*, UINT, UINT)> renderTrig,
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*)> renderTrig1,
|
||||
std::function<void(bool)> clearTrig) : m_pReal(real), RenderTrig(renderTrig), RenderTrig1(renderTrig1), ClearTrig(clearTrig), m_iRefcount(1)
|
||||
WrappedIDXGISwapChain4::WrappedIDXGISwapChain4(IDXGISwapChain* InRealSwapChain,
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT)>* InPresentTrig,
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*)>* InPresentTrig1,
|
||||
std::function<void(bool)>* 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);
|
||||
}
|
||||
+16
-14
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "../pch.h"
|
||||
#include "dxgi1_6.h"
|
||||
#include "imgui_overlay_base.h"
|
||||
#include "../../pch.h"
|
||||
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
class WrappedIDXGISwapChain4 : public IDXGISwapChain4
|
||||
{
|
||||
@@ -11,18 +11,20 @@ class WrappedIDXGISwapChain4 : public IDXGISwapChain4
|
||||
IDXGISwapChain3* m_pReal3 = nullptr;
|
||||
IDXGISwapChain4* m_pReal4 = nullptr;
|
||||
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT)> RenderTrig = nullptr;
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*)> RenderTrig1 = nullptr;
|
||||
std::function<void(bool)> ClearTrig = nullptr;
|
||||
HWND* menuHandle = nullptr;
|
||||
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT)>* PresentTrig = nullptr;
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*)>* PresentTrig1 = nullptr;
|
||||
std::function<void(bool)>* ClearTrig = nullptr;
|
||||
|
||||
unsigned int m_iRefcount;
|
||||
|
||||
public:
|
||||
|
||||
WrappedIDXGISwapChain4(IDXGISwapChain* real,
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT , UINT)> renderTrig,
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*)> renderTrig1,
|
||||
std::function<void(bool)> clearTrig);
|
||||
WrappedIDXGISwapChain4(IDXGISwapChain* InRealSwapChain,
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT)>* InPresentTrig,
|
||||
std::function<HRESULT(IDXGISwapChain3*, UINT, UINT, const DXGI_PRESENT_PARAMETERS*)>* InPresentTrig1,
|
||||
std::function<void(bool)>* 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;
|
||||
}
|
||||
@@ -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 <utility>
|
||||
#include <iterator>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace misc {
|
||||
|
||||
// std::identity is c++20
|
||||
struct identity {
|
||||
template<typename T>
|
||||
constexpr T&& operator()(T&& t) const {
|
||||
return std::forward<T>(t);
|
||||
}
|
||||
};
|
||||
|
||||
namespace details {
|
||||
struct structured_void {};
|
||||
inline structured_void no_value{};
|
||||
|
||||
template <typename T>
|
||||
struct non_void {
|
||||
using type = T;
|
||||
};
|
||||
template <>
|
||||
struct non_void<void> {
|
||||
using type = structured_void;
|
||||
};
|
||||
}
|
||||
// type T if T is non void, details::structured void otherwise
|
||||
template <typename T>
|
||||
using non_void_t = typename details::non_void<T>::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 <typename ForwardIt, typename EndIt, typename Comparator = std::less<std::remove_reference_t<decltype(*std::declval<ForwardIt>())>>>
|
||||
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 <typename ForwardIt, typename EndIt, typename SizeExtractor>
|
||||
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 <typename ForwardIt, typename OutputIt>
|
||||
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 <typename BidirIt1, typename BidirIt2>
|
||||
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 <typename ForwardIt, typename RandomAccessIt>
|
||||
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<unsigned>(std::distance(dest_beg, dest_end)), n);
|
||||
auto copy_length = static_cast<unsigned>(std::distance(src_beg, src_end));
|
||||
auto avail_length = static_cast<unsigned>(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 <typename ForwardIterator, typename ValueType>
|
||||
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 <typename ForwardIterator, typename SpaceDetector>
|
||||
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<unsigned>(&*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 <typename ForwardIt, typename StrExtractor = identity, typename Transform = identity>
|
||||
auto prefix_search(std::string_view prefix, ForwardIt c_beg, ForwardIt c_end,
|
||||
StrExtractor&& str_ext = {}, Transform&& transform = {}) -> std::vector<std::decay_t<decltype(transform(*c_beg))>> {
|
||||
|
||||
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<std::decay_t<decltype(transform(*c_beg))>> ans;
|
||||
std::transform(lower, higher, std::back_inserter(ans), std::forward<Transform>(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 <typename ForwardIt, typename IsSpace, typename StrExtractor = identity>
|
||||
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 AlwaysVoid, template<typename...> typename Op, typename... Args>
|
||||
struct detector : std::false_type {
|
||||
using type = std::is_same<void,void>;
|
||||
};
|
||||
|
||||
template <template<typename...> typename Op, typename... Args>
|
||||
struct detector<std::void_t<Op<Args...>>, Op, Args...> : std::true_type {
|
||||
using type = Op<Args...>;
|
||||
};
|
||||
}
|
||||
|
||||
template <template<typename...> typename Op, typename... Args>
|
||||
using is_detected = typename details::detector<void, Op, Args...>;
|
||||
|
||||
template <template<typename...> typename Op, typename... Args>
|
||||
using is_detected_t = typename is_detected <Op, Args...>::type;
|
||||
|
||||
// compile time function detection, return type agnostic
|
||||
template <template<typename...> typename Op, typename... Args>
|
||||
constexpr bool is_detected_v = is_detected<Op, Args...>::value;
|
||||
|
||||
// compile time function detection
|
||||
template <template<typename...> typename Op, typename ReturnType, typename... Args>
|
||||
constexpr bool is_detected_with_return_type_v = std::is_same_v<is_detected_t<Op, Args...>, 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
|
||||
@@ -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 <atomic>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <optional>
|
||||
#include <array>
|
||||
#include <imgui.h>
|
||||
|
||||
#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<typename TerminalHelper, typename CommandTypeCref>
|
||||
struct assert_wellformed {
|
||||
|
||||
template<typename T>
|
||||
using find_commands_by_prefix_method_v1 =
|
||||
decltype(std::declval<T&>().find_commands_by_prefix(std::declval<std::string_view>()));
|
||||
|
||||
template<typename T>
|
||||
using find_commands_by_prefix_method_v2 =
|
||||
decltype(std::declval<T&>().find_commands_by_prefix(std::declval<const char *>(),
|
||||
std::declval<const char *>()));
|
||||
|
||||
template<typename T>
|
||||
using list_commands_method = decltype(std::declval<T&>().list_commands());
|
||||
|
||||
template<typename T>
|
||||
using format_method = decltype(std::declval<T&>().format(std::declval<std::string>(), std::declval<message::type>()));
|
||||
|
||||
static_assert(
|
||||
misc::is_detected_with_return_type_v<find_commands_by_prefix_method_v1, std::vector<CommandTypeCref>, TerminalHelper>,
|
||||
"TerminalHelper should implement the method 'std::vector<command_type_cref> find_command_by_prefix(std::string_view)'. "
|
||||
"See term::terminal_helper_example for reference");
|
||||
static_assert(
|
||||
misc::is_detected_with_return_type_v<find_commands_by_prefix_method_v2, std::vector<CommandTypeCref>, TerminalHelper>,
|
||||
"TerminalHelper should implement the method 'std::vector<command_type_cref> find_command_by_prefix(const char*, const char*)'. "
|
||||
"See term::terminal_helper_example for reference");
|
||||
static_assert(
|
||||
misc::is_detected_with_return_type_v<list_commands_method, std::vector<CommandTypeCref>, TerminalHelper>,
|
||||
"TerminalHelper should implement the method 'std::vector<command_type_cref> list_commands()'. "
|
||||
"See term::terminal_helper_example for reference");
|
||||
static_assert(
|
||||
misc::is_detected_with_return_type_v<format_method, std::optional<message>, TerminalHelper>,
|
||||
"TerminalHelper should implement the method 'std::optional<term::message> format(std::string, term::message::type)'. "
|
||||
"See term::terminal_helper_example for reference");
|
||||
};
|
||||
}
|
||||
|
||||
template<typename TerminalHelper>
|
||||
class terminal {
|
||||
using buffer_type = std::array<char, 1024>;
|
||||
using small_buffer_type = std::array<char, 128>;
|
||||
public:
|
||||
using value_type = misc::non_void_t<typename TerminalHelper::value_type>;
|
||||
using command_type = command_t<terminal<TerminalHelper>>;
|
||||
using command_type_cref = std::reference_wrapper<const command_type>;
|
||||
using argument_type = argument_t<terminal>;
|
||||
|
||||
using terminal_helper_is_valid = details::assert_wellformed<TerminalHelper, command_type_cref>;
|
||||
|
||||
inline static const std::vector<config_panels> 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 <typename T = value_type, typename = std::enable_if_t<!std::is_same_v<T, misc::details::structured_void>>>
|
||||
explicit terminal(value_type& arg_value, const char * window_name_ = "terminal", int base_width_ = 900,
|
||||
int base_height_ = 200, std::shared_ptr<TerminalHelper> th = std::make_shared<TerminalHelper>())
|
||||
: 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 <typename T = value_type, typename = std::enable_if_t<std::is_same_v<T, misc::details::structured_void>>>
|
||||
explicit terminal(const char * window_name_ = "terminal", int base_width_ = 900,
|
||||
int base_height_ = 200, std::shared_ptr<TerminalHelper> th = std::make_shared<TerminalHelper>())
|
||||
: 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<TerminalHelper> 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<config_panels>& panels_order = DEFAULT_ORDER) noexcept;
|
||||
|
||||
// returns the command line history
|
||||
const std::vector<std::string>& 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 <typename... Args>
|
||||
void add_formatted(const char* fmt, Args&&... args) {
|
||||
add_text(fmt::format(fmt, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
// logs a colorless text to the message panel
|
||||
// added as terminal message with warn severity
|
||||
template <typename... Args>
|
||||
void add_formatted_err(const char* fmt, Args&&... args) {
|
||||
add_text_err(fmt::format(fmt, std::forward<Args>(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<unsigned>(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<unsigned>(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<message::severity::severity_t>(m_level + static_cast<int>(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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<std::string>& 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<message>::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<unsigned>(sz.x), static_cast<unsigned>(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<TerminalHelper> 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<config_panels>& 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<std::string> resolve_history_reference(std::string_view str, bool& modified) const noexcept;
|
||||
|
||||
std::pair<bool, std::string> 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<ImVec4>& color) {
|
||||
if (color) {
|
||||
ImGui::PushStyleColor(col, *color);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int try_push_style(ImGuiCol col, const std::optional<theme::constexpr_color>& 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<std::vector<std::string>> 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<TerminalHelper> 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<std::string>::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<std::string> m_autoscroll_text;
|
||||
std::optional<std::string> m_clear_text;
|
||||
std::optional<std::string> m_log_level_text;
|
||||
std::optional<std::string> m_autowrap_text;
|
||||
std::optional<std::string> 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<message> m_logs{};
|
||||
std::vector<message>::size_type m_max_log_len{5'000}; // TODO: command
|
||||
std::vector<message>::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<command_type_cref> m_current_autocomplete{};
|
||||
std::vector<std::string> 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<std::string> m_command_history{};
|
||||
std::optional<std::vector<std::string>::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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,346 @@
|
||||
#ifndef TERMINAL_HELPER_HPP
|
||||
#define TERMINAL_HELPER_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 <set>
|
||||
#include <array>
|
||||
|
||||
#include "terminal.hpp"
|
||||
#if __has_include("spdlog/spdlog.h")
|
||||
#include "spdlog/common.h"
|
||||
#include "spdlog/formatter.h"
|
||||
#include "spdlog/pattern_formatter.h"
|
||||
#include "spdlog/details/log_msg.h"
|
||||
#include "spdlog/sinks/base_sink.h"
|
||||
|
||||
#define IMTERM_SPDLOG_INCLUDED
|
||||
// helpers
|
||||
namespace ImTerm::details {
|
||||
constexpr message::severity::severity_t to_imterm_severity(spdlog::level::level_enum);
|
||||
constexpr spdlog::level::level_enum to_spdlog_severity(message::severity::severity_t);
|
||||
constexpr spdlog::level::level_enum to_spdlog_severity(message::type);
|
||||
inline ImTerm::message to_imterm_msg(const spdlog::details::log_msg&);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace ImTerm {
|
||||
|
||||
|
||||
// terminal_helper_example is meant to be an example
|
||||
// if you want to inherit from one, pick term::basic_terminal_helper (see below)
|
||||
template <typename T>
|
||||
class terminal_helper_example {
|
||||
public:
|
||||
using value_type = T; // < Mandatory, this type will be passed to commands via argument_type
|
||||
using term_t = ImTerm::terminal<terminal_helper_example>;
|
||||
using command_type = ImTerm::command_t<ImTerm::terminal<terminal_helper_example>>;
|
||||
using argument_type = ImTerm::argument_t<ImTerm::terminal<terminal_helper_example>>;
|
||||
using command_type_cref = std::reference_wrapper<const command_type>;
|
||||
|
||||
// mandatory : return every command starting by prefix
|
||||
std::vector<command_type_cref> find_commands_by_prefix(std::string_view prefix) {
|
||||
|
||||
auto compare_by_name = [](const command_type& cmd) { return cmd.name; };
|
||||
auto map_to_cref = [](const command_type& cmd) { return std::cref(cmd); };
|
||||
|
||||
return misc::prefix_search(prefix, cmd_list.begin(), cmd_list.end(), std::move(compare_by_name), std::move(map_to_cref));
|
||||
}
|
||||
|
||||
// mandatory : return every command starting by the text formed by [beg, end)
|
||||
std::vector<command_type_cref> find_commands_by_prefix(const char* beg, const char* end) {
|
||||
return find_commands_by_prefix({beg, static_cast<unsigned>(end - beg)});
|
||||
}
|
||||
|
||||
// mandatory: returns the full command list
|
||||
std::vector<command_type_cref> list_commands() {
|
||||
return find_commands_by_prefix(std::string_view{});
|
||||
}
|
||||
|
||||
// mandatory: formats the given string.
|
||||
// msg type is either user_input, error, or cmd_history_completion
|
||||
// return an empty optional if you do not want the string to be logged
|
||||
// message's members 'is_term_message' and 'severity' are ignored
|
||||
std::optional<ImTerm::message> format(std::string str, [[maybe_unused]] ImTerm::message::type msg_type) {
|
||||
ImTerm::message msg;
|
||||
msg.color_beg = msg.color_end = 0u;
|
||||
msg.value = std::move(str);
|
||||
return {std::move(msg)}; // other fields are ignored
|
||||
}
|
||||
|
||||
// optional : to be friendlier with non ascii encoding
|
||||
// return value : 0 if str does not begin by a space
|
||||
// otherwise, the number of characters participating in the representation of the beginning space
|
||||
// should not return a value > str.size()
|
||||
// the passed string_view is never empty (at least one char)
|
||||
// int is_space(std::string_view str) const {
|
||||
// return str[0] == ' ';
|
||||
// }
|
||||
|
||||
// optional : to be friendlier with non ascii encoding
|
||||
// return value : number of glyphs represented in str (== str.size() for ascii)
|
||||
// unsigned long get_length(std::string_view str) {
|
||||
// return str.size();
|
||||
// }
|
||||
|
||||
// optional : called right after terminal's construction. You may store the terminal for future usage
|
||||
// void set_terminal(term_t& term) {
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// command samples (implemented as static methods, but they can be outside of a class, if you will to)
|
||||
static std::vector<std::string> no_completion(argument_type&) { return {}; }
|
||||
|
||||
static void clear(argument_type& arg) {
|
||||
arg.term.clear();
|
||||
}
|
||||
|
||||
static void echo(argument_type& arg) {
|
||||
std::string str{};
|
||||
str = arg.command_line[1];
|
||||
for (auto it = std::next(arg.command_line.begin(), 2) ; it != arg.command_line.end() ; ++it) {
|
||||
str.reserve(str.size() + it->size() + 1);
|
||||
str += ' ';
|
||||
str += *it;
|
||||
}
|
||||
message msg;
|
||||
msg.value = std::move(str);
|
||||
msg.color_beg = msg.color_end = 0; // color is disabled when color_beg == color_end
|
||||
// other parameters are ignored
|
||||
arg.term.add_message(std::move(msg));
|
||||
}
|
||||
|
||||
static constexpr std::array<command_type, 2> cmd_list = {
|
||||
command_type{"clear ", "clears the screen", clear, no_completion},
|
||||
command_type{"echo ", "prints text to the screen", echo, no_completion},
|
||||
};
|
||||
};
|
||||
|
||||
// Basic terminal helper
|
||||
// You may inherit to save some hassle
|
||||
// Template parameter TerminalHelper is in most cases the derived class (and should be if you don't know what to put)
|
||||
// Template parameter Value is the type passed to commands together with the other arguments
|
||||
// You may add commands with the 'add_command_' method.
|
||||
// Refer to terminal_helper_example (see above) for a commented example
|
||||
template <typename TerminalHelper, typename Value>
|
||||
class basic_terminal_helper {
|
||||
public:
|
||||
using value_type = Value;
|
||||
using term_t = ImTerm::terminal<TerminalHelper>;
|
||||
using command_type = ImTerm::command_t<ImTerm::terminal<TerminalHelper>>;
|
||||
using argument_type = ImTerm::argument_t<ImTerm::terminal<TerminalHelper>>;
|
||||
using command_type_cref = std::reference_wrapper<const command_type>;
|
||||
|
||||
basic_terminal_helper() = default;
|
||||
basic_terminal_helper(const basic_terminal_helper&) = default;
|
||||
basic_terminal_helper(basic_terminal_helper&&) noexcept = default;
|
||||
|
||||
std::vector<command_type_cref> find_commands_by_prefix(std::string_view prefix) {
|
||||
auto compare_name = [](const command_type& cmd) { return cmd.name; };
|
||||
auto map_to_cref = [](const command_type& cmd) { return std::cref(cmd); };
|
||||
|
||||
return misc::prefix_search(prefix, cmd_list_.begin(), cmd_list_.end(), std::move(compare_name),
|
||||
std::move(map_to_cref));
|
||||
}
|
||||
|
||||
std::vector<command_type_cref> find_commands_by_prefix(const char * beg, const char * end) {
|
||||
return find_commands_by_prefix({beg, static_cast<unsigned>(end - beg)});
|
||||
}
|
||||
|
||||
std::vector<command_type_cref> list_commands() {
|
||||
std::vector<command_type_cref> ans;
|
||||
ans.reserve(cmd_list_.size());
|
||||
for (const command_type& cmd : cmd_list_) {
|
||||
ans.emplace_back(cmd);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
std::optional<ImTerm::message> format(std::string str, ImTerm::message::type) {
|
||||
ImTerm::message msg;
|
||||
msg.value = std::move(str);
|
||||
msg.color_beg = msg.color_end = 0u;
|
||||
return {std::move(msg)};
|
||||
}
|
||||
|
||||
protected:
|
||||
void add_command_(const command_type& cmd) {
|
||||
cmd_list_.emplace(cmd);
|
||||
}
|
||||
|
||||
std::set<command_type> cmd_list_{};
|
||||
};
|
||||
|
||||
#ifdef IMTERM_SPDLOG_INCLUDED
|
||||
|
||||
// Basic spdlog terminal helper inheriting spdlog::sinks::sink (logging messages to the terminal)
|
||||
// You may inherit to save some hassle
|
||||
// Template parameter TerminalHelper is in most cases the derived class (and should be if you don't know what to put)
|
||||
// Template parameter Value is the type passed to commands together with the other arguments
|
||||
// Template parameter Mutex is passed to spdlog::sinks::base_sink
|
||||
// You may add commands with the 'add_command_' method.
|
||||
// Refer to terminal_helper_example (see above) for a commented example
|
||||
// should not be used after move
|
||||
template <typename TerminalHelper, typename Value, typename Mutex>
|
||||
class basic_spdlog_terminal_helper : public basic_terminal_helper<TerminalHelper, Value>, public spdlog::sinks::base_sink<Mutex> {
|
||||
using SinkBase = spdlog::sinks::base_sink<Mutex>;
|
||||
using TermHBase = basic_terminal_helper<TerminalHelper,Value>;
|
||||
public:
|
||||
using typename TermHBase::term_t;
|
||||
|
||||
explicit basic_spdlog_terminal_helper(std::string terminal_to_terminal_logger_name = "ImTerm Terminal")
|
||||
: logger_name_{std::move(terminal_to_terminal_logger_name)} {
|
||||
set_terminal_pattern_("%T.%e - [%^command line%$]: %v", message::type::error);
|
||||
set_terminal_pattern_("%T.%e - %^%v%$", message::type::user_input);
|
||||
set_terminal_pattern_("%T.%e - %^%v%$", message::type::cmd_history_completion);
|
||||
}
|
||||
|
||||
basic_spdlog_terminal_helper(basic_spdlog_terminal_helper&& other) noexcept
|
||||
: SinkBase{}
|
||||
, TermHBase(std::move(other))
|
||||
, terminal_{std::exchange(other.terminal_, nullptr)}
|
||||
, terminal_formatter_{std::move(other.terminal_formatter_)}
|
||||
, logger_name_{std::move(other.logger_name_)}
|
||||
{
|
||||
SinkBase::set_level(other.level());
|
||||
SinkBase::set_formatter(std::move(other.formatter_));
|
||||
}
|
||||
|
||||
virtual ~basic_spdlog_terminal_helper() noexcept = default;
|
||||
|
||||
std::optional<ImTerm::message> format(std::string str, [[maybe_unused]] ImTerm::message::type type) {
|
||||
spdlog::details::log_msg msg(logger_name_, {}, str);
|
||||
spdlog::memory_buf_t buff{};
|
||||
terminal_formatter_[static_cast<int>(type)]->format(msg, buff);
|
||||
|
||||
ImTerm::message term_msg = details::to_imterm_msg(msg);
|
||||
term_msg.value = fmt::to_string(buff);
|
||||
return term_msg;
|
||||
}
|
||||
|
||||
// this method is called automatically right after ImTerm::terminal's construction
|
||||
// used to sink logs to the message panel
|
||||
void set_terminal(term_t& term) {
|
||||
terminal_ = &term;
|
||||
}
|
||||
|
||||
// set logging pattern per message type, for feed-back messages from the terminal
|
||||
void set_terminal_pattern(const std::string& pattern, ImTerm::message::type type) {
|
||||
std::lock_guard<Mutex> lock(SinkBase::mutex_);
|
||||
set_terminal_pattern_(std::make_unique<spdlog::pattern_formatter>(pattern), type);
|
||||
}
|
||||
|
||||
void set_terminal_formatter(std::unique_ptr<spdlog::formatter>&& terminal_formatter, ImTerm::message::type type) {
|
||||
std::lock_guard<Mutex> lock(SinkBase::mutex_);
|
||||
set_terminal_formatter_(std::move(terminal_formatter), type);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void set_terminal_pattern_(const std::string& pattern, ImTerm::message::type type) {
|
||||
set_terminal_formatter_(std::make_unique<spdlog::pattern_formatter>(pattern), type);
|
||||
}
|
||||
|
||||
void set_terminal_formatter_(std::unique_ptr<spdlog::formatter>&& terminal_formatter, ImTerm::message::type type) {
|
||||
terminal_formatter_[static_cast<int>(type)] = std::move(terminal_formatter);
|
||||
}
|
||||
|
||||
void sink_it_(const spdlog::details::log_msg& msg) override {
|
||||
if (msg.level == spdlog::level::off) {
|
||||
return;
|
||||
}
|
||||
assert(terminal_ != nullptr);
|
||||
spdlog::memory_buf_t buff{};
|
||||
SinkBase::formatter_->format(msg, buff);
|
||||
terminal_->add_message({details::to_imterm_severity(msg.level), fmt::to_string(buff)
|
||||
, msg.color_range_start, msg.color_range_end, false});
|
||||
}
|
||||
|
||||
void flush_() override {}
|
||||
|
||||
term_t* terminal_{};
|
||||
std::array<std::unique_ptr<spdlog::formatter>, 3> terminal_formatter_{}; // user_input, error, cmd_history_completion (c.f. ImTerm::message::type)
|
||||
std::string logger_name_;
|
||||
};
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
constexpr message::severity::severity_t to_imterm_severity(spdlog::level::level_enum lvl) {
|
||||
assert(lvl != spdlog::level::off);
|
||||
if constexpr (
|
||||
ImTerm::message::severity::trace == static_cast<int>(spdlog::level::trace) &&
|
||||
ImTerm::message::severity::debug == static_cast<int>(spdlog::level::debug) &&
|
||||
ImTerm::message::severity::info == static_cast<int>(spdlog::level::info) &&
|
||||
ImTerm::message::severity::warn == static_cast<int>(spdlog::level::warn) &&
|
||||
ImTerm::message::severity::err == static_cast<int>(spdlog::level::err) &&
|
||||
ImTerm::message::severity::critical == static_cast<int>(spdlog::level::critical)) {
|
||||
return static_cast<message::severity::severity_t>(lvl);
|
||||
} else {
|
||||
switch (lvl) {
|
||||
case spdlog::level::trace: return ImTerm::message::severity::trace;
|
||||
case spdlog::level::debug: return ImTerm::message::severity::debug;
|
||||
case spdlog::level::info: return ImTerm::message::severity::info;
|
||||
case spdlog::level::warn: return ImTerm::message::severity::warn;
|
||||
case spdlog::level::err: return ImTerm::message::severity::err;
|
||||
case spdlog::level::critical: return ImTerm::message::severity::critical;
|
||||
default:
|
||||
assert(false);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr spdlog::level::level_enum to_spdlog_severity(message::severity::severity_t lvl) {
|
||||
if constexpr (
|
||||
ImTerm::message::severity::trace == static_cast<int>(spdlog::level::trace) &&
|
||||
ImTerm::message::severity::debug == static_cast<int>(spdlog::level::debug) &&
|
||||
ImTerm::message::severity::info == static_cast<int>(spdlog::level::info) &&
|
||||
ImTerm::message::severity::warn == static_cast<int>(spdlog::level::warn) &&
|
||||
ImTerm::message::severity::err == static_cast<int>(spdlog::level::err) &&
|
||||
ImTerm::message::severity::critical == static_cast<int>(spdlog::level::critical)) {
|
||||
return static_cast<spdlog::level::level_enum>(lvl);
|
||||
} else {
|
||||
switch (lvl) {
|
||||
case ImTerm::message::severity::trace: return spdlog::level::trace;
|
||||
case ImTerm::message::severity::debug: return spdlog::level::debug;
|
||||
case ImTerm::message::severity::info: return spdlog::level::info;
|
||||
case ImTerm::message::severity::warn: return spdlog::level::warn;
|
||||
case ImTerm::message::severity::err: return spdlog::level::err;
|
||||
case ImTerm::message::severity::critical: return spdlog::level::critical;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline ImTerm::message to_imterm_msg(const spdlog::details::log_msg& msg) {
|
||||
ImTerm::message term_msg{};
|
||||
term_msg.severity = to_imterm_severity(msg.level);
|
||||
term_msg.color_beg = msg.color_range_start;
|
||||
term_msg.color_end = msg.color_range_end;
|
||||
return term_msg;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#undef IMTERM_SPDLOG_INCLUDED
|
||||
|
||||
#endif //TERMINAL_HELPER_HPP
|
||||
@@ -0,0 +1,266 @@
|
||||
#ifndef IMTERM_UTILS_HPP
|
||||
#define IMTERM_UTILS_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 <string>
|
||||
#include <string_view>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <array>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "misc.hpp"
|
||||
|
||||
namespace ImTerm {
|
||||
// argument passed to commands
|
||||
template<typename Terminal>
|
||||
struct argument_t {
|
||||
using value_type = misc::non_void_t<typename Terminal::value_type>;
|
||||
|
||||
value_type& val; // misc::details::structured_void if Terminal::value_type is void, reference to Terminal::value_type otherwise
|
||||
Terminal& term; // reference to the ImTerm::terminal that called the command
|
||||
|
||||
std::vector<std::string> command_line; // list of arguments the user specified in the command line. command_line[0] is the command name
|
||||
};
|
||||
|
||||
// structure used to represent a command
|
||||
template<typename Terminal>
|
||||
struct command_t {
|
||||
using command_function = void (*)(argument_t<Terminal>&);
|
||||
using further_completion_function = std::vector<std::string> (*)(argument_t<Terminal>& argument_line);
|
||||
|
||||
std::string_view name{}; // name of the command
|
||||
std::string_view description{}; // short description
|
||||
command_function call{}; // function doing whatever you want
|
||||
|
||||
further_completion_function complete{}; // function called when users starts typing in arguments for your command
|
||||
// return a vector of strings containing possible completions.
|
||||
|
||||
friend constexpr bool operator<(const command_t& lhs, const command_t& rhs) {
|
||||
return lhs.name < rhs.name;
|
||||
}
|
||||
|
||||
friend constexpr bool operator<(const command_t& lhs, const std::string_view& rhs) {
|
||||
return lhs.name < rhs;
|
||||
}
|
||||
|
||||
friend constexpr bool operator<(const std::string_view& lhs, const command_t& rhs) {
|
||||
return lhs < rhs.name;
|
||||
}
|
||||
};
|
||||
|
||||
struct message {
|
||||
enum class type {
|
||||
user_input, // terminal wants to log user input
|
||||
error, // terminal wants to log an error in user input
|
||||
cmd_history_completion, // terminal wants to log that it replaced "!:*" family input in the appropriate string
|
||||
};
|
||||
struct severity {
|
||||
enum severity_t { // done this way to be used as array index without a cast
|
||||
trace,
|
||||
debug,
|
||||
info,
|
||||
warn,
|
||||
err,
|
||||
critical
|
||||
};
|
||||
};
|
||||
|
||||
severity::severity_t severity; // severity of the message
|
||||
std::string value; // text to be displayed
|
||||
|
||||
// the actual color used depends on the message's severity
|
||||
size_t color_beg; // color begins at value.data() + color_beg
|
||||
size_t color_end; // color ends at value.data() + color_end - 1
|
||||
// if color_beg == color_end, nothing is colorized.
|
||||
|
||||
bool is_term_message; // if set to true, current msg is considered to be originated from the terminal,
|
||||
// never filtered out by severity filter, and applying for different rules regarding colors.
|
||||
// severity is also ignored for such messages
|
||||
};
|
||||
|
||||
enum class config_panels {
|
||||
autoscroll,
|
||||
autowrap,
|
||||
clearbutton,
|
||||
filter,
|
||||
long_filter, // like filter, but takes up space
|
||||
loglevel,
|
||||
blank, // invisible panel that takes up place, aligning items to the right. More than one can be used, splitting up the consumed space
|
||||
// ie: {clearbutton (C), blank, filter (F), blank, loglevel (L)} will result in the layout [C F L]
|
||||
// Shares space with long_filter
|
||||
none
|
||||
};
|
||||
|
||||
enum class position {
|
||||
up,
|
||||
down,
|
||||
nowhere // disabled
|
||||
};
|
||||
|
||||
// Various settable colors for the terminal
|
||||
// if an optional is empty, current ImGui color will be used
|
||||
struct theme {
|
||||
struct constexpr_color {
|
||||
float r,g,b,a;
|
||||
|
||||
ImVec4 imv4() const {
|
||||
return {r,g,b,a};
|
||||
}
|
||||
};
|
||||
|
||||
std::string_view name; // if you want to give a name to the theme
|
||||
|
||||
std::optional<constexpr_color> text; // global text color
|
||||
std::optional<constexpr_color> window_bg; // ImGuiCol_WindowBg & ImGuiCol_ChildBg
|
||||
std::optional<constexpr_color> border; // ImGuiCol_Border
|
||||
std::optional<constexpr_color> border_shadow; // ImGuiCol_BorderShadow
|
||||
std::optional<constexpr_color> button; // ImGuiCol_Button
|
||||
std::optional<constexpr_color> button_hovered; // ImGuiCol_ButtonHovered
|
||||
std::optional<constexpr_color> button_active; // ImGuiCol_ButtonActive
|
||||
std::optional<constexpr_color> frame_bg; // ImGuiCol_FrameBg
|
||||
std::optional<constexpr_color> frame_bg_hovered; // ImGuiCol_FrameBgHovered
|
||||
std::optional<constexpr_color> frame_bg_active; // ImGuiCol_FrameBgActive
|
||||
std::optional<constexpr_color> text_selected_bg; // ImGuiCol_TextSelectedBg, for text input field
|
||||
std::optional<constexpr_color> check_mark; // ImGuiCol_CheckMark
|
||||
std::optional<constexpr_color> title_bg; // ImGuiCol_TitleBg
|
||||
std::optional<constexpr_color> title_bg_active; // ImGuiCol_TitleBgActive
|
||||
std::optional<constexpr_color> title_bg_collapsed; // ImGuiCol_TitleBgCollapsed
|
||||
std::optional<constexpr_color> message_panel; // logging panel
|
||||
std::optional<constexpr_color> auto_complete_selected; // left-most text in the autocompletion OSD
|
||||
std::optional<constexpr_color> auto_complete_non_selected; // every text but the left most in the autocompletion OSD
|
||||
std::optional<constexpr_color> auto_complete_separator; // color for the separator in the autocompletion OSD
|
||||
std::optional<constexpr_color> cmd_backlog; // color for message type user_input
|
||||
std::optional<constexpr_color> cmd_history_completed; // color for message type cmd_history_completion
|
||||
std::optional<constexpr_color> log_level_drop_down_list_bg; // ImGuiCol_PopupBg
|
||||
std::optional<constexpr_color> log_level_active; // ImGuiCol_HeaderActive
|
||||
std::optional<constexpr_color> log_level_hovered; // ImGuiCol_HeaderHovered
|
||||
std::optional<constexpr_color> log_level_selected; // ImGuiCol_Header
|
||||
std::optional<constexpr_color> scrollbar_bg; // ImGuiCol_ScrollbarBg
|
||||
std::optional<constexpr_color> scrollbar_grab; // ImGuiCol_ScrollbarGrab
|
||||
std::optional<constexpr_color> scrollbar_grab_active; // ImGuiCol_ScrollbarGrabActive
|
||||
std::optional<constexpr_color> scrollbar_grab_hovered; // ImGuiCol_ScrollbarGrabHovered
|
||||
std::optional<constexpr_color> filter_hint; // ImGuiCol_TextDisabled
|
||||
std::optional<constexpr_color> filter_text; // user input in log filter
|
||||
std::optional<constexpr_color> matching_text; // text matching the log filter
|
||||
|
||||
std::array<std::optional<constexpr_color>, message::severity::critical + 1> log_level_colors{}; // colors by severity
|
||||
};
|
||||
|
||||
|
||||
namespace themes {
|
||||
|
||||
constexpr theme light = {
|
||||
"Light Rainbow",
|
||||
theme::constexpr_color{0.100f, 0.100f, 0.100f, 1.000f}, //text
|
||||
theme::constexpr_color{0.243f, 0.443f, 0.624f, 1.000f}, //window_bg
|
||||
theme::constexpr_color{0.600f, 0.600f, 0.600f, 1.000f}, //border
|
||||
theme::constexpr_color{0.000f, 0.000f, 0.000f, 0.000f}, //border_shadow
|
||||
theme::constexpr_color{0.902f, 0.843f, 0.843f, 0.875f}, //button
|
||||
theme::constexpr_color{0.824f, 0.765f, 0.765f, 0.875f}, //button_hovered
|
||||
theme::constexpr_color{0.627f, 0.569f, 0.569f, 0.875f}, //button_active
|
||||
theme::constexpr_color{0.902f, 0.843f, 0.843f, 0.875f}, //frame_bg
|
||||
theme::constexpr_color{0.824f, 0.765f, 0.765f, 0.875f}, //frame_bg_hovered
|
||||
theme::constexpr_color{0.627f, 0.569f, 0.569f, 0.875f}, //frame_bg_active
|
||||
theme::constexpr_color{0.260f, 0.590f, 0.980f, 0.350f}, //text_selected_bg
|
||||
theme::constexpr_color{0.843f, 0.000f, 0.373f, 1.000f}, //check_mark
|
||||
theme::constexpr_color{0.243f, 0.443f, 0.624f, 0.850f}, //title_bg
|
||||
theme::constexpr_color{0.165f, 0.365f, 0.506f, 1.000f}, //title_bg_active
|
||||
theme::constexpr_color{0.243f, 0.443f, 0.624f, 0.850f}, //title_collapsed
|
||||
theme::constexpr_color{0.902f, 0.843f, 0.843f, 0.875f}, //message_panel
|
||||
theme::constexpr_color{0.196f, 1.000f, 0.196f, 1.000f}, //auto_complete_selected
|
||||
theme::constexpr_color{0.000f, 0.000f, 0.000f, 1.000f}, //auto_complete_non_selected
|
||||
theme::constexpr_color{0.000f, 0.000f, 0.000f, 0.392f}, //auto_complete_separator
|
||||
theme::constexpr_color{0.519f, 0.118f, 0.715f, 1.000f}, //cmd_backlog
|
||||
theme::constexpr_color{1.000f, 0.430f, 0.059f, 1.000f}, //cmd_history_completed
|
||||
theme::constexpr_color{0.901f, 0.843f, 0.843f, 0.784f}, //log_level_drop_down_list_bg
|
||||
theme::constexpr_color{0.443f, 0.705f, 1.000f, 1.000f}, //log_level_active
|
||||
theme::constexpr_color{0.443f, 0.705f, 0.784f, 0.705f}, //log_level_hovered
|
||||
theme::constexpr_color{0.443f, 0.623f, 0.949f, 1.000f}, //log_level_selected
|
||||
theme::constexpr_color{0.000f, 0.000f, 0.000f, 0.000f}, //scrollbar_bg
|
||||
theme::constexpr_color{0.470f, 0.470f, 0.588f, 1.000f}, //scrollbar_grab
|
||||
theme::constexpr_color{0.392f, 0.392f, 0.509f, 1.000f}, //scrollbar_grab_active
|
||||
theme::constexpr_color{0.509f, 0.509f, 0.666f, 1.000f}, //scrollbar_grab_hovered
|
||||
theme::constexpr_color{0.470f, 0.470f, 0.470f, 1.000f}, //filter_hint
|
||||
theme::constexpr_color{0.100f, 0.100f, 0.100f, 1.000f}, //filter_text
|
||||
theme::constexpr_color{0.549f, 0.196f, 0.039f, 1.000f}, //matching_text
|
||||
{
|
||||
theme::constexpr_color{0.078f, 0.117f, 0.764f, 1.f}, // log_level::trace
|
||||
theme::constexpr_color{0.100f, 0.100f, 0.100f, 1.f}, // log_level::debug
|
||||
theme::constexpr_color{0.301f, 0.529f, 0.000f, 1.f}, // log_level::info
|
||||
theme::constexpr_color{0.784f, 0.431f, 0.058f, 1.f}, // log_level::warning
|
||||
theme::constexpr_color{0.901f, 0.117f, 0.117f, 1.f}, // log_level::error
|
||||
theme::constexpr_color{0.901f, 0.117f, 0.117f, 1.f}, // log_level::critical
|
||||
}
|
||||
};
|
||||
|
||||
constexpr theme cherry {
|
||||
"Dark Cherry",
|
||||
theme::constexpr_color{0.649f, 0.661f, 0.669f, 1.000f}, //text
|
||||
theme::constexpr_color{0.130f, 0.140f, 0.170f, 1.000f}, //window_bg
|
||||
theme::constexpr_color{0.310f, 0.310f, 1.000f, 0.000f}, //border
|
||||
theme::constexpr_color{0.000f, 0.000f, 0.000f, 0.000f}, //border_shadow
|
||||
theme::constexpr_color{0.470f, 0.770f, 0.830f, 0.140f}, //button
|
||||
theme::constexpr_color{0.455f, 0.198f, 0.301f, 0.860f}, //button_hovered
|
||||
theme::constexpr_color{0.455f, 0.198f, 0.301f, 1.000f}, //button_active
|
||||
theme::constexpr_color{0.200f, 0.220f, 0.270f, 1.000f}, //frame_bg
|
||||
theme::constexpr_color{0.455f, 0.198f, 0.301f, 0.780f}, //frame_bg_hovered
|
||||
theme::constexpr_color{0.455f, 0.198f, 0.301f, 1.000f}, //frame_bg_active
|
||||
theme::constexpr_color{0.455f, 0.198f, 0.301f, 0.430f}, //text_selected_bg
|
||||
theme::constexpr_color{0.710f, 0.202f, 0.207f, 1.000f}, //check_mark
|
||||
theme::constexpr_color{0.232f, 0.201f, 0.271f, 1.000f}, //title_bg
|
||||
theme::constexpr_color{0.502f, 0.075f, 0.256f, 1.000f}, //title_bg_active
|
||||
theme::constexpr_color{0.200f, 0.220f, 0.270f, 0.750f}, //title_bg_collapsed
|
||||
theme::constexpr_color{0.100f, 0.100f, 0.100f, 0.500f}, //message_panel
|
||||
theme::constexpr_color{1.000f, 1.000f, 1.000f, 1.000f}, //auto_complete_selected
|
||||
theme::constexpr_color{0.500f, 0.450f, 0.450f, 1.000f}, //auto_complete_non_selected
|
||||
theme::constexpr_color{0.600f, 0.600f, 0.600f, 1.000f}, //auto_complete_separator
|
||||
theme::constexpr_color{0.860f, 0.930f, 0.890f, 1.000f}, //cmd_backlog
|
||||
theme::constexpr_color{0.153f, 0.596f, 0.498f, 1.000f}, //cmd_history_completed
|
||||
theme::constexpr_color{0.100f, 0.100f, 0.100f, 0.860f}, //log_level_drop_down_list_bg
|
||||
theme::constexpr_color{0.730f, 0.130f, 0.370f, 1.000f}, //log_level_active
|
||||
theme::constexpr_color{0.450f, 0.190f, 0.300f, 0.430f}, //log_level_hovered
|
||||
theme::constexpr_color{0.730f, 0.130f, 0.370f, 0.580f}, //log_level_selected
|
||||
theme::constexpr_color{0.000f, 0.000f, 0.000f, 0.000f}, //scrollbar_bg
|
||||
theme::constexpr_color{0.690f, 0.690f, 0.690f, 0.800f}, //scrollbar_grab
|
||||
theme::constexpr_color{0.490f, 0.490f, 0.490f, 0.800f}, //scrollbar_grab_active
|
||||
theme::constexpr_color{0.490f, 0.490f, 0.490f, 1.000f}, //scrollbar_grab_hovered
|
||||
theme::constexpr_color{0.649f, 0.661f, 0.669f, 1.000f}, //filter_hint
|
||||
theme::constexpr_color{1.000f, 1.000f, 1.000f, 1.000f}, //filter_text
|
||||
theme::constexpr_color{0.490f, 0.240f, 1.000f, 1.000f}, //matching_text
|
||||
{
|
||||
theme::constexpr_color{0.549f, 0.561f, 0.569f, 1.f}, // log_level::trace
|
||||
theme::constexpr_color{0.153f, 0.596f, 0.498f, 1.f}, // log_level::debug
|
||||
theme::constexpr_color{0.459f, 0.686f, 0.129f, 1.f}, // log_level::info
|
||||
theme::constexpr_color{0.839f, 0.749f, 0.333f, 1.f}, // log_level::warning
|
||||
theme::constexpr_color{1.000f, 0.420f, 0.408f, 1.f}, // log_level::error
|
||||
theme::constexpr_color{1.000f, 0.420f, 0.408f, 1.f}, // log_level::critical
|
||||
},
|
||||
};
|
||||
|
||||
constexpr std::array list {
|
||||
cherry,
|
||||
light
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //IMTERM_UTILS_HPP
|
||||
@@ -17,14 +17,14 @@
|
||||
|
||||
#include "../detours/detours.h"
|
||||
|
||||
#include "wrapped_swapchain.h"
|
||||
//#include "wrapped_swapchain.h"
|
||||
|
||||
// Dx12 overlay code adoptes from
|
||||
// https://github.com/bruhmoment21/UniversalHookX
|
||||
|
||||
// MipMap hooks
|
||||
typedef void(__fastcall* PFN_CreateSampler)(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDesc, D3D12_CPU_DESCRIPTOR_HANDLE DestDescriptor);
|
||||
static inline PFN_CreateSampler orgCreateSampler = nullptr;
|
||||
static inline PFN_CreateSampler o_CreateSampler = nullptr;
|
||||
|
||||
typedef struct FfxFrameGenerationConfig
|
||||
{
|
||||
@@ -50,7 +50,7 @@ static ID3D12Resource* g_mainRenderTargetResource[NUM_BACK_BUFFERS] = { };
|
||||
static D3D12_CPU_DESCRIPTOR_HANDLE g_mainRenderTargetDescriptor[NUM_BACK_BUFFERS] = { };
|
||||
|
||||
typedef void(WINAPI* PFN_ExecuteCommandLists)(ID3D12CommandQueue*, UINT, ID3D12CommandList* const*);
|
||||
typedef ULONG(WINAPI* PFN_Release)(IUnknown*);
|
||||
typedef ULONG(WINAPI* PFN_CommandQueueRelease)(IUnknown*);
|
||||
|
||||
typedef void* (WINAPI* PFN_ffxGetDX12SwapchainPtr)(void* ffxSwapChain);
|
||||
typedef int32_t(WINAPI* PFN_ffxCreateFrameinterpolationSwapchainForHwndDX12)(HWND hWnd, const DXGI_SWAP_CHAIN_DESC1* desc1,
|
||||
@@ -69,7 +69,7 @@ static PFN_CreateCommandQueue oCreateCommandQueue = nullptr;
|
||||
static PFN_CreateDXGIFactory oCreateDXGIFactory = nullptr;
|
||||
static PFN_CreateDXGIFactory1 oCreateDXGIFactory1 = nullptr;
|
||||
static PFN_CreateDXGIFactory2 oCreateDXGIFactory2 = nullptr;
|
||||
static PFN_Release oCommandQueueRelease = nullptr;
|
||||
static PFN_CommandQueueRelease oCommandQueueRelease = nullptr;
|
||||
|
||||
// Dx12
|
||||
static PFN_Present oPresent_Dx12 = nullptr;
|
||||
@@ -410,28 +410,28 @@ static void hkCreateSampler(ID3D12Device* device, const D3D12_SAMPLER_DESC* pDes
|
||||
Config::Instance()->lastMipBias = newDesc.MipLODBias;
|
||||
}
|
||||
|
||||
return orgCreateSampler(device, &newDesc, DestDescriptor);
|
||||
return o_CreateSampler(device, &newDesc, DestDescriptor);
|
||||
}
|
||||
|
||||
|
||||
static void HookToDevice(ID3D12Device* InDevice)
|
||||
{
|
||||
if (!ImGuiOverlayDx12::IsEarlyBind() && orgCreateSampler != nullptr || InDevice == nullptr)
|
||||
if (!ImGuiOverlayDx12::IsEarlyBind() && o_CreateSampler != nullptr || InDevice == nullptr)
|
||||
return;
|
||||
|
||||
// Get the vtable pointer
|
||||
PVOID* pVTable = *(PVOID**)InDevice;
|
||||
|
||||
// Get the address of the SetComputeRootSignature function from the vtable
|
||||
orgCreateSampler = (PFN_CreateSampler)pVTable[22];
|
||||
o_CreateSampler = (PFN_CreateSampler)pVTable[22];
|
||||
|
||||
// Apply the detour
|
||||
if (orgCreateSampler != nullptr)
|
||||
if (o_CreateSampler != nullptr)
|
||||
{
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
DetourAttach(&(PVOID&)orgCreateSampler, hkCreateSampler);
|
||||
DetourAttach(&(PVOID&)o_CreateSampler, hkCreateSampler);
|
||||
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
@@ -1048,7 +1048,7 @@ static ffxReturnCode_t hkFfxConfigure_FSR3(ffxContext* context, const ffxConfigu
|
||||
|
||||
#pragma region Hooks for ExecuteCommandLists
|
||||
|
||||
static void WINAPI hkExecuteCommandLists_Dx12(ID3D12CommandQueue* pCommandQueue, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
|
||||
static void WINAPI hkExecuteCommandLists(ID3D12CommandQueue* pCommandQueue, UINT NumCommandLists, ID3D12CommandList* const* ppCommandLists)
|
||||
{
|
||||
if (_cqDx12 == nullptr && _dlssCommandList != nullptr)
|
||||
{
|
||||
@@ -1327,7 +1327,7 @@ static HRESULT WINAPI hkCreateCommandQueue(ID3D12Device* This, const D3D12_COMMA
|
||||
|
||||
void** pCommandQueueVTable = *reinterpret_cast<void***>(cq);
|
||||
|
||||
oCommandQueueRelease = (PFN_Release)pCommandQueueVTable[2];
|
||||
oCommandQueueRelease = (PFN_CommandQueueRelease)pCommandQueueVTable[2];
|
||||
oExecuteCommandLists_Dx12 = (PFN_ExecuteCommandLists)pCommandQueueVTable[10];
|
||||
|
||||
if (oExecuteCommandLists_Dx12 != nullptr)
|
||||
@@ -1337,7 +1337,7 @@ static HRESULT WINAPI hkCreateCommandQueue(ID3D12Device* This, const D3D12_COMMA
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
DetourAttach(&(PVOID&)oExecuteCommandLists_Dx12, hkExecuteCommandLists_Dx12);
|
||||
DetourAttach(&(PVOID&)oExecuteCommandLists_Dx12, hkExecuteCommandLists);
|
||||
DetourAttach(&(PVOID&)oCommandQueueRelease, hkCommandQueueRelease);
|
||||
|
||||
DetourTransactionCommit();
|
||||
@@ -1557,7 +1557,7 @@ static bool CheckDx12(ID3D12Device* InDevice)
|
||||
DetourTransactionBegin();
|
||||
DetourUpdateThread(GetCurrentThread());
|
||||
|
||||
DetourAttach(&(PVOID&)oExecuteCommandLists_Dx12, hkExecuteCommandLists_Dx12);
|
||||
DetourAttach(&(PVOID&)oExecuteCommandLists_Dx12, hkExecuteCommandLists);
|
||||
|
||||
DetourTransactionCommit();
|
||||
}
|
||||
@@ -2550,7 +2550,7 @@ void DeatachAllHooks()
|
||||
|
||||
if (oExecuteCommandLists_Dx12 != nullptr)
|
||||
{
|
||||
DetourDetach(&(PVOID&)oExecuteCommandLists_Dx12, hkExecuteCommandLists_Dx12);
|
||||
DetourDetach(&(PVOID&)oExecuteCommandLists_Dx12, hkExecuteCommandLists);
|
||||
oExecuteCommandLists_Dx12 = nullptr;
|
||||
}
|
||||
|
||||
@@ -2656,10 +2656,10 @@ void DeatachAllHooks()
|
||||
offxFsr3ConfigureFrameGeneration_FSR3 = nullptr;
|
||||
}
|
||||
|
||||
if (orgCreateSampler != nullptr)
|
||||
if (o_CreateSampler != nullptr)
|
||||
{
|
||||
DetourDetach(&(PVOID&)orgCreateSampler, hkCreateSampler);
|
||||
orgCreateSampler = nullptr;
|
||||
DetourDetach(&(PVOID&)o_CreateSampler, hkCreateSampler);
|
||||
o_CreateSampler = nullptr;
|
||||
}
|
||||
|
||||
DetourTransactionCommit();
|
||||
|
||||
+3
-2
@@ -25,8 +25,9 @@
|
||||
// Enables logging of DLSS NV Parameters
|
||||
//#define DLSS_PARAM_DUMP
|
||||
|
||||
inline HMODULE dllModule;
|
||||
inline DWORD processId;
|
||||
inline static HMODULE dllModule;
|
||||
inline static HMODULE nvngxModule;
|
||||
inline static DWORD processId;
|
||||
|
||||
#define LOG_TRACE(msg, ...) \
|
||||
spdlog::trace(__FUNCTION__ " " msg, ##__VA_ARGS__)
|
||||
|
||||
Reference in New Issue
Block a user