Skip to content

Commit a2d5073

Browse files
committed
refactor(native): multi-backend hook architecture with per-API files
- Split monolithic hook into hook_d3d9/d3d11/d3d12.cpp + shared hook_common.h - Remove kiero_all.cpp; use explicit kiero::locate<> per backend in MainThread - Replace IDXGISwapChain3 with IDXGISwapChain for COM compatibility - Remove Process namespace; use g_GameWindow from swapchain desc (kiero API) - D3D11: create persistent backbuffer RTV in Init, OMSetRenderTargets in Render - D3D9/D3D11: viewport/scissor state save-restore to prevent game clipping - Add DEBUG_LOG conditional compilation (NDEBUG -> compiled out in Release) - Add DPI-aware mouse coordinate scaling (clientRect -> backbuffer ratio) - GL/VK: proper init path (Win32 only, C# handles backend) - Add GetDevice IUnknown fallback for wrapped swapchains - Update README with new architecture diagram and per-backend table
1 parent 5837a62 commit a2d5073

10 files changed

Lines changed: 389 additions & 274 deletions

File tree

‎README.md‎

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,33 @@ cd Android && ./gradlew :library:assembleRelease
8484

8585
## Windows Architecture
8686

87-
The Windows native DLL (`StArray.ModManager.Windows.Native.dll`) uses
88-
[kiero2](https://github.com/kirchesz/kiero2) + [MinHook](https://github.com/TsudaKageyu/minhook) to
89-
detect and hook the game's graphics API at runtime.
87+
The native DLL (`StArray.ModManager.Windows.Native.dll`) uses
88+
[kiero2](https://github.com/kirchesz/kiero2) for graphics API detection and
89+
[MinHook](https://github.com/TsudaKageyu/minhook) for `Present` hooking.
9090

91-
| Backend | Support |
92-
|---------|---------|
93-
| D3D12 | Descriptor heap + Command list |
94-
| D3D11 | Device + Context |
95-
| D3D9 | Device |
96-
| OpenGL / Vulkan | Detected only |
91+
**Per-backend hook files** (`Native/`):
9792

98-
The C# side (`ImGuiRenderer`) is backend-agnostic — it provides init/shutdown/render callbacks and
99-
the native DLL handles all platform-specific `ImGui_Impl*` setup.
93+
| File | Backend | Init | Render |
94+
|------|---------|------|--------|
95+
| `hook_d3d12.cpp` | D3D12 | Descriptor heaps, command list, RTV per-frame contexts | Resource barriers + OMSetRenderTargets |
96+
| `hook_d3d11.cpp` | D3D11 | Device + Context + persistent backbuffer RTV | OMSetRenderTargets + RenderDrawData |
97+
| `hook_d3d9.cpp` | D3D9 | SwapChain QI → Device | Viewport/scissor save-restore |
98+
| `main.cpp` | GL/VK | Win32 init only (C# handles backend) | C# render callback only |
99+
100+
**Unified dispatch** (`main.cpp` `hkPresent`):
101+
- All backends share `DisplaySize` (from swapchain desc), `ImGui_ImplWin32_NewFrame`, WndProc hook
102+
- `DEBUG_LOG` conditional compilation (`NDEBUG` → compiled out in Release)
103+
- Window handle from `SwapChain::GetDesc().OutputWindow` (kiero approach)
100104

101105
```mermaid
102106
flowchart LR
103107
CSharp[C# ImGuiRenderer] -->|P/Invoke Init| Native[Native DLL]
104-
Native -->|kiero| API[D3D9/11/12]
105-
API -->|MinHook| Present[Present Hook]
106-
Present -->|callback| CSharp
108+
Native -->|kiero2 detect| API[D3D9/11/12/GL/VK]
109+
API -->|MinHook| Present[hkPresent]
110+
Present -->|dispatch| D3D11[hook_d3d11]
111+
Present -->|dispatch| D3D12[hook_d3d12]
112+
Present -->|dispatch| D3D9[hook_d3d9]
113+
D3D11 & D3D12 & D3D9 -->|callback| CSharp
107114
CSharp -->|ImGui.NET| cimgui[cimgui.dll]
108115
```
109116

‎StArray.ModManager.Windows/Managed.cs‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,17 +55,20 @@ public static int Entry(int argc, IntPtr argv)
5555
Logger.Info($"{nameof(Managed)}-Benchmark", $"Args parse ({argc} args): {Benchmark.End():F3}s");
5656

5757
Benchmark.Begin();
58+
// args[0]: mods directory (from corehold.json entrypoint_string_args)
5859
string modsPath = args.Length > 0
5960
? Path.GetFullPath(args[0])
60-
: Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "..", "mods");
61-
AssemblyPath = Path.Combine(Path.GetDirectoryName(modsPath)!, "manager", typeof(Managed).Namespace + ".dll");
61+
: Path.Combine(AppContext.BaseDirectory, "..", "mods");
62+
63+
// Managed directory = where our DLLs live (AppContext.BaseDirectory for CoreCLR host)
64+
string managedDir = AppContext.BaseDirectory;
65+
AssemblyPath = Path.Combine(managedDir, typeof(Managed).Namespace + ".dll");
6266
if (!Directory.Exists(modsPath))
6367
Directory.CreateDirectory(modsPath);
6468
Writer = new StreamWriter(Path.Combine(Path.GetDirectoryName(modsPath), "log.txt"), append: false);
6569
Writer.AutoFlush = true;
6670
Logger.Info($"{nameof(Managed)}-Benchmark", $"Path resolve: {Benchmark.End():F3}s");
67-
Il2CppFunctions.SetIl2CppLibraryPath(Path.Combine(new DirectoryInfo(modsPath).Parent.Parent.FullName,"GameAssembly.dll"));
68-
ModManagerUI modManagerUI = new(new ModLoader(modsPath), Path.GetDirectoryName(AssemblyPath));
71+
ModManagerUI modManagerUI = new(new ModLoader(modsPath), managedDir);
6972

7073
// Use DX12 renderer — hooks IDXGISwapChain::Present via vtable + MinHook
7174
ImGuiRenderer.OnRender += modManagerUI.Render;

‎StArray.ModManager.Windows/Native/CMakeLists.txt‎

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,31 @@ target_include_directories(MinHook PUBLIC minhook/include)
2020
target_compile_definitions(MinHook PRIVATE _CRT_SECURE_NO_WARNINGS)
2121

2222
# ---- kiero2 (submodule, static lib, all backends except D3D10) ----
23-
# Single translation unit ensures consistent KIERO_IMPL_FREE_SLOT values
24-
add_library(kiero STATIC kiero_all.cpp)
23+
# Compile each backend separately, using KIERO_IMPL_FIRST_SLOT to offset enum values
24+
# to match the include order in main.h: d3d9=1,d3d11=2,d3d12=3,opengl=4,vulkan=5
25+
add_library(kiero STATIC
26+
kiero2/kiero_intern.cpp
27+
kiero2/kiero_d3d9.cpp
28+
kiero2/kiero_d3d11.cpp
29+
kiero2/kiero_d3d12.cpp
30+
kiero2/kiero_opengl.cpp
31+
kiero2/kiero_vulkan.cpp
32+
)
2533
target_include_directories(kiero PUBLIC . kiero2)
2634
target_compile_definitions(kiero PRIVATE KIERO_BUILD_D3D9 KIERO_BUILD_D3D11 KIERO_BUILD_D3D12 KIERO_BUILD_OPENGL KIERO_BUILD_VULKAN)
35+
set_source_files_properties(kiero2/kiero_d3d9.cpp PROPERTIES COMPILE_DEFINITIONS "KIERO_IMPL_FIRST_SLOT=0")
36+
set_source_files_properties(kiero2/kiero_d3d11.cpp PROPERTIES COMPILE_DEFINITIONS "KIERO_IMPL_FIRST_SLOT=1")
37+
set_source_files_properties(kiero2/kiero_d3d12.cpp PROPERTIES COMPILE_DEFINITIONS "KIERO_IMPL_FIRST_SLOT=2")
38+
set_source_files_properties(kiero2/kiero_opengl.cpp PROPERTIES COMPILE_DEFINITIONS "KIERO_IMPL_FIRST_SLOT=3")
39+
set_source_files_properties(kiero2/kiero_vulkan.cpp PROPERTIES COMPILE_DEFINITIONS "KIERO_IMPL_FIRST_SLOT=4")
2740

2841
# ---- Main hook DLL ----
29-
add_library(${PROJECT_NAME} SHARED main.cpp)
42+
add_library(${PROJECT_NAME} SHARED
43+
main.cpp
44+
hook_d3d9.cpp
45+
hook_d3d11.cpp
46+
hook_d3d12.cpp
47+
)
3048
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "") # no "lib" prefix
3149
target_include_directories(${PROJECT_NAME} PRIVATE . kiero2 minhook/include)
3250
target_link_libraries(${PROJECT_NAME} PRIVATE kiero MinHook d3d12 dxgi ${CMAKE_CURRENT_SOURCE_DIR}/libcimgui.a)
@@ -37,4 +55,7 @@ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
3755
COMMAND ${CMAKE_COMMAND} -E copy_if_different
3856
"$<TARGET_FILE:${PROJECT_NAME}>"
3957
"${CMAKE_CURRENT_SOURCE_DIR}/../bin/${CMAKE_BUILD_TYPE}/net10.0/"
58+
COMMAND ${CMAKE_COMMAND} -E copy_if_different
59+
"$<TARGET_FILE:${PROJECT_NAME}>"
60+
"D:/Softwares/Steam/steamapps/common/A Dance of Fire and Ice/Corehold/managed"
4061
)
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Shared hook state and helpers
2+
#pragma once
3+
#include "main.h"
4+
#include "sharpdelegate.h"
5+
6+
extern ImGuiCallbacks imgui_callbacks;
7+
extern bool g_BridgeMode;
8+
9+
typedef HRESULT(APIENTRY* PresentFn)(IDXGISwapChain*, UINT, UINT);
10+
extern PresentFn oPresent;
11+
typedef void(APIENTRY* ExecuteCommandListsFn)(ID3D12CommandQueue*, UINT, ID3D12CommandList*);
12+
extern ExecuteCommandListsFn oExecuteCommandLists;
13+
14+
extern bool ShowMenu;
15+
extern bool ImGui_Initialised;
16+
17+
// ---- window handle (from swapchain desc via kiero) ----
18+
extern HWND g_GameWindow;
19+
extern WNDPROC g_OriginalWndProc;
20+
21+
namespace DX12 {
22+
extern ID3D12Device* Device;
23+
extern ID3D12DescriptorHeap* RTVHeap, *SRVHeap;
24+
extern ID3D12GraphicsCommandList* CmdList;
25+
extern ID3D12CommandQueue* CmdQueue;
26+
struct FCtx { ID3D12CommandAllocator* Alloc; ID3D12Resource* Res; D3D12_CPU_DESCRIPTOR_HANDLE Handle; };
27+
extern UINT BufCount; extern FCtx* Frames;
28+
void Init(IDXGISwapChain* sc);
29+
void Render(IDXGISwapChain* sc);
30+
}
31+
namespace DX11 { extern ID3D11Device* Device; extern ID3D11DeviceContext* Context; extern ID3D11RenderTargetView* MainRTV;
32+
extern bool Initialized;
33+
void Init(IDXGISwapChain* sc); void Render(IDXGISwapChain* sc); }
34+
namespace DX9 { extern IDirect3DDevice9* Device;
35+
void Init(IDXGISwapChain* sc); void Render(IDXGISwapChain* sc); }
36+
37+
LRESULT APIENTRY WndProc(HWND h, UINT m, WPARAM w, LPARAM l);
38+
void APIENTRY hkExecuteCommandLists(ID3D12CommandQueue*, UINT, ID3D12CommandList*);
39+
HRESULT APIENTRY hkPresent(IDXGISwapChain*, UINT, UINT);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// D3D11 hook: init + render
2+
#include "hook_common.h"
3+
4+
namespace DX11 {
5+
ID3D11Device* Device = nullptr;
6+
ID3D11DeviceContext* Context = nullptr;
7+
ID3D11RenderTargetView* MainRTV = nullptr;
8+
bool Initialized = false;
9+
10+
void Init(IDXGISwapChain* sc) {
11+
DEBUG_LOG("D3D11::Init: sc=%p, getting device...", sc);
12+
HRESULT hr = sc->GetDevice(__uuidof(ID3D11Device), (void**)&Device);
13+
if (FAILED(hr)) {
14+
IUnknown* unk = nullptr;
15+
if (SUCCEEDED(sc->GetDevice(IID_IUnknown, (void**)&unk)) && unk) {
16+
hr = unk->QueryInterface(__uuidof(ID3D11Device), (void**)&Device);
17+
unk->Release();
18+
}
19+
}
20+
if (FAILED(hr) || !Device) {
21+
DEBUG_LOG("D3D11::Init: GetDevice FAILED hr=0x%08X", hr); return;
22+
}
23+
Device->GetImmediateContext(&Context);
24+
25+
ID3D11Texture2D* backBuf = nullptr;
26+
sc->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&backBuf);
27+
if (backBuf) {
28+
Device->CreateRenderTargetView(backBuf, nullptr, &MainRTV);
29+
backBuf->Release();
30+
}
31+
DEBUG_LOG("D3D11::Init: device=%p context=%p rtv=%p", Device, Context, MainRTV);
32+
33+
imgui_callbacks.init_callback();
34+
ImGui_ImplWin32_Init(g_GameWindow);
35+
ImGui_ImplDX11_Init(Device, Context);
36+
Initialized = true;
37+
DEBUG_LOG("D3D11::Init: complete");
38+
}
39+
40+
void Render(IDXGISwapChain*) {
41+
ImGui_ImplDX11_NewFrame();
42+
if (imgui_callbacks.render_callback) imgui_callbacks.render_callback();
43+
if (MainRTV) Context->OMSetRenderTargets(1, &MainRTV, nullptr);
44+
ImGui_ImplDX11_RenderDrawData(igGetDrawData());
45+
}
46+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// D3D12 hook: init + render + ExecuteCommandLists
2+
#include "hook_common.h"
3+
4+
namespace DX12 {
5+
ID3D12Device* Device = nullptr;
6+
ID3D12DescriptorHeap* RTVHeap = nullptr, *SRVHeap = nullptr;
7+
ID3D12GraphicsCommandList* CmdList = nullptr;
8+
ID3D12CommandQueue* CmdQueue = nullptr;
9+
UINT BufCount = 0; FCtx* Frames = nullptr;
10+
11+
void Init(IDXGISwapChain* sc) {
12+
DEBUG_LOG("D3D12::Init: starting, sc=%p", sc);
13+
HRESULT hr = sc->GetDevice(__uuidof(ID3D12Device), (void**)&Device);
14+
if (FAILED(hr)) {
15+
IUnknown* unk = nullptr;
16+
if (SUCCEEDED(sc->GetDevice(IID_IUnknown, (void**)&unk)) && unk) {
17+
hr = unk->QueryInterface(__uuidof(ID3D12Device), (void**)&Device); unk->Release();
18+
}
19+
}
20+
if (FAILED(hr)) { DEBUG_LOG("D3D12::Init: GetDevice FAILED hr=0x%08X", hr); return; }
21+
DXGI_SWAP_CHAIN_DESC sd; sc->GetDesc(&sd);
22+
BufCount = sd.BufferCount; Frames = new FCtx[BufCount];
23+
DEBUG_LOG("D3D12::Init: device=%p bufCount=%u wxh=%ux%u", Device, BufCount, sd.BufferDesc.Width, sd.BufferDesc.Height);
24+
25+
D3D12_DESCRIPTOR_HEAP_DESC srvDh = { D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, BufCount, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE };
26+
if (Device->CreateDescriptorHeap(&srvDh, IID_PPV_ARGS(&SRVHeap)) != S_OK) { DEBUG_LOG("D3D12::Init: SRV heap FAILED"); return; }
27+
DEBUG_LOG("D3D12::Init: SRV heap=%p", SRVHeap);
28+
29+
ID3D12CommandAllocator* alloc;
30+
if (Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&alloc)) != S_OK) { DEBUG_LOG("D3D12::Init: CommandAllocator FAILED"); return; }
31+
for (UINT i = 0; i < BufCount; i++) Frames[i].Alloc = alloc;
32+
33+
if (Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, alloc, nullptr, IID_PPV_ARGS(&CmdList)) != S_OK || CmdList->Close() != S_OK) {
34+
DEBUG_LOG("D3D12::Init: CommandList FAILED"); return;
35+
}
36+
DEBUG_LOG("D3D12::Init: CmdList=%p", CmdList);
37+
38+
D3D12_DESCRIPTOR_HEAP_DESC rtvDh = { D3D12_DESCRIPTOR_HEAP_TYPE_RTV, BufCount, D3D12_DESCRIPTOR_HEAP_FLAG_NONE, 1 };
39+
if (Device->CreateDescriptorHeap(&rtvDh, IID_PPV_ARGS(&RTVHeap)) != S_OK) { DEBUG_LOG("D3D12::Init: RTV heap FAILED"); return; }
40+
DEBUG_LOG("D3D12::Init: RTV heap=%p", RTVHeap);
41+
42+
UINT rtvSize = Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
43+
D3D12_CPU_DESCRIPTOR_HANDLE rtvH = RTVHeap->GetCPUDescriptorHandleForHeapStart();
44+
for (UINT i = 0; i < BufCount; i++) {
45+
ID3D12Resource* buf = nullptr; Frames[i].Handle = rtvH;
46+
sc->GetBuffer(i, IID_PPV_ARGS(&buf)); Device->CreateRenderTargetView(buf, nullptr, rtvH);
47+
Frames[i].Res = buf; rtvH.ptr += rtvSize;
48+
}
49+
DEBUG_LOG("D3D12::Init: %u RTVs created", BufCount);
50+
51+
imgui_callbacks.init_callback();
52+
ImGui_ImplWin32_Init(g_GameWindow);
53+
54+
static int srvIdx = 0;
55+
ImGui_ImplDX12_InitInfo info = {};
56+
info.Device = Device; info.CommandQueue = CmdQueue;
57+
info.NumFramesInFlight = (int)BufCount; info.RTVFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
58+
info.SrvDescriptorHeap = SRVHeap;
59+
info.SrvDescriptorAllocFn = [](ImGui_ImplDX12_InitInfo* i, D3D12_CPU_DESCRIPTOR_HANDLE* c, D3D12_GPU_DESCRIPTOR_HANDLE* g) {
60+
UINT inc = i->Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
61+
*c = i->SrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart(); c->ptr += inc * (++srvIdx);
62+
*g = i->SrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart(); g->ptr += inc * srvIdx;
63+
};
64+
info.SrvDescriptorFreeFn = [](ImGui_ImplDX12_InitInfo*, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_GPU_DESCRIPTOR_HANDLE) {};
65+
ImGui_ImplDX12_Init(&info);
66+
ImGui_ImplDX12_CreateDeviceObjects();
67+
DEBUG_LOG("D3D12::Init: ImGui DX12 backend initialized, CmdQueue=%p", CmdQueue);
68+
}
69+
70+
void Render(IDXGISwapChain* sc) {
71+
if (!CmdQueue) { DEBUG_LOG("D3D12::Render: CmdQueue is null, skipping"); return; }
72+
ImGui_ImplDX12_NewFrame();
73+
if (imgui_callbacks.render_callback) imgui_callbacks.render_callback();
74+
75+
static UINT frameIdx = 0;
76+
auto& ctx = Frames[frameIdx++ % BufCount];
77+
ctx.Alloc->Reset();
78+
D3D12_RESOURCE_BARRIER bar = { D3D12_RESOURCE_BARRIER_TYPE_TRANSITION };
79+
bar.Transition = { ctx.Res, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET };
80+
CmdList->Reset(ctx.Alloc, nullptr);
81+
CmdList->ResourceBarrier(1, &bar);
82+
CmdList->OMSetRenderTargets(1, &ctx.Handle, FALSE, nullptr);
83+
CmdList->SetDescriptorHeaps(1, &SRVHeap);
84+
ImGui_ImplDX12_RenderDrawData(igGetDrawData(), CmdList);
85+
bar.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
86+
bar.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
87+
CmdList->ResourceBarrier(1, &bar);
88+
CmdList->Close();
89+
CmdQueue->ExecuteCommandLists(1, reinterpret_cast<ID3D12CommandList* const*>(&CmdList));
90+
}
91+
}
92+
93+
void APIENTRY hkExecuteCommandLists(ID3D12CommandQueue* queue, UINT n, ID3D12CommandList* lists) {
94+
if (!DX12::CmdQueue) { DX12::CmdQueue = queue; DEBUG_LOG("hkExecuteCommandLists: CmdQueue captured=%p", queue); }
95+
oExecuteCommandLists(queue, n, lists);
96+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// D3D9 hook: init + render
2+
#include "hook_common.h"
3+
4+
namespace DX9 {
5+
IDirect3DDevice9* Device = nullptr;
6+
7+
void Init(IDXGISwapChain* sc) {
8+
DEBUG_LOG("D3D9::Init: sc=%p, querying IDirect3DSwapChain9...", sc);
9+
IDirect3DSwapChain9* swap = nullptr;
10+
HRESULT hr = sc->QueryInterface(__uuidof(IDirect3DSwapChain9), (void**)&swap);
11+
if (SUCCEEDED(hr) && swap) { hr = swap->GetDevice(&Device); swap->Release(); }
12+
if (FAILED(hr) || !Device) { DEBUG_LOG("D3D9::Init: FAILED hr=0x%08X device=%p", hr, Device); return; }
13+
DEBUG_LOG("D3D9::Init: device=%p OK", Device);
14+
imgui_callbacks.init_callback();
15+
ImGui_ImplWin32_Init(g_GameWindow);
16+
ImGui_ImplDX9_Init(Device);
17+
DEBUG_LOG("D3D9::Init: complete");
18+
}
19+
20+
void Render(IDXGISwapChain*) {
21+
// Save viewport + scissor state (game may clip our ImGui rendering)
22+
D3DVIEWPORT9 savedVp;
23+
Device->GetViewport(&savedVp);
24+
DWORD savedScissor = FALSE;
25+
Device->GetRenderState(D3DRS_SCISSORTESTENABLE, &savedScissor);
26+
27+
ImGui_ImplDX9_NewFrame();
28+
if (imgui_callbacks.render_callback) imgui_callbacks.render_callback();
29+
30+
// Set full viewport + disable scissor
31+
ImGuiIO* io = igGetIO();
32+
D3DVIEWPORT9 vp = { 0, 0, (DWORD)io->DisplaySize.x, (DWORD)io->DisplaySize.y, 0.f, 1.f };
33+
Device->SetViewport(&vp);
34+
Device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
35+
36+
ImGui_ImplDX9_RenderDrawData(igGetDrawData());
37+
38+
// Restore
39+
Device->SetViewport(&savedVp);
40+
Device->SetRenderState(D3DRS_SCISSORTESTENABLE, savedScissor);
41+
}
42+
}

‎StArray.ModManager.Windows/Native/kiero_all.cpp‎

Lines changed: 0 additions & 15 deletions
This file was deleted.

0 commit comments

Comments
 (0)