1
0
mirror of https://github.com/djhackersdev/bemanitools.git synced 2025-02-20 20:41:10 +01:00

feat: Add bt d3d9 hook specific imgui overlay (#318)

For now, we focus on internal overlays for bemanitools
that hook into an existing d3d9 context. The current
abstraction is fairly thin and should be fine as a start.

Implementations are called “components” and hook
up with a single frame_update function to execute
and logic and drawing updates with imgui
This commit is contained in:
icex2 2025-02-08 23:19:49 +01:00 committed by GitHub
parent a85ce4bc96
commit 3090b9a029
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 189 additions and 0 deletions

View File

@ -161,6 +161,7 @@ include src/main/iidxio-ezusb2/Module.mk
include src/main/iidxio/Module.mk
include src/main/iidxiotest/Module.mk
include src/main/imgui/Module.mk
include src/main/imgui-bt/Module.mk
include src/main/inject/Module.mk
include src/main/jbio-magicbox/Module.mk
include src/main/jbio-p4io/Module.mk

View File

@ -0,0 +1,10 @@
libs += imgui-bt
libs_imgui-bt := \
hook \
hooklib \
util \
imgui \
src_imgui-bt := \
imgui-d3d9-hook.c \

View File

@ -0,0 +1,10 @@
#ifndef IMGUI_BT_CIMGUI_H
#define IMGUI_BT_CIMGUI_H
// Comprehensive header file for including cimgui correctly for integration in this project
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#include "imgui/cimgui.h"
#include "imgui/cimgui_impl_dx9.h"
#include "imgui/cimgui_impl_win32.h"
#endif

View File

@ -0,0 +1,12 @@
#ifndef IMGUI_BT_COMPONENT_H
#define IMGUI_BT_COMPONENT_H
#include "imgui-bt/cimgui.h"
typedef void (*imgui_bt_component_frame_update_t)(ImGuiContext *ctx);
typedef struct imgui_bt_component {
imgui_bt_component_frame_update_t frame_update;
} imgui_bt_component_t;
#endif

View File

@ -0,0 +1,143 @@
#define LOG_MODULE "imgui-d3d9-hook"
#include "hook/d3d9.h"
#include "hook/table.h"
#include "imgui-bt/cimgui.h"
#include "imgui-bt/component.h"
#include "util/defs.h"
#include "util/log.h"
#include "util/mem.h"
typedef LRESULT WINAPI (*RegisterClassA_t)(WNDCLASSA *lpwcx);
typedef LRESULT WINAPI (*WndProc_t)(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static LRESULT WINAPI _imgui_d3d9_hook_RegisterClassA(WNDCLASSA *lpwcx);
static bool _imgui_d3d9_hook_initialized;
static ImGuiContext *_imgui_d3d9_hook_imgui_ctx;
static RegisterClassA_t _imgui_d3d9_hook_original_RegisterClassA;
static WndProc_t _imgui_d3d9_hook_original_wndproc;
static imgui_bt_component_t *_imgui_d3d9_hook_components;
static size_t _imgui_d3d9_hook_component_count;
static const struct hook_symbol _imgui_d3d9_hook_syms[] = {
{.name = "RegisterClassA",
.patch = _imgui_d3d9_hook_RegisterClassA,
.link = (void **) &_imgui_d3d9_hook_original_RegisterClassA},
};
CIMGUI_API LRESULT igImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
static LRESULT WINAPI _imgui_d3d9_hook_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LRESULT result;
result = igImplWin32_WndProcHandler(hWnd, msg, wParam, lParam);
if (result) {
return result;
}
return _imgui_d3d9_hook_original_wndproc(hWnd, msg, wParam, lParam);
}
static LRESULT WINAPI _imgui_d3d9_hook_RegisterClassA(WNDCLASSA *lpwcx)
{
log_info("Swapping out WndProc handler for wrapper handler in RegisterClassA %s", lpwcx->lpszClassName);
_imgui_d3d9_hook_original_wndproc = lpwcx->lpfnWndProc;
lpwcx->lpfnWndProc = _imgui_d3d9_hook_WndProc;
return _imgui_d3d9_hook_original_RegisterClassA(lpwcx);
}
void imgui_d3d9_hook_init(const imgui_bt_component_t *components, size_t component_count)
{
ImGuiIO *io;
ImGuiStyle* style;
log_assert(components);
log_assert(component_count > 0);
_imgui_d3d9_hook_components = (imgui_bt_component_t *) xmalloc(component_count * sizeof(imgui_bt_component_t));
memcpy(_imgui_d3d9_hook_components, components, component_count * sizeof(imgui_bt_component_t));
_imgui_d3d9_hook_component_count = component_count;
_imgui_d3d9_hook_imgui_ctx = igCreateContext(NULL);
io = igGetIO();
io->ConfigFlags = ImGuiConfigFlags_NavEnableKeyboard
| ImGuiConfigFlags_DockingEnable
| ImGuiConfigFlags_ViewportsEnable;
io->MouseDrawCursor = true;
io->IniFilename = NULL;
io->FontAllowUserScaling = true;
hook_table_apply(NULL, "user32.dll", _imgui_d3d9_hook_syms, lengthof(_imgui_d3d9_hook_syms));
// Setup style
style = igGetStyle();
style->Colors[ImGuiCol_WindowBg] = (ImVec4){0.0f, 0.0f, 0.0f, 1.0f};
style->Colors[ImGuiCol_PlotLines] = (ImVec4){1.0f, 1.0f, 0.0f, 1.0f};
_imgui_d3d9_hook_initialized = true;
}
void imgui_d3d9_hook_fini()
{
hook_table_revert(NULL, "user32.dll", _imgui_d3d9_hook_syms, lengthof(_imgui_d3d9_hook_syms));
igImplDX9_Shutdown();
igImplWin32_Shutdown();
igDestroyContext(NULL);
_imgui_d3d9_hook_initialized = false;
}
HRESULT imgui_hook_d3d9_irp_handler(struct hook_d3d9_irp *irp)
{
HRESULT hr;
log_assert(irp);
if (!_imgui_d3d9_hook_initialized) {
return hook_d3d9_irp_invoke_next(irp);
}
switch (irp->op) {
case HOOK_D3D9_IRP_OP_CTX_CREATE_DEVICE:
hr = hook_d3d9_irp_invoke_next(irp);
if (hr == S_OK) {
igImplWin32_Init(irp->args.ctx_create_device.hwnd);
igImplDX9_Init(*irp->args.ctx_create_device.pdev);
}
return hr;
case HOOK_D3D9_IRP_OP_DEV_BEGIN_SCENE:
igImplDX9_NewFrame();
igImplWin32_NewFrame();
igNewFrame();
for (size_t i = 0; i < _imgui_d3d9_hook_component_count; i++) {
_imgui_d3d9_hook_components[i].frame_update(_imgui_d3d9_hook_imgui_ctx);
}
return hook_d3d9_irp_invoke_next(irp);
case HOOK_D3D9_IRP_OP_DEV_END_SCENE:
igRender();
igImplDX9_RenderDrawData(igGetDrawData());
return hook_d3d9_irp_invoke_next(irp);
default:
return hook_d3d9_irp_invoke_next(irp);
}
log_fatal("Illegal state");
}

View File

@ -0,0 +1,13 @@
#ifndef IMGUI_D3D9_HOOK_H
#define IMGUI_D3D9_HOOK_H
#include "hook/d3d9.h"
#include "imgui-bt/component.h"
void imgui_d3d9_hook_init(const imgui_bt_component_t *components, size_t component_count);
void imgui_d3d9_hook_fini();
HRESULT imgui_hook_d3d9_irp_handler(struct hook_d3d9_irp *irp);
#endif