From 81f97fab190eea067057e46c452ca5870dde8555 Mon Sep 17 00:00:00 2001 From: cppimmo Date: Wed, 22 Jun 2022 14:48:22 -0500 Subject: [PATCH] prepare for second release Signed-off-by: cppimmo --- CHANGELOG.md | 34 ++++++ Examples/Fm.cpp | 53 ++++++---- README.md | 32 ++++-- Source/FmGui.cpp | 269 ++++++++++++++++++++++++++++++++++------------- Source/FmGui.hpp | 67 ++++++++++-- 5 files changed, 344 insertions(+), 111 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..1efd591 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,34 @@ +# Changelog + + + +## Version 1.0.0 - 21 Mar 2022 + +### Added +- Initial release. + +### Fixed + +### Changed + +### Known Issues + +## Version 1.0.1 - 22 Mar 2022 + +### Added +- Add more error handling. +- Add basic configuration structure with defaults. +- Implement configuration structure as argument to `FmGui::StartupHook().` +- Add comments. +- Add implementation for OnResize. Not used yet. + +### Fixed +- Fixed crashes due to derefrencing ImGuiContext on mission restart. + +### Changed +- Updated instructions in *README.md*. + - Inform users that static linking is prefered. +- Updated *Examples/Fm.cpp*. + +### Known Issues +- Crashes on second mission quit when ImGui IniFileName is not null pointer. diff --git a/Examples/Fm.cpp b/Examples/Fm.cpp index 4890204..ae36843 100644 --- a/Examples/Fm.cpp +++ b/Examples/Fm.cpp @@ -9,12 +9,12 @@ // The user's ImGuiRoutine function: void -FMImGuiRoutine(void) +FmGuiRoutine(void) { - /* - * Set up your ImGui widgets here. Refer to the ImGui documentation and - * examples for creating widgets. - */ + /* + * Set up your ImGui widgets here. Refer to the ImGui documentation and + * examples for creating widgets. + */ ImGui::ShowDemoWindow(); // ImGui::ShowAboutWindow(); // ImGui::ShowUserGuide(); @@ -25,12 +25,14 @@ FMImGuiRoutine(void) // The user's ImGuiInputRoutine function: void -FMImGuiInputRoutine(UINT uMsg, WPARAM wParam, LPARAM lParam) +FmGuiInputRoutine(UINT uMsg, WPARAM wParam, LPARAM lParam) { - /* - * Handle input. See the links below for Win32 input handling. - * - */ + /* + * Handle input. See the links below for Win32 input handling. + * https://docs.microsoft.com/en-us/windows/win32/inputdev/keyboard-input + * https://docs.microsoft.com/en-us/windows/win32/learnwin32/keyboard-input + * https://docs.microsoft.com/en-us/windows/win32/inputdev/using-keyboard-input + */ if (uMsg == WM_KEYDOWN) { if (wParam == 'W') { std::printf("W key pressed!\n"); @@ -44,17 +46,30 @@ FMImGuiInputRoutine(UINT uMsg, WPARAM wParam, LPARAM lParam) void ed_fm_set_plugin_data_install_path(const char *path) { - // Start the FmGui and associated hook. - if (!FmGui::StartupHook()) { + /* + * Optional configuration. For more information and default values see the + * FmGuiConfig struct in FmGui.hpp. + */ + FmGuiConfig fmGuiConfig; + /* + * This following line is known to cause crashes on the second mission's + * quit: + * fmGuiConfig.imGuiIniFileName = std::string(path) + "/bin/imgui.ini"; + */ + fmGuiConfig.imGuiStyle = FmGuiStyle::CLASSIC; // FmGuiStyle::DARK + + // Start the FmGui and associated hook. + // You can ommit the fmGuiConfig arugment entirely: FmGui::StartupHook() is valid. + if (!FmGui::StartupHook(fmGuiConfig)) { std::fprintf(stderr, "FmGui::StartupHook failed!\n"); } else { - // Print the addresses of the D3D11 context. - std::printf("%s", FmGui::AddressDump().c_str()); - // Set the pointers to your ImGui and ImGui Input routines. - FmGui::SetImGuiRoutinePtr(FMImGuiRoutine); - FmGui::SetImGuiInputRoutinePtr(FMImGuiInputRoutine); - // Set the widget visibility to ON. + // Print the addresses of the D3D11 context. + std::printf("%s\n", FmGui::AddressDump().c_str()); + // Set the pointers to your ImGui and ImGui Input routines. + FmGui::SetImGuiRoutinePtr(FmGuiRoutine); + FmGui::SetImGuiInputRoutinePtr(FmGuiInputRoutine); + // Set the widget visibility to ON. FmGui::SetWidgetVisibility(true); } } @@ -64,7 +79,7 @@ ed_fm_set_plugin_data_install_path(const char *path) void ed_fm_release(void) { - // Finally close the FmGui and associated hook. + // Finally close the FmGui and associated hook. if (!FmGui::ShutdownHook()) { std::fprintf(stderr, "FmGui::ShutdownHook failed...\n"); } diff --git a/README.md b/README.md index 595ec54..66760da 100644 --- a/README.md +++ b/README.md @@ -64,37 +64,47 @@ below. - FmGui.hpp - FmGui.cpp - .vcxproj in this directory. + - .sln in this directory. In Visual Studio select your project in the Solution Explorer and then add the following entry to *Configuration Properties -> C/C++ -> General -> Additional Include Directories*: $(ProjectDir)..\lib\imgui-1.87\ -As for the MinHook v1.3.3 binary release, assume the same project directory +As for the MinHook v1.3.3 release, assume the same project directory structure. - EFM - lib - - MinHook_133_bin - - bin - - MinHook.x64.lib + - MinHook_133 (directory has been renamed) + - lib + - libMinHook-v\-\.x64.lib - include - MY_EFM_PROJECT - FmGui.hpp - FmGui.cpp - .vcxproj in this directory. + - .sln in this directory. -To add the include directory and link statically for MinHook you can use the -following instructions: +I personally recommended downloading the the +[static library release](https://github.com/TsudaKageyu/minhook/releases/download/v1.3.3/MinHook_133_lib.zip) +for MinHook or building it from source. That way you don't have to worry about +having multiple dynamic link libraries in your aircraft mod's bin folder. + +To add the include directory and link statically for the MinHook static library +release you can use the following instructions: In Visual Studio select your project in the Solution Explorer and then add the following entry to *Configuration Properties -> C/C++ -> General -> Additional -Include Directories*: $(ProjectDir)..\lib\MinHook_133_bin\include\ +Include Directories*: $(ProjectDir)..\lib\MinHook_133\include\ Select *Configuration Properties -> Linker -> General -> Additional Libraries -Directories* and add $(ProjectDir)/../lib/MinHook_133_bin/bin/ +Directories* and add $(ProjectDir)/../lib/MinHook_133/lib/ -Select *Configuration Properties -> Linker -> Input -> Additional Dependencies* -and add MinHook.x64.lib +In the MinHook_133/lib/ directory, you will see several different static +libraries. You will most likely want to link against libMinHook-x64-v141-mt.lib +for your release builds and libMinHook-x64-v141-mtd.lib for your debug builds. +Add these for you different configurations in *Configuration Properties -> +Linker -> Input -> Additional Dependencies*. Phew, I think that's everything. @@ -119,6 +129,8 @@ These source files were built and tested using Visual Studio Community 2022, Windows 10 SDK Version 10.0.19041.0, the C++20 Standard, the MinHook library v1.3.3, the DirectX SDK Version _____, and the ImGui library version 1.87. +The minimum C++ ISO Standard requirement for these files is C++11. + ## 5. License: This project is licensed under the permissive BSD 2-Clause License. For more diff --git a/Source/FmGui.cpp b/Source/FmGui.cpp index a2c3c8d..e85330e 100644 --- a/Source/FmGui.cpp +++ b/Source/FmGui.cpp @@ -29,7 +29,7 @@ #include "FmGui.hpp" // #include "cppimmo/FmGui.hpp" #if defined FMGUI_CPPIMMO -#include "cppimmo/Logger.h" +#include "cppimmo/Logger.hpp" #endif #include @@ -91,9 +91,13 @@ static bool isInitialized = false, areWidgetsEnabled = false; static ImGuiRoutinePtr pWidgetRoutine = nullptr; static ImGuiInputRoutinePtr pInputRoutine = nullptr; // ImGui Configuration -static constexpr ImGuiConfigFlags imGuiConfigFlags = - ImGuiConfigFlags_NavNoCaptureKeyboard; -static constexpr const char *imGuiConfigFileName = "imgui.ini"; +// static constexpr ImGuiConfigFlags imGuiConfigFlags = +// ImGuiConfigFlags_NavNoCaptureKeyboard; +// static constexpr const char *imGuiConfigFileName = "imgui.ini"; +static ImGuiContext *pImGuiContext = nullptr; +static bool isImGuiImplWin32Initialized = false; +static bool isImGuiImplDX11Initialized = false; +static FmGuiConfig fmGuiConfig; } // namespace FmGui void @@ -190,7 +194,7 @@ FmGui::DebugLayerMessageDump(void) #endif } // Allocate memory. - D3D11_MESSAGE *message = (D3D11_MESSAGE *)malloc(messageSize); + D3D11_MESSAGE *message = (D3D11_MESSAGE *)std::malloc(messageSize); if (!message) { #if defined FMGUI_CPPIMMO LOG_WRITELN_T("message memory alloc failed!", Utils::Logger::Type::ERROR); @@ -404,8 +408,9 @@ FmGui::SetWidgetVisibility(bool isEnabled) } bool -FmGui::StartupHook(void) +FmGui::StartupHook(const FmGuiConfig &config) { + fmGuiConfig = config; #if defined FMGUI_CPPIMMO LOG_WRITELN_T("Redirecting Direct3D routines...", Utils::Logger::Type::MESSAGE); @@ -509,20 +514,66 @@ FmGui::SwapChainPresentImpl(IDXGISwapChain *pSwapChain, UINT syncInterval, #endif return pSwapChainPresentTrampoline(pSwapChain, syncInterval, flags); } - ImGui::CreateContext(); + pImGuiContext = ImGui::CreateContext(); + if (!pImGuiContext) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("ImGui::CreateContext failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(stderr, "ImGui::CreateContext failed!\n"); +#endif + return pSwapChainPresentTrampoline(pSwapChain, syncInterval, flags); + } + ImGui::SetCurrentContext(pImGuiContext); ImGuiIO &imGuiIO = ImGui::GetIO(); + // Configuration of the current ImGui context. + imGuiIO.ConfigFlags |= fmGuiConfig.imGuiConfigFlags; + if (fmGuiConfig.imGuiIniFileName.empty()) + imGuiIO.IniFilename = nullptr; + else + imGuiIO.IniFilename = fmGuiConfig.imGuiIniFileName.c_str(); + imGuiIO.IniSavingRate = fmGuiConfig.imGuiIniSavingRate; + switch (fmGuiConfig.imGuiStyle) { + case FmGuiStyle::CLASSIC: + ImGui::StyleColorsClassic(); + break; + case FmGuiStyle::DARK: + ImGui::StyleColorsDark(); + break; + case FmGuiStyle::LIGHT: + ImGui::StyleColorsLight(); + break; + } + // Get the IDXGISwapChain's description. DXGI_SWAP_CHAIN_DESC swapChainDesc; ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); - pSwapChain->GetDesc(&swapChainDesc); - imGuiIO.ConfigFlags |= imGuiConfigFlags; - imGuiIO.IniFilename = imGuiConfigFileName; - + if (FAILED(pSwapChain->GetDesc(&swapChainDesc))) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("IDXGISwapChain::GetDesc failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(stderr, "IDXGISwapChain::GetDesc failed!\n"); +#endif + return pSwapChainPresentTrampoline(pSwapChain, syncInterval, flags); + } + // Set global window handle to the OutputWindow of the IDXGISwapChain. hWnd = swapChainDesc.OutputWindow; - pWndProcApp = reinterpret_cast(SetWindowLongPtr(hWnd, + pWndProcApp = reinterpret_cast(SetWindowLongPtrW(hWnd, GWLP_WNDPROC, reinterpret_cast(WndProc))); + if (pWndProcApp == NULL) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("SetWindowLongPtrW failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(pFileStderr, "SetWindowLongPtrW failed!\n"); +#endif + return S_FALSE; + } + // ImGui Win32 and DX11 implementation initialization. bool result = ImGui_ImplWin32_Init(hWnd); + isImGuiImplWin32Initialized = result; if (!result) { #if defined FMGUI_CPPIMMO LOG_WRITELN_T("ImGui_ImplWin32_Init failed!", @@ -530,8 +581,11 @@ FmGui::SwapChainPresentImpl(IDXGISwapChain *pSwapChain, UINT syncInterval, #elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO std::fprintf(pFileStderr, "ImGui_ImplWin32_Init failed!\n"); #endif + return S_FALSE; } + result = ImGui_ImplDX11_Init(pDevice, pDeviceContext); + isImGuiImplDX11Initialized = result; if (!result) { #if defined FMGUI_CPPIMMO LOG_WRITELN_T("ImGui_ImplDX11_Init failed!", @@ -539,33 +593,43 @@ FmGui::SwapChainPresentImpl(IDXGISwapChain *pSwapChain, UINT syncInterval, #elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO std::fprintf(pFileStderr, "ImGui_ImplDX11_Init failed!\n"); #endif + return S_FALSE; } - ImGui::GetIO().ImeWindowHandle = hWnd; + imGuiIO.ImeWindowHandle = hWnd; + // Retrieve the back buffer from the IDXGISwapChain. ID3D11Texture2D *pSwapChainBackBuffer = nullptr; hResult = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&pSwapChainBackBuffer)); if (FAILED(hResult)) { #if defined FMGUI_CPPIMMO - LOG_WRITELN_T("GetBuffer failed!", Utils::Logger::Type::ERROR); + LOG_WRITELN_T("IDXGISwapChain::GetBuffer failed!", + Utils::Logger::Type::ERROR); #elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO - std::fprintf(pFileStderr, "GetBuffer failed!\n"); + std::fprintf(pFileStderr, "IDXGISwapChain::GetBuffer failed!\n"); #endif + return S_FALSE; } hResult = pDevice->CreateRenderTargetView(pSwapChainBackBuffer, nullptr, &pRenderTargetView); if (FAILED(hResult)) { #if defined FMGUI_CPPIMMO - LOG_WRITELN_T("CreateRenderTargetView failed!", + LOG_WRITELN_T("ID3D11Device::CreateRenderTargetView failed!", Utils::Logger::Type::ERROR); #elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO - std::fprintf(pFileStderr, "CreateRenderTargetView failed!\n"); + std::fprintf(pFileStderr, + "ID3D11Device::CreateRenderTargetView failed!\n"); #endif + return S_FALSE; } ReleaseCOM(pSwapChainBackBuffer); isInitialized = true; } else { + ImGui::SetCurrentContext(pImGuiContext); + // Check for NULL context. + if (!ImGui::GetCurrentContext()) + return pSwapChainPresentTrampoline(pSwapChain, syncInterval, flags); ImGui_ImplWin32_NewFrame(); ImGui_ImplDX11_NewFrame(); @@ -622,18 +686,39 @@ FmGui::ShutdownHook(void) return false; } - ImGui_ImplDX11_Shutdown(); - ImGui_ImplWin32_Shutdown(); - ImGui::DestroyContext(); + if (isImGuiImplDX11Initialized) { + ImGui_ImplDX11_Shutdown(); + isImGuiImplDX11Initialized = false; + } + + if (isImGuiImplWin32Initialized) { + ImGui_ImplWin32_Shutdown(); + isImGuiImplWin32Initialized = false; + } + + if (pImGuiContext != nullptr) { + ImGui::DestroyContext(pImGuiContext); + pImGuiContext = nullptr; + } ReleaseCOM(pDevice); ReleaseCOM(pDeviceContext); ReleaseCOM(pRenderTargetView); if (hWnd) { // Set hWnd's WndProc back to it's original proc. - SetWindowLongPtr(hWnd, GWLP_WNDPROC, - reinterpret_cast(pWndProcApp)); + if (SetWindowLongPtrW(hWnd, GWLP_WNDPROC, + reinterpret_cast(pWndProcApp)) == 0) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("SetWindowLongPtrW failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(pFileStderr, "SetWindowLongPtrW failed!\n"); +#endif + return false; + } } + // Set the Present initialization check to false. + isInitialized = false; return true; } @@ -641,9 +726,8 @@ static void FmGui::OnResize(IDXGISwapChain *pSwapChain, UINT newWidth, UINT newHeight) { /* - * This function is not implemented yet. - */ - /* + * This function is not fully implemented yet. + * * First release the RenderTargetView. * Then Resize the SwapChain buffers. * Get the BackBuffer, Recreate the RenderTargetView, @@ -651,65 +735,89 @@ FmGui::OnResize(IDXGISwapChain *pSwapChain, UINT newWidth, UINT newHeight) * Also set the render targets of the DeviceContext as well as the * rasterizer viewport. */ - /* CODE FROM ANOTHER ONE OF MY PROJECTS - pRenderTarget.Reset(); - pDepthStencilView.Reset(); - pDepthStencilBuffer.Reset(); - - HRESULT hr = S_OK; - - hr = pSwapChain->ResizeBuffers(1, newWidth, newHeight, DXGI_FORMAT_B8G8R8A8_UNORM, 0u); - wrl::ComPtr pBackBuffer; //Create our BackBuffer - hr = pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(pBackBuffer.GetAddressOf())); - THROW_IF_FAILED(hr, "GetBuffer failed"); - //Create our Render Target - hr = pDevice->CreateRenderTargetView(pBackBuffer.Get(), nullptr, pRenderTarget.GetAddressOf()); - pBackBuffer.Reset(); - THROW_IF_FAILED(hr, "Create render target view failed"); - - D3D11_TEXTURE2D_DESC ds = {}; - ds.Width = newWidth; - ds.Height = newHeight; - ds.MipLevels = 1; - ds.ArraySize = 1; - ds.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; - ds.SampleDesc.Count = samplingLevel; - ds.SampleDesc.Quality = sampleQuality - 1; - ds.Usage = D3D11_USAGE_DEFAULT; - ds.BindFlags = D3D11_BIND_DEPTH_STENCIL; - ds.CPUAccessFlags = 0; - ds.MiscFlags = 0; - - hr = pDevice->CreateTexture2D(&ds, nullptr, pDepthStencilBuffer.GetAddressOf()); - THROW_IF_FAILED(hr, "DepthStencilBuffer could not be created"); - hr = pDevice->CreateDepthStencilView(pDepthStencilBuffer.Get(), nullptr, pDepthStencilView.GetAddressOf()); - THROW_IF_FAILED(hr, "DepthStencilView could not be created"); - //Set our Render Target - pContext->OMSetRenderTargets(1, pRenderTarget.GetAddressOf(), pDepthStencilView.Get()); - - CD3D11_VIEWPORT viewport(0.0f, 0.0f, static_cast(newWidth), static_cast(newHeight), 0.0f, 1.0f); - pContext->RSSetViewports(1, &viewport); - */ + ReleaseCOM(pRenderTargetView); + + DXGI_SWAP_CHAIN_DESC swapChainDesc; + ZeroMemory(&swapChainDesc, sizeof(swapChainDesc)); + if (FAILED(pSwapChain->GetDesc(&swapChainDesc))) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("IDXGISwapChain::GetDesc failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(pFileStderr, "IDXGISwapChain::GetDesc failed!\n"); +#endif + return; + } + + if (FAILED(pSwapChain->ResizeBuffers( + swapChainDesc.BufferCount, + newWidth, newHeight, + swapChainDesc.BufferDesc.Format, 0u))) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("IDXGISwapChain::ResizeBuffers failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(pFileStderr, "IDXGISwapChain::ResizeBuffers failed!\n"); +#endif + return; + } + + ID3D11Texture2D *pSwapChainBackBuffer = nullptr; + if (FAILED(pSwapChain->GetBuffer(0u, __uuidof(ID3D11Texture2D), + reinterpret_cast(&pSwapChainBackBuffer)))) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("IDXGISwapChain::GetBuffer failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(pFileStderr, "IDXGISwapChain::GetBuffer failed!\n"); +#endif + ReleaseCOM(pSwapChainBackBuffer); + return; + } + + if (FAILED(pDevice->CreateRenderTargetView(pSwapChainBackBuffer, nullptr, + &pRenderTargetView))) { +#if defined FMGUI_CPPIMMO + LOG_WRITELN_T("ID3D11Device::CreateRenderTargetView failed!", + Utils::Logger::Type::ERROR); +#elif !defined FMGUI_CPPIMMO && defined FMGUI_ENABLE_IO + std::fprintf(pFileStderr, + "ID3D11Device::CreateRenderTargetView failed!\n"); +#endif + ReleaseCOM(pSwapChainBackBuffer); + return; + } + ReleaseCOM(pSwapChainBackBuffer); + pDeviceContext->OMSetRenderTargets(1, &pRenderTargetView, nullptr); + CD3D11_VIEWPORT viewport(0.0f, 0.0f, static_cast(newWidth), + static_cast(newHeight), 0.0f, 1.0f); + pDeviceContext->RSSetViewports(1, &viewport); } static LRESULT FmGui::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - ImGuiIO &imGuiIO = ImGui::GetIO(); - POINT cursorPos; GetCursorPos(&cursorPos); - if (FmGui::hWnd) - ScreenToClient(FmGui::hWnd, &cursorPos); - imGuiIO.MousePos.x = cursorPos.x; - imGuiIO.MousePos.y = cursorPos.y; - + // Check if there is a valid context. + if (ImGui::GetCurrentContext()) { + ImGuiIO &imGuiIO = ImGui::GetIO(); + POINT cursorPos; GetCursorPos(&cursorPos); + if (FmGui::hWnd) + ScreenToClient(FmGui::hWnd, &cursorPos); + imGuiIO.MousePos.x = cursorPos.x; + imGuiIO.MousePos.y = cursorPos.y; + } + // Only handle if widgets are enabled. if (areWidgetsEnabled) { - if (ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam)) + // Check for a non-NULL context and handle ImGui events. + if (ImGui::GetCurrentContext() + && ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam)) { return TRUE; - + } + // Handle user's non-NULL input routine. if (pInputRoutine != nullptr) pInputRoutine(uMsg, wParam, lParam); } - + // Other events. switch (uMsg) { case WM_SIZE: { const UINT newWidth = static_cast(LOWORD(lParam)); @@ -719,9 +827,20 @@ FmGui::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) break; } } - return CallWindowProc(pWndProcApp, hWnd, uMsg, wParam, lParam); + return CallWindowProcW(pWndProcApp, hWnd, uMsg, wParam, lParam); } #if defined FMGUI_CPPIMMO } // namespace Utils #endif + +/* + * FmGuiConfig's members need be defined where imgui/imgui.h is included. + */ +FmGuiConfig::FmGuiConfig(void) + : imGuiStyle(FmGuiStyle::DARK), + imGuiConfigFlags(static_cast(ImGuiConfigFlags_NavNoCaptureKeyboard)), + imGuiIniFileName(), + imGuiIniSavingRate(5.0f) +{ +} diff --git a/Source/FmGui.hpp b/Source/FmGui.hpp index a3b137a..0c63f1e 100644 --- a/Source/FmGui.hpp +++ b/Source/FmGui.hpp @@ -26,8 +26,8 @@ ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ** ============================================================================= **/ -#ifndef __FMGUI_HPP__ -#define __FMGUI_HPP__ +#ifndef _FMGUI_HPP_ +#define _FMGUI_HPP_ 0 /* * This a preprocessor flag specific to the author's project. It should be left @@ -55,19 +55,65 @@ */ // #include -// Define FMGUI_ENABLE_IO to enable output. +// Define FMGUI_ENABLE_IO to disable ouput while in _DEBUG. #define FMGUI_ENABLE_IO #if !defined(FMGUI_FASTCALL) #define FMGUI_FASTCALL __fastcall #endif -// Disable ImGui XINPUT. +// Disable ImGui XINPUT #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD // Forward declare IDXGISwapChain structure. struct IDXGISwapChain; +enum struct FmGuiStyle +{ + CLASSIC, + DARK, + LIGHT +}; + +// Forward declare typedef for ImGuiConfigFlags. +using ImGuiConfigFlags = int; + +struct FmGuiConfig +{ +public: + FmGuiConfig(void); + FmGuiConfig(const FmGuiConfig &) = default; + FmGuiConfig &operator=(const FmGuiConfig &) = default; + FmGuiConfig(FmGuiConfig &&) = default; + FmGuiConfig &operator=(FmGuiConfig &&) = default; +public: + /* + * Enumeration that can be set to the three default styles provided by ImGui + * in the form FmGuiStyle::CLASSIC, FmGuiStyle::DARK, & FmGuiStyle::LIGHT. + * Default value: FmGuiStyle::DARK + */ + FmGuiStyle imGuiStyle; + /* + * The configuration flags passed to the ImGui context. See ImGui + * documentation for ImGuiConfigFlags. + * Default value: ImGuiConfigFlags_NavNoCaptureKeyboard + */ + ImGuiConfigFlags imGuiConfigFlags; + /* + * Full path and filename of the auto generated ImGui .ini configuration file. + * This can be a full or relative path. See Examples/Fm.cpp for more info. + * This string is empty by default and results in no configuration file. + * Default value: "" (empty) + */ + std::string imGuiIniFileName; + /* + * The rate in seconds at which the .ini configuration file is updated. + * Only applicable when the ImGui .ini is enabled. + * Default value: 5.0f + */ + float imGuiIniSavingRate; +}; + #if defined FMGUI_CPPIMMO namespace Utils { @@ -131,11 +177,18 @@ void RedirectStdErr(std::FILE *const pFile); bool SetWidgetVisibility(bool isEnabled); /* * Start the FmGui and ImGui. + * You can supply an optional configuration using an FmGuiConfig object. + * Example: + * FmGuiConfig config; + * config.imGuiStyle = FmGuiStyle::DARK; + * if (!FmGui::StartupHook(config)) { + * // FAILED! + * } */ #if defined FMGUI_CPPIMMO -[[nodiscard]] bool StartupHook(void); +[[nodiscard]] bool StartupHook(const FmGuiConfig &config = FmGuiConfig()); #else -bool StartupHook(void); +bool StartupHook(const FmGuiConfig &config = FmGuiConfig()); #endif /* * Return formatted string of the D3D context memory addresses. @@ -193,4 +246,4 @@ ReleaseCOM(Type **ppInterface) } // namespace Utils #endif -#endif // __FMGUI_HPP__ \ No newline at end of file +#endif /* !_FMGUI_HPP_ */ \ No newline at end of file