diff --git a/dist/carol/segatools.ini b/dist/carol/segatools.ini index e79cf13..e75f1cd 100644 --- a/dist/carol/segatools.ini +++ b/dist/carol/segatools.ini @@ -64,6 +64,8 @@ subnet=192.168.126.0 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/chuni/segatools.ini b/dist/chuni/segatools.ini index 5b8af0c..3e87cb0 100644 --- a/dist/chuni/segatools.ini +++ b/dist/chuni/segatools.ini @@ -56,6 +56,8 @@ subnet=192.168.139.0 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/chusan/segatools.ini b/dist/chusan/segatools.ini index ee3af18..7ff4d0a 100644 --- a/dist/chusan/segatools.ini +++ b/dist/chusan/segatools.ini @@ -82,6 +82,8 @@ dipsw3=1 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/cxb/segatools.ini b/dist/cxb/segatools.ini index 6d9e5e0..1fe70c8 100644 --- a/dist/cxb/segatools.ini +++ b/dist/cxb/segatools.ini @@ -75,6 +75,8 @@ path=../DEVICE/sram.bin ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. +enable=1 ; Force the game to run windowed. windowed=1 ; Add a frame to the game window if running windowed. diff --git a/dist/diva/segatools.ini b/dist/diva/segatools.ini index 000f5c8..e8db667 100644 --- a/dist/diva/segatools.ini +++ b/dist/diva/segatools.ini @@ -5,7 +5,7 @@ [vfs] ; Insert the path to the game AMFS directory here (contains ICF1 and ICF2) amfs= -; Insert the path to the game Option directory here (contains Axxx directories) +; Insert the path to the game Option (mdata) directory here (contains Mxxx directories) option= ; Create an empty directory somewhere and insert the path here. ; This directory may be shared between multiple SEGA games. @@ -36,6 +36,10 @@ default=127.0.0.1 ; Chunithm is extremely picky about its LAN environment, so leaving this ; setting enabled is strongly recommended. enable=1 +; The final octet of the local host's IP address on the virtualized subnet (so, +; if the keychip subnet is `192.168.32.0` and this value is set to `11`, then the +; local host's virtualized LAN IP is `192.168.32.11`). +addrSuffix=11 ; ----------------------------------------------------------------------------- ; Board settings @@ -54,6 +58,18 @@ dipsw1=1 ; that subnet must start with 192.168. subnet=192.168.78.0 +; ----------------------------------------------------------------------------- +; Misc. hooks settings +; ----------------------------------------------------------------------------- + +[gfx] +; Enables the graphics hook. +enable=1 +; Force the game to run windowed. +windowed=1 +; Add a frame to the game window if running windowed. +framed=0 + ; ----------------------------------------------------------------------------- ; Custom IO settings ; ----------------------------------------------------------------------------- diff --git a/dist/fgo/segatools.ini b/dist/fgo/segatools.ini index 790de88..e9c7c20 100644 --- a/dist/fgo/segatools.ini +++ b/dist/fgo/segatools.ini @@ -85,6 +85,14 @@ freeplay=0 ; Misc. hook settings ; ----------------------------------------------------------------------------- +[gfx] +; Enables the graphics hook. +enable=1 +; Force the game to run windowed. +windowed=0 +; Add a frame to the game window if running windowed. +framed=0 + [touch] ; WinTouch emulation setting. enable=1 diff --git a/dist/mercury/segatools.ini b/dist/mercury/segatools.ini index 0755bac..4e24489 100644 --- a/dist/mercury/segatools.ini +++ b/dist/mercury/segatools.ini @@ -74,6 +74,7 @@ dipsw1=1 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. enable=1 ; Hooks related to the touch boards diff --git a/dist/mu3/segatools.ini b/dist/mu3/segatools.ini index 59ec0d2..43fef6e 100644 --- a/dist/mu3/segatools.ini +++ b/dist/mu3/segatools.ini @@ -70,6 +70,7 @@ dipsw1=1 ; ----------------------------------------------------------------------------- [gfx] +; Enables the graphics hook. enable=1 [unity] diff --git a/divahook/config.c b/divahook/config.c index 29ca5c8..142cf73 100644 --- a/divahook/config.c +++ b/divahook/config.c @@ -8,6 +8,9 @@ #include "board/config.h" #include "board/sg-reader.h" +#include "hooklib/config.h" +#include "hooklib/dvd.h" + #include "divahook/config.h" #include "platform/config.h" @@ -47,6 +50,8 @@ void diva_hook_config_load( platform_config_load(&cfg->platform, filename); amex_config_load(&cfg->amex, filename); aime_config_load(&cfg->aime, filename); + dvd_config_load(&cfg->dvd, filename); + gfx_config_load(&cfg->gfx, filename); diva_dll_config_load(&cfg->dll, filename); slider_config_load(&cfg->slider, filename); } diff --git a/divahook/config.h b/divahook/config.h index a327f47..3b3f1ea 100644 --- a/divahook/config.h +++ b/divahook/config.h @@ -6,15 +6,25 @@ #include "board/sg-reader.h" +#include "hooklib/dvd.h" +#include "hooklib/touch.h" + +#include "gfxhook/config.h" + +#include "platform/config.h" + +#include "divahook/3mpxsc.h" #include "divahook/diva-dll.h" #include "divahook/slider.h" -#include "platform/platform.h" - struct diva_hook_config { struct platform_config platform; struct amex_config amex; struct aime_config aime; + struct dvd_config dvd; + struct gfx_config gfx; + struct touch3mpxsc_config touch3mpxsc; + struct touch_screen_config touch; struct diva_dll_config dll; struct slider_config slider; }; diff --git a/divahook/dllmain.c b/divahook/dllmain.c index 412fe9c..337eff5 100644 --- a/divahook/dllmain.c +++ b/divahook/dllmain.c @@ -22,6 +22,9 @@ #include "divahook/jvs.h" #include "divahook/slider.h" +#include "gfxhook/gfx.h" +#include "gfxhook/gl.h" + #include "hook/process.h" #include "hooklib/serial.h" @@ -38,15 +41,30 @@ static struct diva_hook_config diva_hook_cfg; static DWORD CALLBACK diva_pre_startup(void) { HRESULT hr; + HMODULE dbghelp; dprintf("--- Begin diva_pre_startup ---\n"); + /* Pin dbghelp so the path hooks apply to it. */ + + dbghelp = LoadLibraryW(L"dbghelp.dll"); + + if (dbghelp != NULL) { + dprintf("Pinned debug helper library, hMod=%p\n", dbghelp); + } + else { + dprintf("Failed to load debug helper library!\n"); + } + /* Config load */ diva_hook_config_load(&diva_hook_cfg, L".\\segatools.ini"); /* Hook Win32 APIs */ + dvd_hook_init(&diva_hook_cfg.dvd, diva_hook_mod); + gfx_hook_init(&diva_hook_cfg.gfx); + gfx_gl_hook_init(&diva_hook_cfg.gfx, diva_hook_mod); serial_hook_init(); /* Initialize emulation hooks */ diff --git a/divahook/jvs.c b/divahook/jvs.c index 14d222d..f718438 100644 --- a/divahook/jvs.c +++ b/divahook/jvs.c @@ -63,33 +63,33 @@ static void diva_jvs_read_switches(void *ctx, struct io3_switch_state *out) diva_dll.jvs_poll(&opbtn, &gamebtn); - if (gamebtn & 0x01) { + if (gamebtn & DIVA_IO_GAMEBTN_CIRCLE) { out->p1 |= 1 << 6; } - if (gamebtn & 0x02) { + if (gamebtn & DIVA_IO_GAMEBTN_CROSS) { out->p1 |= 1 << 7; } - if (gamebtn & 0x04) { + if (gamebtn & DIVA_IO_GAMEBTN_SQUARE) { out->p1 |= 1 << 8; } - if (gamebtn & 0x08) { + if (gamebtn & DIVA_IO_GAMEBTN_TRIANGLE) { out->p1 |= 1 << 9; } - if (gamebtn & 0x10) { + if (gamebtn & DIVA_IO_GAMEBTN_START) { out->p1 |= 1 << 15; } - if (opbtn & 0x01) { + if (opbtn & DIVA_IO_OPBTN_TEST) { out->system = 0x80; } else { out->system = 0; } - if (opbtn & 0x02) { + if (opbtn & DIVA_IO_OPBTN_SERVICE) { out->p1 |= 1 << 14; } } diff --git a/divahook/meson.build b/divahook/meson.build index 20c1ff2..e291f3e 100644 --- a/divahook/meson.build +++ b/divahook/meson.build @@ -14,6 +14,7 @@ shared_library( amex_lib, board_lib, divaio_lib, + gfxhook_lib, hooklib_lib, jvs_lib, platform_lib, diff --git a/divaio/divaio.c b/divaio/divaio.c index 760e198..9976cb7 100644 --- a/divaio/divaio.c +++ b/divaio/divaio.c @@ -37,11 +37,11 @@ void diva_io_jvs_poll(uint8_t *opbtn_out, uint8_t *gamebtn_out) opbtn = 0; if (GetAsyncKeyState(diva_io_cfg.vk_test) & 0x8000) { - opbtn |= 1; + opbtn |= DIVA_IO_OPBTN_TEST; } if (GetAsyncKeyState(diva_io_cfg.vk_service) & 0x8000) { - opbtn |= 2; + opbtn |= DIVA_IO_OPBTN_SERVICE; } for (i = 0 ; i < _countof(diva_io_cfg.vk_buttons) ; i++) { diff --git a/divaio/divaio.h b/divaio/divaio.h index bac3627..7dd13b8 100644 --- a/divaio/divaio.h +++ b/divaio/divaio.h @@ -5,6 +5,19 @@ #include #include +enum { + DIVA_IO_OPBTN_TEST = 0x01, + DIVA_IO_OPBTN_SERVICE = 0x02 +}; + +enum { + DIVA_IO_GAMEBTN_CIRCLE = 0x01, + DIVA_IO_GAMEBTN_CROSS = 0x02, + DIVA_IO_GAMEBTN_SQUARE = 0x04, + DIVA_IO_GAMEBTN_TRIANGLE = 0x08, + DIVA_IO_GAMEBTN_START = 0x10, +}; + /* Get the version of the Project Diva IO API that this DLL supports. This function should return a positive 16-bit integer, where the high byte is the major version and the low byte is the minor version (as defined by the diff --git a/fgohook/config.c b/fgohook/config.c index 5442b32..b2bb7f5 100644 --- a/fgohook/config.c +++ b/fgohook/config.c @@ -122,5 +122,6 @@ void fgo_hook_config_load( fgo_deck_config_load(&cfg->deck, filename); ftdi_config_load(&cfg->ftdi, filename); led15093_config_load(&cfg->led15093, filename); + gfx_config_load(&cfg->gfx, filename); fgo_dll_config_load(&cfg->dll, filename); } diff --git a/fgohook/config.h b/fgohook/config.h index ffffc25..ca8895a 100644 --- a/fgohook/config.h +++ b/fgohook/config.h @@ -9,6 +9,8 @@ #include "hooklib/touch.h" #include "hooklib/printer.h" +#include "gfxhook/config.h" + #include "fgohook/deck.h" #include "fgohook/ftdi.h" #include "fgohook/fgo-dll.h" @@ -26,6 +28,7 @@ struct fgo_hook_config { struct deck_config deck; struct ftdi_config ftdi; struct led15093_config led15093; + struct gfx_config gfx; struct fgo_dll_config dll; }; diff --git a/fgohook/dllmain.c b/fgohook/dllmain.c index 1604a8d..9bc3694 100644 --- a/fgohook/dllmain.c +++ b/fgohook/dllmain.c @@ -34,6 +34,8 @@ #include "hooklib/serial.h" #include "hooklib/spike.h" +#include "gfxhook/gfx.h" + #include "fgohook/config.h" #include "fgohook/io4.h" #include "fgohook/fgo-dll.h" @@ -50,9 +52,21 @@ static struct fgo_hook_config fgo_hook_cfg; static DWORD CALLBACK fgo_pre_startup(void) { HRESULT hr; + HMODULE dbghelp; dprintf("--- Begin fgo_pre_startup ---\n"); + /* Pin dbghelp so the path hooks apply to it. */ + + dbghelp = LoadLibraryW(L"dbghelp.dll"); + + if (dbghelp != NULL) { + dprintf("Pinned debug helper library, hMod=%p\n", dbghelp); + } + else { + dprintf("Failed to load debug helper library!\n"); + } + /* Load config */ fgo_hook_config_load(&fgo_hook_cfg, L".\\segatools.ini"); @@ -60,6 +74,7 @@ static DWORD CALLBACK fgo_pre_startup(void) /* Hook Win32 APIs */ dvd_hook_init(&fgo_hook_cfg.dvd, fgo_hook_mod); + gfx_hook_init(&fgo_hook_cfg.gfx); touch_screen_hook_init(&fgo_hook_cfg.touch, fgo_hook_mod); serial_hook_init(); diff --git a/fgohook/meson.build b/fgohook/meson.build index 2e9772f..257048b 100644 --- a/fgohook/meson.build +++ b/fgohook/meson.build @@ -13,6 +13,7 @@ shared_library( link_with : [ aimeio_lib, board_lib, + gfxhook_lib, hooklib_lib, fgoio_lib, platform_lib, diff --git a/gfxhook/gfx.c b/gfxhook/gfx.c index 1af3647..af844a3 100644 --- a/gfxhook/gfx.c +++ b/gfxhook/gfx.c @@ -9,18 +9,53 @@ #include "util/dprintf.h" -typedef BOOL (WINAPI *ShowWindow_t)(HWND hWnd, int nCmdShow); +/* Hook functions */ static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow); +static BOOL WINAPI hook_CreateWindowExA( + DWORD dwExStyle, + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam +); + +/* Link pointers */ + +static BOOL (WINAPI *next_ShowWindow)(HWND hWnd, int nCmdShow); +static BOOL (WINAPI *next_CreateWindowExA)( + DWORD dwExStyle, + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam +); static struct gfx_config gfx_config; -static ShowWindow_t next_ShowWindow; static const struct hook_symbol gfx_hooks[] = { { .name = "ShowWindow", .patch = hook_ShowWindow, .link = (void **) &next_ShowWindow, + }, { + .name = "CreateWindowExA", + .patch = hook_CreateWindowExA, + .link = (void **) &next_CreateWindowExA, }, }; @@ -46,3 +81,45 @@ static BOOL WINAPI hook_ShowWindow(HWND hWnd, int nCmdShow) return next_ShowWindow(hWnd, nCmdShow); } + +static BOOL WINAPI hook_CreateWindowExA( + DWORD dwExStyle, + LPCSTR lpClassName, + LPCSTR lpWindowName, + DWORD dwStyle, + int X, + int Y, + int nWidth, + int nHeight, + HWND hWndParent, + HMENU hMenu, + HINSTANCE hInstance, + LPVOID lpParam +) +{ + dprintf("Gfx: CreateWindowExA hook hit\n"); + + // Set to WS_OVERLAPPEDWINDOW to enable a window with a border and windowed style + if (gfx_config.windowed) { + dwStyle = WS_OVERLAPPEDWINDOW; + + if (!gfx_config.framed) { + dwStyle = WS_POPUP; + } + } + + return next_CreateWindowExA( + dwExStyle, + lpClassName, + lpWindowName, + dwStyle, + X, + Y, + nWidth, + nHeight, + hWndParent, + hMenu, + hInstance, + lpParam + ); +} diff --git a/gfxhook/gl.c b/gfxhook/gl.c new file mode 100644 index 0000000..67812ab --- /dev/null +++ b/gfxhook/gl.c @@ -0,0 +1,77 @@ +#include + +#include +#include + +#include "gfxhook/gfx.h" +#include "gfxhook/gl.h" + +#include "hook/table.h" + +#include "hooklib/dll.h" + +#include "util/dprintf.h" + +/* Hook functions */ + +static void WINAPI hook_glutFullScreen(void); +static void WINAPI hook_glutInitDisplayMode(unsigned int mode); + +/* Link pointers */ + +static void (WINAPI *next_glutFullScreen)(void); +static void (WINAPI *next_glutInitDisplayMode)(unsigned int mode); + +static struct gfx_config gfx_config; + +static const struct hook_symbol glut_hooks[] = { + { + .name = "glutFullScreen", + .patch = hook_glutFullScreen, + .link = (void **) &next_glutFullScreen, + }, { + .name = "glutInitDisplayMode", + .patch = hook_glutInitDisplayMode, + .link = (void **) &next_glutInitDisplayMode, + }, +}; + +void gfx_gl_hook_init(const struct gfx_config *cfg, HINSTANCE self) +{ + assert(cfg != NULL); + + if (!cfg->enable) { + return; + } + + memcpy(&gfx_config, cfg, sizeof(*cfg)); + hook_table_apply(NULL, "glut32.dll", glut_hooks, _countof(glut_hooks)); + + if (self != NULL) { + dll_hook_push(self, L"glut32.dll"); + } +} + +static void WINAPI hook_glutFullScreen(void) +{ + dprintf("Gfx: glutFullScreen hook hit\n"); + + if (gfx_config.windowed) { + return; + } + + return next_glutFullScreen(); +} + +static void WINAPI hook_glutInitDisplayMode(unsigned int mode) +{ + dprintf("Gfx: glutInitDisplayMode hook hit\n"); + + // GLUT adds a frame when going windowed + if (gfx_config.windowed && !gfx_config.framed) { + // GLUT_BORDERLESS + mode |= 0x0800; + } + + return next_glutInitDisplayMode(mode); +} diff --git a/gfxhook/gl.h b/gfxhook/gl.h new file mode 100644 index 0000000..033840d --- /dev/null +++ b/gfxhook/gl.h @@ -0,0 +1,3 @@ +#pragma once + +void gfx_gl_hook_init(const struct gfx_config *cfg, HINSTANCE self); diff --git a/gfxhook/meson.build b/gfxhook/meson.build index b973ddd..1cf8df3 100644 --- a/gfxhook/meson.build +++ b/gfxhook/meson.build @@ -22,6 +22,8 @@ gfxhook_lib = static_library( 'dxgi.h', 'gfx.c', 'gfx.h', + 'gl.c', + 'gl.h', 'util.c', 'util.h', ],