diff --git a/Dependencies/GWCA b/Dependencies/GWCA index 9588909a3..6b5d1010c 160000 --- a/Dependencies/GWCA +++ b/Dependencies/GWCA @@ -1 +1 @@ -Subproject commit 9588909a3f75fe2b165e7c09d1d1690b1131eaef +Subproject commit 6b5d1010cf0bea7e95ffadf6fd6041cf6ba9b868 diff --git a/Dependencies/imgui b/Dependencies/imgui index e916310b2..78b28d545 160000 --- a/Dependencies/imgui +++ b/Dependencies/imgui @@ -1 +1 @@ -Subproject commit e916310b2e1f9cacbb2b9ce192a3dfb359e4b509 +Subproject commit 78b28d545f79c5c5ed3e0ebae4099e44bdc6c5a6 diff --git a/GWToolbox/GWToolbox.vcxproj b/GWToolbox/GWToolbox.vcxproj index f4e8048b1..ebe185863 100644 --- a/GWToolbox/GWToolbox.vcxproj +++ b/GWToolbox/GWToolbox.vcxproj @@ -56,7 +56,7 @@ Level3 Disabled - WIN32_LEAN_AND_MEAN;WIN32;_DEBUG;_WINDOWS;_USRDLL;API_EXPORTS;_USE_MATH_DEFINES;NOMINMAX;_CRT_SECURE_NO_WARNINGS;IMGUI_USE_BGRA_PACKED_COLOR;%(PreprocessorDefinitions) + ENABLE_BORDERLESS;WIN32_LEAN_AND_MEAN;WIN32;_DEBUG;_WINDOWS;_USRDLL;API_EXPORTS;_USE_MATH_DEFINES;NOMINMAX;_CRT_SECURE_NO_WARNINGS;IMGUI_USE_BGRA_PACKED_COLOR;%(PreprocessorDefinitions) true GWCA\Utilities\Export.h false @@ -81,7 +81,7 @@ Full true true - WIN32_LEAN_AND_MEAN;WIN32;NDEBUG;_WINDOWS;_USRDLL;API_EXPORTS;_USE_MATH_DEFINES;NOMINMAX;_CRT_SECURE_NO_WARNINGS;IMGUI_USE_BGRA_PACKED_COLOR;%(PreprocessorDefinitions) + ENABLE_BORDERLESS;WIN32_LEAN_AND_MEAN;WIN32;NDEBUG;_WINDOWS;_USRDLL;API_EXPORTS;_USE_MATH_DEFINES;NOMINMAX;_CRT_SECURE_NO_WARNINGS;IMGUI_USE_BGRA_PACKED_COLOR;%(PreprocessorDefinitions) true Speed diff --git a/GWToolbox/GWToolbox/GWToolbox.cpp b/GWToolbox/GWToolbox/GWToolbox.cpp index c8aaa1b50..81e048ec7 100644 --- a/GWToolbox/GWToolbox/GWToolbox.cpp +++ b/GWToolbox/GWToolbox/GWToolbox.cpp @@ -1,462 +1,503 @@ -#include "GWToolbox.h" - -#include "Defines.h" - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include - -#include "logger.h" -#include "CursorFix.h" - -#include -#include -#include -#include -#include -#include -#ifdef ENABLE_LUA -# include -#endif -#include - -#include - -#include "GuiUtils.h" - -namespace { - HMODULE dllmodule = 0; - - long OldWndProc = 0; - bool tb_initialized = false; - bool tb_destroyed = false; - - bool drawing_world = 0; - int drawing_passes = 0; - int last_drawing_passes = 0; -} - -HMODULE GWToolbox::GetDLLModule() { - return dllmodule; -} - -DWORD __stdcall SafeThreadEntry(LPVOID module) { - dllmodule = (HMODULE)module; - __try { - return ThreadEntry(nullptr); - } __except ( EXCEPT_EXPRESSION_ENTRY ) { - Log::Log("SafeThreadEntry __except body\n"); - return EXIT_SUCCESS; - } -} - -DWORD __stdcall ThreadEntry(LPVOID) { - Log::Log("Initializing API\n"); - - GW::HookBase::Initialize(); - if (!GW::Initialize()){ - MessageBoxA(0, "Initialize Failed at finding all addresses, contact Developers about this.", "GWToolbox++ API Error", 0); - FreeLibraryAndExitThread(dllmodule, EXIT_SUCCESS); - return EXIT_SUCCESS; - } - - Log::Log("Installing Cursor Fix\n"); - - InstallCursorFix(); - - Log::Log("Installing dx hooks\n"); - GW::Render::SetRenderCallback([](IDirect3DDevice9* device) { - GWToolbox::Instance().Draw(device); - }); - GW::Render::SetResetCallback([](IDirect3DDevice9* device) { - ImGui_ImplDX9_InvalidateDeviceObjects(); - }); - - Log::Log("Installed dx hooks\n"); - - Log::InitializeChat(); - - Log::Log("Installed chat hooks\n"); - - GW::HookBase::EnableHooks(); - - Log::Log("Hooks Enabled!\n"); - - while (!tb_destroyed) { // wait until destruction - Sleep(100); - -#ifdef _DEBUG - if (GetAsyncKeyState(VK_END) & 1) { - GWToolbox::Instance().StartSelfDestruct(); - break; - } -#endif - } - - Sleep(100); - Log::Log("Removing Cursor Fix\n"); - UninstallCursorFix(); - Sleep(100); - Log::Log("Closing log/console, bye!\n"); - Log::Terminate(); - Sleep(100); - - GW::HookBase::Deinitialize(); // At this point every hook should be disable, so we only need to free the memory - FreeLibraryAndExitThread(dllmodule, EXIT_SUCCESS); -} - -LRESULT CALLBACK SafeWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { - __try { - return WndProc(hWnd, Message, wParam, lParam); - } __except (EXCEPTION_EXECUTE_HANDLER) { - return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); - } -} - -LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { - static bool right_mouse_down = false; - - if (!tb_initialized || tb_destroyed) { - return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); - } - - if (Message == WM_QUIT || Message == WM_CLOSE) { - GWToolbox::Instance().SaveSettings(); - return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); - } - - if (Message == WM_RBUTTONDOWN) right_mouse_down = true; - if (Message == WM_RBUTTONDBLCLK) right_mouse_down = true; - if (Message == WM_RBUTTONUP) right_mouse_down = false; - - GWToolbox::Instance().right_mouse_down = right_mouse_down; - - // === Send events to ImGui === - ImGuiIO& io = ImGui::GetIO(); - - switch (Message) { - case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - if (!right_mouse_down) io.MouseDown[0] = true; - break; - case WM_LBUTTONUP: - io.MouseDown[0] = false; - break; - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - if (!right_mouse_down) { - io.KeysDown[VK_MBUTTON] = true; - io.MouseDown[2] = true; - } - break; - case WM_MBUTTONUP: - io.KeysDown[VK_MBUTTON] = false; - io.MouseDown[2] = false; - break; - case WM_MOUSEWHEEL: - if (!right_mouse_down) io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; - break; - case WM_MOUSEMOVE: - if (!right_mouse_down) { - io.MousePos.x = (float)GET_X_LPARAM(lParam); - io.MousePos.y = (float)GET_Y_LPARAM(lParam); - } - break; - case WM_XBUTTONDOWN: - if (!right_mouse_down) { - if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) io.KeysDown[VK_XBUTTON1] = true; - if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) io.KeysDown[VK_XBUTTON2] = true; - } - break; - case WM_XBUTTONUP: - if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) io.KeysDown[VK_XBUTTON1] = false; - if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) io.KeysDown[VK_XBUTTON2] = false; - break; - case WM_KEYDOWN: - if (wParam < 256) - io.KeysDown[wParam] = true; - break; - case WM_KEYUP: - if (wParam < 256) - io.KeysDown[wParam] = false; - break; - case WM_CHAR: // You can also use ToAscii()+GetKeyboardState() to retrieve characters. - if (wParam > 0 && wParam < 0x10000) - io.AddInputCharacter((unsigned short)wParam); - break; - default: - break; - } - - // === Send events to toolbox === - GWToolbox& tb = GWToolbox::Instance(); - switch (Message) { - // Send button up mouse events to everything, to avoid being stuck on mouse-down - case WM_LBUTTONUP: - for (ToolboxModule* m : tb.GetModules()) { - m->WndProc(Message, wParam, lParam); - } - break; - - // Other mouse events: - // - If right mouse down, leave it to gw - // - ImGui first (above), if WantCaptureMouse that's it - // - Toolbox module second (e.g.: minimap), if captured, that's it - // - otherwise pass to gw - case WM_LBUTTONDOWN: - case WM_LBUTTONDBLCLK: - case WM_MOUSEMOVE: - case WM_MOUSEWHEEL: - if (!right_mouse_down) { - if (io.WantCaptureMouse) return true; - bool captured = false; - for (ToolboxModule* m : tb.GetModules()) { - if (m->WndProc(Message, wParam, lParam)) captured = true; - } - if (captured) return true; - } - break; - - // keyboard messages - case WM_KEYUP: - case WM_SYSKEYUP: - if (io.WantTextInput) break; // if imgui wants them, send to imgui (above) and to gw - // else fallthrough - case WM_KEYDOWN: - case WM_SYSKEYDOWN: - case WM_CHAR: - case WM_SYSCHAR: - case WM_IME_CHAR: - case WM_XBUTTONDOWN: - case WM_XBUTTONDBLCLK: - case WM_XBUTTONUP: - case WM_MBUTTONDOWN: - case WM_MBUTTONDBLCLK: - case WM_MBUTTONUP: - if (io.WantTextInput) return true; // if imgui wants them, send just to imgui (above) - - // send input to chat commands for camera movement - if (ChatCommands::Instance().WndProc(Message, wParam, lParam)) { - return true; - } - - // send to toolbox modules - for (ToolboxModule* m : tb.GetModules()) { - m->WndProc(Message, wParam, lParam); - } - // note: capturing those events would prevent typing if you have a hotkey assigned to normal letters. - // We may want to not send events to toolbox if the player is typing in-game - // Otherwise, we may want to capture events. - // For that, we may want to only capture *successfull* hotkey activations. - - // block alt-enter if in borderless to avoid graphic glitches (no reason to go fullscreen anyway) - if (GameSettings::Instance().borderlesswindow - && (GetAsyncKeyState(VK_MENU) < 0) - && (GetAsyncKeyState(VK_RETURN) < 0)) { - return true; - } - break; - - case WM_SIZE: - // ImGui doesn't need this, it reads the viewport size directly - break; - - default: - break; - } - - return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); -} - -void GWToolbox::Initialize() { - Log::Log("Creating Toolbox\n"); - Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img")); - Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\bonds")); - Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\icons")); - Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\materials")); - Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\pcons")); - Resources::Instance().EnsureFolderExists(Resources::GetPath(L"location logs")); - Resources::Instance().EnsureFileExists(Resources::GetPath(L"GWToolbox.ini"), - L"https://raw.githubusercontent.com/HasKha/GWToolboxpp/master/resources/GWToolbox.ini", - [](bool success) { - if (success) { - GWToolbox::Instance().OpenSettingsFile(); - GWToolbox::Instance().LoadModuleSettings(); - } - }); - // if the file does not exist we'll load module settings once downloaded, but we need the file open - // in order to read defaults - OpenSettingsFile(); - Resources::Instance().EnsureFileExists(Resources::GetPath(L"Markers.ini"), - L"https://raw.githubusercontent.com/HasKha/GWToolboxpp/master/resources/Markers.ini", - [](bool success) { - Minimap::Instance().custom_renderer.LoadMarkers(); - }); - - Log::Log("Creating Modules\n"); - std::vector core_modules; - core_modules.push_back(&Resources::Instance()); - core_modules.push_back(&Updater::Instance()); -#ifdef ENABLE_LUA - core_modules.push_back(&LUAInterface::Instance()); -#endif - core_modules.push_back(&GameSettings::Instance()); - core_modules.push_back(&ToolboxSettings::Instance()); - core_modules.push_back(&ChatFilter::Instance()); - core_modules.push_back(&ChatCommands::Instance()); - core_modules.push_back(&ToolboxTheme::Instance()); - - for (ToolboxModule* core : core_modules) { - core->Initialize(); - } - LoadModuleSettings(); // This will only read settings of the core modules (specified above) - - ToolboxSettings::Instance().InitializeModules(); // initialize all other modules as specified by the user - - // Only read settings of non-core modules - for (ToolboxModule* module : modules) { - bool is_core = false; - for (ToolboxModule* core : core_modules) { - if (module == core) is_core = true; - } - if (!is_core) module->LoadSettings(inifile); - } - - Updater::Instance().CheckForUpdate(); - - if (GW::Map::GetInstanceType() != GW::Constants::InstanceType::Loading - && GW::Agents::GetAgentArray().valid() - && GW::Agents::GetPlayer() != nullptr) { - - DWORD playerNumber = GW::Agents::GetPlayer()->PlayerNumber; - Log::Info("Hello %ls!", GW::Agents::GetPlayerNameByLoginNumber(playerNumber)); - } -} - -void GWToolbox::OpenSettingsFile() { - Log::Log("Opening ini file\n"); - if (inifile == nullptr) inifile = new CSimpleIni(false, false, false); - inifile->LoadFile(Resources::GetPath(L"GWToolbox.ini").c_str()); -} -void GWToolbox::LoadModuleSettings() { - for (ToolboxModule* module : modules) { - module->LoadSettings(inifile); - } -} - -void GWToolbox::SaveSettings() { - for (ToolboxModule* module : modules) { - module->SaveSettings(inifile); - } - if (inifile) inifile->SaveFile(Resources::GetPath(L"GWToolbox.ini").c_str()); -} - -void GWToolbox::Terminate() { - SaveSettings(); - inifile->Reset(); - delete inifile; - - for (ToolboxModule* module : modules) { - module->Terminate(); - } - - if (GW::Map::GetInstanceType() != GW::Constants::InstanceType::Loading) { - Log::Info("Bye!"); - } -} - -void GWToolbox::Draw(IDirect3DDevice9* device) { - - static HWND gw_window_handle = 0; - static DWORD last_tick_count; - - // === initialization === - if (!tb_initialized && !GWToolbox::Instance().must_self_destruct) { - - Log::Log("installing event handler\n"); - gw_window_handle = GW::MemoryMgr::GetGWWindowHandle(); - OldWndProc = SetWindowLongPtr(gw_window_handle, GWL_WNDPROC, (long)SafeWndProc); - Log::Log("Installed input event handler, oldwndproc = 0x%X\n", OldWndProc); - - ImGui_ImplDX9_Init(GW::MemoryMgr().GetGWWindowHandle(), device); - ImGuiIO& io = ImGui::GetIO(); - io.MouseDrawCursor = false; - static Utf8 imgui_inifile = Resources::GetPathUtf8(L"interface.ini"); - io.IniFilename = imgui_inifile.c_str(); - - Resources::Instance().EnsureFileExists(Resources::GetPath(L"Font.ttf"), - L"https://raw.githubusercontent.com/HasKha/GWToolboxpp/master/resources/Font.ttf", - [](bool success) { - if (success) { - GuiUtils::LoadFonts(); - } else { - Log::Error("Cannot load font!"); - } - }); - - GWToolbox::Instance().Initialize(); - - // Maybe temporary... - GW::HookBase::EnableHooks(); - - last_tick_count = GetTickCount(); - tb_initialized = true; - } - - // === runtime === - if (tb_initialized - && !GWToolbox::Instance().must_self_destruct - && GW::Render::GetViewportWidth() > 0 - && GW::Render::GetViewportHeight() > 0) { - - ImGui_ImplDX9_NewFrame(GW::Render::GetViewportWidth(), GW::Render::GetViewportHeight()); - - // Improve precision with QueryPerformanceCounter - DWORD tick = GetTickCount(); - DWORD delta = tick - last_tick_count; - float delta_f = delta / 1000.f; - - for (ToolboxModule* module : GWToolbox::Instance().modules) { - module->Update(delta_f); - } - last_tick_count = tick; - - Resources::Instance().DxUpdate(device); - - for (ToolboxUIElement* uielement : GWToolbox::Instance().uielements) { - uielement->Draw(device); - } - -#ifdef _DEBUG - // Feel free to uncomment to play with ImGui's features - //ImGui::ShowDemoWindow(); - //ImGui::ShowStyleEditor(); // Warning, this WILL change your theme. Back up theme.ini first! -#endif - - ImGui::Render(); - } - - // === destruction === - if (tb_initialized && GWToolbox::Instance().must_self_destruct) { - GWToolbox::Instance().Terminate(); - - ImGui_ImplDX9_Shutdown(); - - Log::Log("Restoring input hook\n"); - SetWindowLongPtr(gw_window_handle, GWL_WNDPROC, (long)OldWndProc); - Log::Log("Destroying directX hook\n"); - GW::Render::RestoreHooks(); - Log::Log("Destroying API\n"); - GW::Terminate(); - tb_destroyed = true; - } -} +#include "GWToolbox.h" + +#include "Defines.h" + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "logger.h" +#include "CursorFix.h" + +#include +#include +#include +#include +#include +#include +#ifdef ENABLE_LUA +# include +#endif +#include + +#include + +#include "GuiUtils.h" + +namespace { + HMODULE dllmodule = 0; + + long OldWndProc = 0; + bool tb_initialized = false; + bool tb_destroyed = false; + + bool drawing_world = 0; + int drawing_passes = 0; + int last_drawing_passes = 0; +} + +HMODULE GWToolbox::GetDLLModule() { + return dllmodule; +} + +DWORD __stdcall SafeThreadEntry(LPVOID module) { + dllmodule = (HMODULE)module; + __try { + return ThreadEntry(nullptr); + } __except ( EXCEPT_EXPRESSION_ENTRY ) { + Log::Log("SafeThreadEntry __except body\n"); + return EXIT_SUCCESS; + } +} + +DWORD __stdcall ThreadEntry(LPVOID) { + Log::Log("Initializing API\n"); + + GW::HookBase::Initialize(); + if (!GW::Initialize()){ + MessageBoxA(0, "Initialize Failed at finding all addresses, contact Developers about this.", "GWToolbox++ API Error", 0); + FreeLibraryAndExitThread(dllmodule, EXIT_SUCCESS); + return EXIT_SUCCESS; + } + + Log::Log("Installing Cursor Fix\n"); + + InstallCursorFix(); + + Log::Log("Installing dx hooks\n"); + GW::Render::SetRenderCallback([](IDirect3DDevice9* device) { + GWToolbox::Instance().Draw(device); + }); + GW::Render::SetResetCallback([](IDirect3DDevice9* device) { + ImGui_ImplDX9_InvalidateDeviceObjects(); + }); + + Log::Log("Installed dx hooks\n"); + + Log::InitializeChat(); + + Log::Log("Installed chat hooks\n"); + + GW::HookBase::EnableHooks(); + + Log::Log("Hooks Enabled!\n"); + + while (!tb_destroyed) { // wait until destruction + Sleep(100); + +#ifdef _DEBUG + if (GetAsyncKeyState(VK_END) & 1) { + GWToolbox::Instance().StartSelfDestruct(); + break; + } +#endif + } + + Sleep(100); + Log::Log("Removing Cursor Fix\n"); + UninstallCursorFix(); + Sleep(100); + Log::Log("Closing log/console, bye!\n"); + Log::Terminate(); + Sleep(100); + + GW::HookBase::Deinitialize(); // At this point every hook should be disable, so we only need to free the memory + FreeLibraryAndExitThread(dllmodule, EXIT_SUCCESS); +} + +LRESULT CALLBACK SafeWndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { + __try { + return WndProc(hWnd, Message, wParam, lParam); + } __except (EXCEPTION_EXECUTE_HANDLER) { + return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); + } +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { + static bool right_mouse_down = false; + + if (!tb_initialized || tb_destroyed) { + return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); + } + + if (Message == WM_QUIT || Message == WM_CLOSE) { + GWToolbox::Instance().SaveSettings(); + return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); + } + + if (Message == WM_RBUTTONDOWN) right_mouse_down = true; + if (Message == WM_RBUTTONDBLCLK) right_mouse_down = true; + if (Message == WM_RBUTTONUP) right_mouse_down = false; + + GWToolbox::Instance().right_mouse_down = right_mouse_down; + + // === Send events to ImGui === + ImGuiIO& io = ImGui::GetIO(); + + switch (Message) { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + if (!right_mouse_down) io.MouseDown[0] = true; + break; + case WM_LBUTTONUP: + io.MouseDown[0] = false; + break; + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + if (!right_mouse_down) { + io.KeysDown[VK_MBUTTON] = true; + io.MouseDown[2] = true; + } + break; + case WM_MBUTTONUP: + io.KeysDown[VK_MBUTTON] = false; + io.MouseDown[2] = false; + break; + case WM_MOUSEWHEEL: + if (!right_mouse_down) io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; + break; + case WM_MOUSEMOVE: + if (!right_mouse_down) { + io.MousePos.x = (float)GET_X_LPARAM(lParam); + io.MousePos.y = (float)GET_Y_LPARAM(lParam); + } + break; + case WM_XBUTTONDOWN: + if (!right_mouse_down) { + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) io.KeysDown[VK_XBUTTON1] = true; + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) io.KeysDown[VK_XBUTTON2] = true; + } + break; + case WM_XBUTTONUP: + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) io.KeysDown[VK_XBUTTON1] = false; + if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2) io.KeysDown[VK_XBUTTON2] = false; + break; + case WM_KEYDOWN: + if (wParam < 256) + io.KeysDown[wParam] = true; + break; + case WM_KEYUP: + if (wParam < 256) + io.KeysDown[wParam] = false; + break; + case WM_CHAR: // You can also use ToAscii()+GetKeyboardState() to retrieve characters. + if (wParam > 0 && wParam < 0x10000) + io.AddInputCharacter((unsigned short)wParam); + break; + default: + break; + } + + // === Send events to toolbox === + GWToolbox& tb = GWToolbox::Instance(); + switch (Message) { + // Send button up mouse events to everything, to avoid being stuck on mouse-down + case WM_LBUTTONUP: + for (ToolboxModule* m : tb.GetModules()) { + m->WndProc(Message, wParam, lParam); + } + break; + + // Other mouse events: + // - If right mouse down, leave it to gw + // - ImGui first (above), if WantCaptureMouse that's it + // - Toolbox module second (e.g.: minimap), if captured, that's it + // - otherwise pass to gw + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + case WM_MOUSEMOVE: + case WM_MOUSEWHEEL: + if (!right_mouse_down) { + if (io.WantCaptureMouse) return true; + bool captured = false; + for (ToolboxModule* m : tb.GetModules()) { + if (m->WndProc(Message, wParam, lParam)) captured = true; + } + if (captured) return true; + } + break; + + // keyboard messages + case WM_KEYUP: + case WM_SYSKEYUP: + if (io.WantTextInput) break; // if imgui wants them, send to imgui (above) and to gw + // else fallthrough + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_CHAR: + case WM_SYSCHAR: + case WM_IME_CHAR: + case WM_XBUTTONDOWN: + case WM_XBUTTONDBLCLK: + case WM_XBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONDBLCLK: + case WM_MBUTTONUP: + if (io.WantTextInput) return true; // if imgui wants them, send just to imgui (above) + + // send input to chat commands for camera movement + if (ChatCommands::Instance().WndProc(Message, wParam, lParam)) { + return true; + } + + // send to toolbox modules + for (ToolboxModule* m : tb.GetModules()) { + m->WndProc(Message, wParam, lParam); + } + // note: capturing those events would prevent typing if you have a hotkey assigned to normal letters. + // We may want to not send events to toolbox if the player is typing in-game + // Otherwise, we may want to capture events. + // For that, we may want to only capture *successfull* hotkey activations. + + // block alt-enter if in borderless to avoid graphic glitches (no reason to go fullscreen anyway) + if (GameSettings::Instance().borderlesswindow + && (GetAsyncKeyState(VK_MENU) < 0) + && (GetAsyncKeyState(VK_RETURN) < 0)) { + return true; + } + break; + + case WM_SIZE: + // ImGui doesn't need this, it reads the viewport size directly + break; + + default: + break; + } + + return CallWindowProc((WNDPROC)OldWndProc, hWnd, Message, wParam, lParam); +} + +void GWToolbox::Initialize() { + Log::Log("Creating Toolbox\n"); + Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img")); + Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\bonds")); + Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\icons")); + Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\materials")); + Resources::Instance().EnsureFolderExists(Resources::GetPath(L"img\\pcons")); + Resources::Instance().EnsureFolderExists(Resources::GetPath(L"location logs")); + Resources::Instance().EnsureFileExists(Resources::GetPath(L"GWToolbox.ini"), + L"https://raw.githubusercontent.com/HasKha/GWToolboxpp/master/resources/GWToolbox.ini", + [](bool success) { + if (success) { + GWToolbox::Instance().OpenSettingsFile(); + GWToolbox::Instance().LoadModuleSettings(); + } + }); + // if the file does not exist we'll load module settings once downloaded, but we need the file open + // in order to read defaults + OpenSettingsFile(); + Resources::Instance().EnsureFileExists(Resources::GetPath(L"Markers.ini"), + L"https://raw.githubusercontent.com/HasKha/GWToolboxpp/master/resources/Markers.ini", + [](bool success) { + Minimap::Instance().custom_renderer.LoadMarkers(); + }); + + Log::Log("Creating Modules\n"); + std::vector core_modules; + core_modules.push_back(&Resources::Instance()); + core_modules.push_back(&Updater::Instance()); +#ifdef ENABLE_LUA + core_modules.push_back(&LUAInterface::Instance()); +#endif + core_modules.push_back(&GameSettings::Instance()); + core_modules.push_back(&ToolboxSettings::Instance()); + core_modules.push_back(&ChatFilter::Instance()); + core_modules.push_back(&ChatCommands::Instance()); + core_modules.push_back(&ToolboxTheme::Instance()); + + for (ToolboxModule* core : core_modules) { + core->Initialize(); + } + LoadModuleSettings(); // This will only read settings of the core modules (specified above) + + // Loading all plugin modules. + + std::vector plugin_modules; + + WIN32_FIND_DATAW find_data; + HANDLE find_handle = FindFirstFileW(Resources::GetPath(L"plugins\\*.dll").c_str(), &find_data); + if (find_handle != INVALID_HANDLE_VALUE) { + do { + HMODULE dllmod = LoadLibraryW(find_data.cFileName); + if (!dllmod) { + Log::Warning("DLL plugin \"%S\" could not be loaded. LoadLibraryW Err %d", find_data.cFileName, GetLastError()); + continue; + } + typedef ToolboxModule* InstanceFn_t(); + InstanceFn_t* inst = (InstanceFn_t*)GetProcAddress(dllmod, "GWTB_Instance"); + if (!inst) { + Log::Warning("DLL plugin \"%S\" could not be loaded. TB_Instance entry point not defined.", find_data.cFileName); + continue; + } + ToolboxModule* mod = inst(); + if (!mod) { + Log::Warning("DLL plugin \"%S\" could not be loaded. Module does not exist.", find_data.cFileName); + continue; + } + dllhandles.push_back(dllmod); + plugin_modules.push_back(mod); + Log::LogW(L"DLL plugin \"%s\" loaded successfully.", find_data.cFileName); + } while (FindNextFileW(find_handle, &find_data)); + } + + for (ToolboxModule* plugin : plugin_modules) { + plugin->Initialize(); + } + + ToolboxSettings::Instance().InitializeModules(); // initialize all other modules as specified by the user + + // Only read settings of non-core modules + for (ToolboxModule* module : modules) { + bool is_core = false; + for (ToolboxModule* core : core_modules) { + if (module == core) is_core = true; + } + if (!is_core) module->LoadSettings(inifile); + } + + Updater::Instance().CheckForUpdate(); + + if (GW::Map::GetInstanceType() != GW::Constants::InstanceType::Loading + && GW::Agents::GetAgentArray().valid() + && GW::Agents::GetPlayer() != nullptr) { + + DWORD playerNumber = GW::Agents::GetPlayer()->PlayerNumber; + Log::Info("Hello %ls!", GW::Agents::GetPlayerNameByLoginNumber(playerNumber)); + } +} + +void GWToolbox::OpenSettingsFile() { + Log::Log("Opening ini file\n"); + if (inifile == nullptr) inifile = new CSimpleIni(false, false, false); + inifile->LoadFile(Resources::GetPath(L"GWToolbox.ini").c_str()); +} +void GWToolbox::LoadModuleSettings() { + for (ToolboxModule* module : modules) { + module->LoadSettings(inifile); + } +} + +void GWToolbox::SaveSettings() { + for (ToolboxModule* module : modules) { + module->SaveSettings(inifile); + } + if (inifile) inifile->SaveFile(Resources::GetPath(L"GWToolbox.ini").c_str()); +} + +void GWToolbox::Terminate() { + SaveSettings(); + inifile->Reset(); + delete inifile; + + for (ToolboxModule* module : modules) { + module->Terminate(); + } + + if (GW::Map::GetInstanceType() != GW::Constants::InstanceType::Loading) { + Log::Info("Bye!"); + } +} + +void GWToolbox::Draw(IDirect3DDevice9* device) { + + static HWND gw_window_handle = 0; + static DWORD last_tick_count; + + // === initialization === + if (!tb_initialized && !GWToolbox::Instance().must_self_destruct) { + + Log::Log("installing event handler\n"); + gw_window_handle = GW::MemoryMgr::GetGWWindowHandle(); + OldWndProc = SetWindowLongPtr(gw_window_handle, GWL_WNDPROC, (long)SafeWndProc); + Log::Log("Installed input event handler, oldwndproc = 0x%X\n", OldWndProc); + + ImGui::CreateContext(); + ImGui_ImplDX9_Init(GW::MemoryMgr().GetGWWindowHandle(), device); + ImGuiIO& io = ImGui::GetIO(); + io.MouseDrawCursor = false; + static Utf8 imgui_inifile = Resources::GetPathUtf8(L"interface.ini"); + io.IniFilename = imgui_inifile.c_str(); + + Resources::Instance().EnsureFileExists(Resources::GetPath(L"Font.ttf"), + L"https://raw.githubusercontent.com/HasKha/GWToolboxpp/master/resources/Font.ttf", + [](bool success) { + if (success) { + GuiUtils::LoadFonts(); + } else { + Log::Error("Cannot load font!"); + } + }); + + GWToolbox::Instance().Initialize(); + + // Maybe temporary... + GW::HookBase::EnableHooks(); + + last_tick_count = GetTickCount(); + tb_initialized = true; + } + + // === runtime === + if (tb_initialized + && !GWToolbox::Instance().must_self_destruct + && GW::Render::GetViewportWidth() > 0 + && GW::Render::GetViewportHeight() > 0) { + + if (!GW::UI::GetIsUIDrawn()) + return; + + ImGui_ImplDX9_NewFrame(); + + // Improve precision with QueryPerformanceCounter + DWORD tick = GetTickCount(); + DWORD delta = tick - last_tick_count; + float delta_f = delta / 1000.f; + + for (ToolboxModule* module : GWToolbox::Instance().modules) { + module->Update(delta_f); + } + last_tick_count = tick; + + Resources::Instance().DxUpdate(device); + + for (ToolboxUIElement* uielement : GWToolbox::Instance().uielements) { + uielement->Draw(device); + } + +#ifdef _DEBUG + // Feel free to uncomment to play with ImGui's features + //ImGui::ShowDemoWindow(); + //ImGui::ShowStyleEditor(); // Warning, this WILL change your theme. Back up theme.ini first! +#endif + + ImGui::Render(); + ImDrawData* draw_data = ImGui::GetDrawData(); + ImGui_ImplDX9_RenderDrawData(draw_data); + } + + // === destruction === + if (tb_initialized && GWToolbox::Instance().must_self_destruct) { + GWToolbox::Instance().Terminate(); + + ImGui_ImplDX9_Shutdown(); + ImGui::DestroyContext(); + + Log::Log("Restoring input hook\n"); + SetWindowLongPtr(gw_window_handle, GWL_WNDPROC, (long)OldWndProc); + Log::Log("Destroying directX hook\n"); + GW::Render::RestoreHooks(); + Log::Log("Destroying API\n"); + GW::Terminate(); + tb_destroyed = true; + } +} diff --git a/GWToolbox/GWToolbox/GWToolbox.h b/GWToolbox/GWToolbox/GWToolbox.h index 6fb1d0a49..7556aa218 100644 --- a/GWToolbox/GWToolbox/GWToolbox.h +++ b/GWToolbox/GWToolbox/GWToolbox.h @@ -46,6 +46,7 @@ class GWToolbox { private: std::vector modules; std::vector uielements; + std::vector dllhandles; CSimpleIni* inifile = nullptr; }; diff --git a/GWToolbox/GWToolbox/Modules/ChatFilter.cpp b/GWToolbox/GWToolbox/Modules/ChatFilter.cpp index 7070ce4a7..9750b21c6 100644 --- a/GWToolbox/GWToolbox/Modules/ChatFilter.cpp +++ b/GWToolbox/GWToolbox/Modules/ChatFilter.cpp @@ -351,6 +351,8 @@ bool ChatFilter::ShouldIgnore(const wchar_t *message) { case 0x152B: // you win 12 festival tickets case 0x152C: // You win 3 festival tickets return ninerings; + case 0x39CD: // you have a special item available: + return ninerings; case 0x7B91: // x minutes of favor of the gods remaining. Note: full message is 0x8101 0x7B91 0xC686 0xE490 0x6922 0x101 0x100+value case 0x7B92: // x more achievements must be performed to earn the favor of the gods. // 0x8101 0x7B92 0x8B0A 0x8DB5 0x5135 0x101 0x100+value return favor; diff --git a/GWToolbox/GWToolbox/Modules/GameSettings.cpp b/GWToolbox/GWToolbox/Modules/GameSettings.cpp index ddfeaae7c..482234f32 100644 --- a/GWToolbox/GWToolbox/Modules/GameSettings.cpp +++ b/GWToolbox/GWToolbox/Modules/GameSettings.cpp @@ -357,9 +357,9 @@ void GameSettings::Initialize() { } { - uintptr_t found = GW::Scanner::Find("\x8B\x9E\x7C\x0C\x00\x00\x2B\xC3\x8B", "xxxxxxxxx", 0); - patches.push_back(new GW::MemoryPatcher(found - 0xB, "\xEB", 1)); - patches.push_back(new GW::MemoryPatcher(found + 0x12, "\xEB", 1)); + uintptr_t found = GW::Scanner::Find("\x2B\x8E\x78\x0C\x00\x00\x3B\xC1\x7F", "xxxxxxxxx", 0); + patches.push_back(new GW::MemoryPatcher(found + 0xF, "\xEB", 1)); + patches.push_back(new GW::MemoryPatcher(found + 0x1E, "\xEB", 1)); } { @@ -371,16 +371,16 @@ void GameSettings::Initialize() { } { - uintptr_t found = GW::Scanner::Find("\x56\x57\x8B\xF9\x8B\x87\xF4\x0C\x00\x00\x85\xC0\x75\x14", "xxxxxxxxxxxxxx", 0); + uintptr_t found = GW::Scanner::Find("\x55\x8B\xEC\x51\x56\x57\x8B\xF9\x8B\x87\xF8\x0C\x00\x00", "xxxxxxxxxxxxxx", 0); void *patch = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"; - patches.push_back(new GW::MemoryPatcher(found + 0x86, patch, 10)); - patches.push_back(new GW::MemoryPatcher(found + 0x100, patch, 10)); - patches.push_back(new GW::MemoryPatcher(found + 0x13F, patch, 10)); + patches.push_back(new GW::MemoryPatcher(found + 0x8A, patch, 10)); + patches.push_back(new GW::MemoryPatcher(found + 0x10A, patch, 10)); + patches.push_back(new GW::MemoryPatcher(found + 0x149, patch, 10)); } #endif // ENABLE_BORDERLESS { // Patch that allow storage page (and Anniversary page) to work... (ask Ziox for more info) - uintptr_t found = GW::Scanner::Find("\xEB\x20\x33\xC0\xBE\x06", "xxxxxx", -4); + uintptr_t found = GW::Scanner::Find("\xEB\x00\x33\xC0\xBE\x06", "x?xxxx", -4); printf("[SCAN] StoragePatch = %p\n", (void *)found); // Xunlai Chest has a behavior where if you @@ -447,7 +447,7 @@ void GameSettings::LoadSettings(CSimpleIni* ini) { GW::Chat::ShowTimestamps = ini->GetBoolValue(Name(), "show_timestamps", false); GW::Chat::TimestampsColor = Colors::Load(ini, Name(), "timestamps_color", Colors::White()); - GW::Chat::KeepChatHistory = ini->GetBoolValue(Name(), "keep_chat_history", true); + // GW::Chat::KeepChatHistory = ini->GetBoolValue(Name(), "keep_chat_history", true); @Deprecated openlinks = ini->GetBoolValue(Name(), VAR_NAME(openlinks), true); auto_url = ini->GetBoolValue(Name(), VAR_NAME(auto_url), true); @@ -486,7 +486,7 @@ void GameSettings::SaveSettings(CSimpleIni* ini) { ini->SetBoolValue(Name(), "show_timestamps", GW::Chat::ShowTimestamps); Colors::Save(ini, Name(), "timestamps_color", GW::Chat::TimestampsColor); - ini->SetBoolValue(Name(), "keep_chat_history", GW::Chat::KeepChatHistory); + // ini->SetBoolValue(Name(), "keep_chat_history", GW::Chat::KeepChatHistory); @Deprecated ini->SetBoolValue(Name(), VAR_NAME(openlinks), openlinks); ini->SetBoolValue(Name(), VAR_NAME(auto_url), auto_url); @@ -518,8 +518,8 @@ void GameSettings::DrawSettingInternal() { } ImGui::ShowHelp("Show timestamps in message history."); - ImGui::Checkbox("Keep chat history.", &GW::Chat::KeepChatHistory); - ImGui::ShowHelp("Messages in the chat do not disappear on character change."); + // ImGui::Checkbox("Keep chat history.", &GW::Chat::KeepChatHistory); @Deprecated + // ImGui::ShowHelp("Messages in the chat do not disappear on character change."); if (ImGui::Checkbox("Open web links from templates", &openlinks)) { GW::Chat::SetOpenLinks(openlinks); diff --git a/GWToolbox/GWToolbox/Modules/ToolboxSettings.cpp b/GWToolbox/GWToolbox/Modules/ToolboxSettings.cpp index c22c01ab7..9566a3155 100644 --- a/GWToolbox/GWToolbox/Modules/ToolboxSettings.cpp +++ b/GWToolbox/GWToolbox/Modules/ToolboxSettings.cpp @@ -129,10 +129,8 @@ void ToolboxSettings::DrawSettingInternal() { } void ToolboxSettings::DrawFreezeSetting() { - if (ImGui::Checkbox("Unlock Move All", &move_all)) { - ImGui::GetStyle().WindowBorderSize = (move_all ? 1.0f : 0.0f); - } - ImGui::ShowHelp("Will allow movement and resize of all widgets and windows"); + ImGui::Checkbox("Unlock Move All", &move_all); + ImGui::ShowHelp("Will allow movement and resize of all widgets and windows"); } void ToolboxSettings::LoadSettings(CSimpleIni* ini) { @@ -184,6 +182,8 @@ void ToolboxSettings::SaveSettings(CSimpleIni* ini) { } void ToolboxSettings::Update(float delta) { + ImGui::GetStyle().WindowBorderSize = (move_all ? 1.0f : 0.0f); + // save location data if (save_location_data && TIMER_DIFF(location_timer) > 1000) { location_timer = TIMER_INIT(); diff --git a/GWToolbox/GWToolbox/Modules/ToolboxTheme.cpp b/GWToolbox/GWToolbox/Modules/ToolboxTheme.cpp index dd5af7e80..f6714b0f0 100644 --- a/GWToolbox/GWToolbox/Modules/ToolboxTheme.cpp +++ b/GWToolbox/GWToolbox/Modules/ToolboxTheme.cpp @@ -32,12 +32,9 @@ ImGuiStyle ToolboxTheme::DefaultTheme() { style.Colors[ImGuiCol_Button] = ImColor(0x99344870); style.Colors[ImGuiCol_ButtonHovered] = ImColor(0xFF344870); style.Colors[ImGuiCol_ButtonActive] = ImColor(0xFF283C68); - style.Colors[ImGuiCol_CloseButton] = ImColor(0x80808080); style.Colors[ImGuiCol_Header] = ImColor(0x73E62800); style.Colors[ImGuiCol_HeaderHovered] = ImColor(0xCCF03200); style.Colors[ImGuiCol_HeaderActive] = ImColor(0xCCFA3C00); - style.Colors[ImGuiCol_CloseButtonHovered] = ImColor(0x99BDBDBD); - style.Colors[ImGuiCol_CloseButtonActive] = ImColor(0xFFBDBDBD); return style; } diff --git a/GWToolbox/GWToolbox/Windows/HeroBuildsWindow.cpp b/GWToolbox/GWToolbox/Windows/HeroBuildsWindow.cpp index 583132243..3b24a62c4 100644 --- a/GWToolbox/GWToolbox/Windows/HeroBuildsWindow.cpp +++ b/GWToolbox/GWToolbox/Windows/HeroBuildsWindow.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include "GuiUtils.h" @@ -73,6 +74,8 @@ namespace { "Mercenary Hero 4", "Mercenary Hero 5", "Mercenary Hero 6", "Mercenary Hero 7", "Mercenary Hero 8", "Miku", "Zei Ri" }; + + char MercHeroNames[8][20] = { 0 }; } unsigned int HeroBuildsWindow::TeamHeroBuild::cur_ui_id = 0; @@ -163,7 +166,23 @@ void HeroBuildsWindow::Draw(IDirect3DDevice9* pDevice) { [](void* data, int idx, const char** out_text) -> bool { if (idx < 0) return false; if (idx >= hero_count) return false; - *out_text = HeroName[HeroIndexToID[idx]]; + auto id = HeroIndexToID[idx]; + if (id < HeroID::Merc1 || id > HeroID::Merc8) { + *out_text = HeroName[HeroIndexToID[idx]]; + return true; + } + bool match = false; + auto ctx = GW::GameContext::instance(); + auto& hero_array = ctx->world->hero_info; + for (auto& hero : hero_array) { + if (hero.HeroID == id) { + match = true; + wcstombs(MercHeroNames[id - HeroID::Merc1], hero.name, 20); + *out_text = MercHeroNames[id - HeroID::Merc1]; + } + } + if(!match) + *out_text = HeroName[id]; return true; }, nullptr, hero_count)) { builds_changed = true; diff --git a/GWToolbox/GWToolbox/Windows/TravelWindow.cpp b/GWToolbox/GWToolbox/Windows/TravelWindow.cpp index 12ee09e27..df81a8055 100644 --- a/GWToolbox/GWToolbox/Windows/TravelWindow.cpp +++ b/GWToolbox/GWToolbox/Windows/TravelWindow.cpp @@ -15,7 +15,7 @@ namespace { bool outpost_name_array_getter(void* data, int idx, const char** out_text); - bool ImInPresearing() { return GW::Map::GetCurrentMapInfo().Region == GW::Region::Presearing; } + bool ImInPresearing() { return GW::Map::GetCurrentMapInfo().Region == GW::Region_Presearing; } } void TravelWindow::Initialize() { diff --git a/GWToolbox/GWToolbox/imgui_impl_dx9.cpp b/GWToolbox/GWToolbox/imgui_impl_dx9.cpp index 34209b9ce..dea5c3fc8 100644 --- a/GWToolbox/GWToolbox/imgui_impl_dx9.cpp +++ b/GWToolbox/GWToolbox/imgui_impl_dx9.cpp @@ -1,12 +1,24 @@ // ImGui Win32 + DirectX9 binding -// In this binding, ImTextureID is used to store a 'LPDIRECT3DTEXTURE9' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + +// Implemented features: +// [X] User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). // If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp. // https://github.com/ocornut/imgui -#include +// CHANGELOG +// (minor and older changes stripped away, please see git history for details) +// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud. +// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag. +// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling). +// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself. +// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. +// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavEnableSetMousePos is set). +// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. + +#include "imgui.h" #include "imgui_impl_dx9.h" // DirectX @@ -14,44 +26,42 @@ #define DIRECTINPUT_VERSION 0x0800 #include -// Data +// Win32 data static HWND g_hWnd = 0; static INT64 g_Time = 0; static INT64 g_TicksPerSecond = 0; +static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT; + +// DirectX data static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL; static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL; static LPDIRECT3DTEXTURE9 g_FontTexture = NULL; static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000; -struct CUSTOMVERTEX -{ +struct CUSTOMVERTEX { float pos[3]; D3DCOLOR col; float uv[2]; }; #define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1) -// This is the main rendering function that you have to implement and provide to ImGui (via setting up 'RenderDrawListsFn' in the ImGuiIO structure) -// If text or lines are blurry when integrating ImGui in your engine: -// - in your Render function, try translating your projection matrix by (0.5f,0.5f) or (0.375f,0.375f) -void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) -{ +// Render function. +// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop) +void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data) { // Avoid rendering when minimized ImGuiIO& io = ImGui::GetIO(); if (io.DisplaySize.x <= 0.0f || io.DisplaySize.y <= 0.0f) return; // Create and grow buffers if needed - if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) - { + if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) { if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } g_VertexBufferSize = draw_data->TotalVtxCount + 5000; if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(CUSTOMVERTEX), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL) < 0) return; } - if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) - { + if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) { if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } g_IndexBufferSize = draw_data->TotalIdxCount + 10000; if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx), D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32, D3DPOOL_DEFAULT, &g_pIB, NULL) < 0) @@ -63,25 +73,31 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0) return; - // Copy and convert all vertices into a single contiguous buffer + // Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to) + D3DMATRIX last_world, last_view, last_projection; + g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world); + g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view); + g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection); + + // Copy and convert all vertices into a single contiguous buffer, convert colors to DX9 default format. + // FIXME-OPT: This is a waste of resource, the ideal is to use imconfig.h and + // 1) to avoid repacking colors: #define IMGUI_USE_BGRA_PACKED_COLOR + // 2) to avoid repacking vertices: #define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; } CUSTOMVERTEX* vtx_dst; ImDrawIdx* idx_dst; if (g_pVB->Lock(0, (UINT)(draw_data->TotalVtxCount * sizeof(CUSTOMVERTEX)), (void**)&vtx_dst, D3DLOCK_DISCARD) < 0) return; if (g_pIB->Lock(0, (UINT)(draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void**)&idx_dst, D3DLOCK_DISCARD) < 0) return; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { + for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; const ImDrawVert* vtx_src = cmd_list->VtxBuffer.Data; - for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) - { + for (int i = 0; i < cmd_list->VtxBuffer.Size; i++) { vtx_dst->pos[0] = vtx_src->pos.x; vtx_dst->pos[1] = vtx_src->pos.y; vtx_dst->pos[2] = 0.0f; - //vtx_dst->col = (vtx_src->col & 0xFF00FF00) | ((vtx_src->col & 0xFF0000)>>16) | ((vtx_src->col & 0xFF) << 16); // RGBA --> ARGB for DirectX9 - vtx_dst->col = vtx_src->col; - vtx_dst->uv[0] = vtx_src->uv.x; + vtx_dst->col = vtx_src->col; + vtx_dst->uv[0] = vtx_src->uv.x; vtx_dst->uv[1] = vtx_src->uv.y; vtx_dst++; vtx_src++; @@ -104,7 +120,7 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) vp.MaxZ = 1.0f; g_pd3dDevice->SetViewport(&vp); - // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing + // Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient) g_pd3dDevice->SetPixelShader(NULL); g_pd3dDevice->SetVertexShader(NULL); g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); @@ -116,6 +132,7 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true); + g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); @@ -128,14 +145,14 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) // Setup orthographic projection matrix // Being agnostic of whether or can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH() { - const float L = 0.5f, R = io.DisplaySize.x+0.5f, T = 0.5f, B = io.DisplaySize.y+0.5f; + const float L = 0.5f, R = io.DisplaySize.x + 0.5f, T = 0.5f, B = io.DisplaySize.y + 0.5f; D3DMATRIX mat_identity = { { 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f } }; D3DMATRIX mat_projection = { - 2.0f/(R-L), 0.0f, 0.0f, 0.0f, - 0.0f, 2.0f/(T-B), 0.0f, 0.0f, + 2.0f / (R - L), 0.0f, 0.0f, 0.0f, + 0.0f, 2.0f / (T - B), 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, - (L+R)/(L-R), (T+B)/(B-T), 0.5f, 1.0f, + (L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f, }; g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity); g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity); @@ -145,58 +162,87 @@ void ImGui_ImplDX9_RenderDrawLists(ImDrawData* draw_data) // Render command lists int vtx_offset = 0; int idx_offset = 0; - for (int n = 0; n < draw_data->CmdListsCount; n++) - { + for (int n = 0; n < draw_data->CmdListsCount; n++) { const ImDrawList* cmd_list = draw_data->CmdLists[n]; - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) - { + for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) { const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i]; - if (pcmd->UserCallback) - { + if (pcmd->UserCallback) { pcmd->UserCallback(cmd_list, pcmd); - } - else - { + } else { const RECT r = { (LONG)pcmd->ClipRect.x, (LONG)pcmd->ClipRect.y, (LONG)pcmd->ClipRect.z, (LONG)pcmd->ClipRect.w }; g_pd3dDevice->SetTexture(0, (LPDIRECT3DTEXTURE9)pcmd->TextureId); g_pd3dDevice->SetScissorRect(&r); - g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, idx_offset, pcmd->ElemCount/3); + g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vtx_offset, 0, (UINT)cmd_list->VtxBuffer.Size, idx_offset, pcmd->ElemCount / 3); } idx_offset += pcmd->ElemCount; } vtx_offset += cmd_list->VtxBuffer.Size; } + // Restore the DX9 transform + g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world); + g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view); + g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection); + // Restore the DX9 state d3d9_state_block->Apply(); d3d9_state_block->Release(); } -static bool IsAnyMouseButtonDown() -{ +static bool ImGui_ImplWin32_UpdateMouseCursor() { ImGuiIO& io = ImGui::GetIO(); - for (int n = 0; n < ARRAYSIZE(io.MouseDown); n++) - if (io.MouseDown[n]) - return true; - return false; + if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) + return false; + + ImGuiMouseCursor imgui_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (imgui_cursor == ImGuiMouseCursor_None) { + // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor + ::SetCursor(NULL); + } else { + // Hardware cursor type + LPTSTR win32_cursor = IDC_ARROW; + switch (imgui_cursor) { + case ImGuiMouseCursor_Arrow: win32_cursor = IDC_ARROW; break; + case ImGuiMouseCursor_TextInput: win32_cursor = IDC_IBEAM; break; + case ImGuiMouseCursor_ResizeAll: win32_cursor = IDC_SIZEALL; break; + case ImGuiMouseCursor_ResizeEW: win32_cursor = IDC_SIZEWE; break; + case ImGuiMouseCursor_ResizeNS: win32_cursor = IDC_SIZENS; break; + case ImGuiMouseCursor_ResizeNESW: win32_cursor = IDC_SIZENESW; break; + case ImGuiMouseCursor_ResizeNWSE: win32_cursor = IDC_SIZENWSE; break; + } + ::SetCursor(::LoadCursor(NULL, win32_cursor)); + } + return true; } -// We use the Win32 capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinations when dragging mouse outside of our window bounds. -IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ +// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions. +#ifndef WM_MOUSEHWHEEL +#define WM_MOUSEHWHEEL 0x020E +#endif + +// Process Win32 mouse/keyboard inputs. +// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. +// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application. +// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application. +// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. +// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinations when dragging mouse outside of our window bounds. +// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag. +IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + if (ImGui::GetCurrentContext() == NULL) + return 0; + ImGuiIO& io = ImGui::GetIO(); - switch (msg) - { - case WM_LBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_MBUTTONDOWN: + switch (msg) { + case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK: + case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK: + case WM_MBUTTONDOWN: case WM_MBUTTONDBLCLK: { int button = 0; - if (msg == WM_LBUTTONDOWN) button = 0; - if (msg == WM_RBUTTONDOWN) button = 1; - if (msg == WM_MBUTTONDOWN) button = 2; - if (!IsAnyMouseButtonDown() && GetCapture() == NULL) - SetCapture(hwnd); + if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONDBLCLK) button = 0; + if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) button = 1; + if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) button = 2; + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL) + ::SetCapture(hwnd); io.MouseDown[button] = true; return 0; } @@ -209,13 +255,16 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa if (msg == WM_RBUTTONUP) button = 1; if (msg == WM_MBUTTONUP) button = 2; io.MouseDown[button] = false; - if (!IsAnyMouseButtonDown() && GetCapture() == hwnd) - ReleaseCapture(); + if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd) + ::ReleaseCapture(); return 0; } case WM_MOUSEWHEEL: io.MouseWheel += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; return 0; + case WM_MOUSEHWHEEL: + io.MouseWheelH += GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? +1.0f : -1.0f; + return 0; case WM_MOUSEMOVE: io.MousePos.x = (signed short)(lParam); io.MousePos.y = (signed short)(lParam >> 16); @@ -235,12 +284,15 @@ IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wPa if (wParam > 0 && wParam < 0x10000) io.AddInputCharacter((unsigned short)wParam); return 0; + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT && ImGui_ImplWin32_UpdateMouseCursor()) + return 1; + return 0; } return 0; } -bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) -{ +bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) { g_hWnd = (HWND)hwnd; g_pd3dDevice = device; @@ -249,8 +301,13 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) if (!QueryPerformanceCounter((LARGE_INTEGER *)&g_Time)) return false; + // Setup back-end capabilities flags ImGuiIO& io = ImGui::GetIO(); - io.KeyMap[ImGuiKey_Tab] = VK_TAB; // Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array that we will update during the application lifetime. + io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) + io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime. + io.KeyMap[ImGuiKey_Tab] = VK_TAB; io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT; io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT; io.KeyMap[ImGuiKey_UpArrow] = VK_UP; @@ -259,8 +316,10 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) io.KeyMap[ImGuiKey_PageDown] = VK_NEXT; io.KeyMap[ImGuiKey_Home] = VK_HOME; io.KeyMap[ImGuiKey_End] = VK_END; + io.KeyMap[ImGuiKey_Insert] = VK_INSERT; io.KeyMap[ImGuiKey_Delete] = VK_DELETE; io.KeyMap[ImGuiKey_Backspace] = VK_BACK; + io.KeyMap[ImGuiKey_Space] = VK_SPACE; io.KeyMap[ImGuiKey_Enter] = VK_RETURN; io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE; io.KeyMap[ImGuiKey_A] = 'A'; @@ -270,22 +329,18 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) io.KeyMap[ImGuiKey_Y] = 'Y'; io.KeyMap[ImGuiKey_Z] = 'Z'; - io.RenderDrawListsFn = ImGui_ImplDX9_RenderDrawLists; // Alternatively you can set this to NULL and call ImGui::GetDrawData() after ImGui::Render() to get the same ImDrawData pointer. io.ImeWindowHandle = g_hWnd; return true; } -void ImGui_ImplDX9_Shutdown() -{ +void ImGui_ImplDX9_Shutdown() { ImGui_ImplDX9_InvalidateDeviceObjects(); - ImGui::Shutdown(); g_pd3dDevice = NULL; g_hWnd = 0; } -static bool ImGui_ImplDX9_CreateFontsTexture() -{ +static bool ImGui_ImplDX9_CreateFontsTexture() { // Build texture atlas ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels; @@ -309,8 +364,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() return true; } -bool ImGui_ImplDX9_CreateDeviceObjects() -{ +bool ImGui_ImplDX9_CreateDeviceObjects() { if (!g_pd3dDevice) return false; if (!ImGui_ImplDX9_CreateFontsTexture()) @@ -318,17 +372,14 @@ bool ImGui_ImplDX9_CreateDeviceObjects() return true; } -void ImGui_ImplDX9_InvalidateDeviceObjects() -{ +void ImGui_ImplDX9_InvalidateDeviceObjects() { if (!g_pd3dDevice) return; - if (g_pVB) - { + if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } - if (g_pIB) - { + if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } @@ -342,8 +393,7 @@ void ImGui_ImplDX9_InvalidateDeviceObjects() io.Fonts->TexID = NULL; } -void ImGui_ImplDX9_NewFrame(int client_width, int client_height) -{ +void ImGui_ImplDX9_NewFrame() { if (!g_FontTexture) ImGui_ImplDX9_CreateDeviceObjects(); @@ -352,7 +402,7 @@ void ImGui_ImplDX9_NewFrame(int client_width, int client_height) // Setup display size (every frame to accommodate for window resizing) RECT rect; GetClientRect(g_hWnd, &rect); - io.DisplaySize = ImVec2(client_width, client_height); // ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); + io.DisplaySize = ImVec2((float)(rect.right - rect.left), (float)(rect.bottom - rect.top)); // Setup time step INT64 current_time; @@ -370,18 +420,20 @@ void ImGui_ImplDX9_NewFrame(int client_width, int client_height) // io.MouseDown : filled by WM_*BUTTON* events // io.MouseWheel : filled by WM_MOUSEWHEEL events - // Set OS mouse position if requested last frame by io.WantMoveMouse flag (used when io.NavMovesTrue is enabled by user and using directional navigation) - if (io.WantMoveMouse) - { + // Set OS mouse position if requested (only used when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user) + if (io.WantSetMousePos) { POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y }; ClientToScreen(g_hWnd, &pos); SetCursorPos(pos.x, pos.y); } - // Hide OS mouse cursor if ImGui is drawing it - if (io.MouseDrawCursor) - SetCursor(NULL); + // Update OS mouse cursor with the cursor requested by imgui + ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor(); + if (g_LastMouseCursor != mouse_cursor) { + g_LastMouseCursor = mouse_cursor; + ImGui_ImplWin32_UpdateMouseCursor(); + } - // Start the frame + // Start the frame. This call will update the io.WantCaptureMouse, io.WantCaptureKeyboard flag that you can use to dispatch inputs (or not) to your application. ImGui::NewFrame(); } diff --git a/GWToolbox/GWToolbox/imgui_impl_dx9.h b/GWToolbox/GWToolbox/imgui_impl_dx9.h index 08c2b2c72..e0ea2deae 100644 --- a/GWToolbox/GWToolbox/imgui_impl_dx9.h +++ b/GWToolbox/GWToolbox/imgui_impl_dx9.h @@ -1,5 +1,7 @@ // ImGui Win32 + DirectX9 binding -// In this binding, ImTextureID is used to store a 'LPDIRECT3DTEXTURE9' texture identifier. Read the FAQ about ImTextureID in imgui.cpp. + +// Implemented features: +// [X] User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), ImGui::Render() and ImGui_ImplXXXX_Shutdown(). @@ -10,7 +12,8 @@ struct IDirect3DDevice9; IMGUI_API bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device); IMGUI_API void ImGui_ImplDX9_Shutdown(); -IMGUI_API void ImGui_ImplDX9_NewFrame(int client_width, int client_height); +IMGUI_API void ImGui_ImplDX9_NewFrame(); +IMGUI_API void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data); // Use if you want to reset your rendering device without losing ImGui state. IMGUI_API void ImGui_ImplDX9_InvalidateDeviceObjects(); @@ -20,5 +23,5 @@ IMGUI_API bool ImGui_ImplDX9_CreateDeviceObjects(); // You may or not need this for your implementation, but it can serve as reference for handling inputs. // Commented out to avoid dragging dependencies on types. You can copy the extern declaration in your code. /* -IMGUI_API LRESULT ImGui_ImplDX9_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +IMGUI_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); */ diff --git a/GWToolbox/GWToolbox/main.cpp b/GWToolbox/GWToolbox/main.cpp index bc1b4eee7..b1790fc9a 100644 --- a/GWToolbox/GWToolbox/main.cpp +++ b/GWToolbox/GWToolbox/main.cpp @@ -20,6 +20,8 @@ DWORD WINAPI init(HMODULE hModule){ if (!(found && *found)) { MessageBoxA(0, "We can't determine if the character is ingame.\nContact the developpers.", "GWToolbox++ - Clientside Error Detected", 0); FreeLibraryAndExitThread(hModule, EXIT_SUCCESS); + } else { + printf("[SCAN] is_ingame = %p\n", found); } DWORD *is_ingame = *found; diff --git a/GWToolboxpp.sln b/GWToolboxpp.sln index 14836cde2..e897af22f 100644 --- a/GWToolboxpp.sln +++ b/GWToolboxpp.sln @@ -17,7 +17,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GWCA", "Dependencies\GWCA\G EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "LUA", "LUA\LUA.vcxproj", "{07E36EE0-D8A8-48F0-A872-681512E93CCD}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GWCA_Tests", "Dependencies\GWCA\Tests\GWCA_Tests.vcxproj", "{ECC70C1A-462D-4BF1-95CA-B8B95E6E01AC}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GWCA_Test_DLL", "Dependencies\GWCA\GWCA_Test_DLL\GWCA_Test_DLL.vcxproj", "{ECC70C1A-462D-4BF1-95CA-B8B95E6E01AC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GWCA_Test_Static", "Dependencies\GWCA\GWCA_Test_Static\GWCA_Test_Static.vcxproj", "{A917F016-425B-485A-AB6B-9F0331B5CF5D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -45,6 +47,10 @@ Global {ECC70C1A-462D-4BF1-95CA-B8B95E6E01AC}.Debug|Win32.Build.0 = Debug|Win32 {ECC70C1A-462D-4BF1-95CA-B8B95E6E01AC}.Release|Win32.ActiveCfg = Release|Win32 {ECC70C1A-462D-4BF1-95CA-B8B95E6E01AC}.Release|Win32.Build.0 = Release|Win32 + {A917F016-425B-485A-AB6B-9F0331B5CF5D}.Debug|Win32.ActiveCfg = Debug|Win32 + {A917F016-425B-485A-AB6B-9F0331B5CF5D}.Debug|Win32.Build.0 = Debug|Win32 + {A917F016-425B-485A-AB6B-9F0331B5CF5D}.Release|Win32.ActiveCfg = Release|Win32 + {A917F016-425B-485A-AB6B-9F0331B5CF5D}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE