From dca9468f66f48db7ce38e27a8a8ab7ee40d8e14c Mon Sep 17 00:00:00 2001 From: Toni Uhlig Date: Mon, 14 Oct 2019 20:48:50 +0200 Subject: added new static lib and moved code from Test to it; use "old" console app as integration test --- GdiRadar.sln | 16 ++ GdiRadar/GdiRadar.cpp | 343 -------------------------------- GdiRadar/GdiRadar.h | 56 ------ GdiRadar/GdiRadar.vcxproj | 14 +- GdiRadar/GdiRadar.vcxproj.filters | 6 - GdiRadar/GdiRadarMain.cpp | 2 +- GdiRadarLib/GdiRadar.cpp | 343 ++++++++++++++++++++++++++++++++ GdiRadarLib/GdiRadar.h | 56 ++++++ GdiRadarLib/GdiRadarLib.vcxproj | 168 ++++++++++++++++ GdiRadarLib/GdiRadarLib.vcxproj.filters | 36 ++++ GdiRadarLib/stdafx.cpp | 1 + GdiRadarLib/stdafx.h | 14 ++ GdiRadarLib/targetver.h | 8 + 13 files changed, 654 insertions(+), 409 deletions(-) delete mode 100644 GdiRadar/GdiRadar.cpp delete mode 100644 GdiRadar/GdiRadar.h create mode 100644 GdiRadarLib/GdiRadar.cpp create mode 100644 GdiRadarLib/GdiRadar.h create mode 100644 GdiRadarLib/GdiRadarLib.vcxproj create mode 100644 GdiRadarLib/GdiRadarLib.vcxproj.filters create mode 100644 GdiRadarLib/stdafx.cpp create mode 100644 GdiRadarLib/stdafx.h create mode 100644 GdiRadarLib/targetver.h diff --git a/GdiRadar.sln b/GdiRadar.sln index 398fc16..68d956b 100644 --- a/GdiRadar.sln +++ b/GdiRadar.sln @@ -5,16 +5,32 @@ VisualStudioVersion = 15.0.28307.757 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GdiRadar", "GdiRadar\GdiRadar.vcxproj", "{C9774084-968A-4F0A-96F7-B5F4E7B254A4}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GdiRadarLib", "GdiRadarLib\GdiRadarLib.vcxproj", "{846C5E70-36F1-4790-AAD5-7DE55345AF2E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Debug|x64.ActiveCfg = Debug|x64 {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Debug|x64.Build.0 = Debug|x64 + {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Debug|x86.ActiveCfg = Debug|Win32 + {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Debug|x86.Build.0 = Debug|Win32 {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Release|x64.ActiveCfg = Release|x64 {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Release|x64.Build.0 = Release|x64 + {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Release|x86.ActiveCfg = Release|Win32 + {C9774084-968A-4F0A-96F7-B5F4E7B254A4}.Release|x86.Build.0 = Release|Win32 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Debug|x64.ActiveCfg = Debug|x64 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Debug|x64.Build.0 = Debug|x64 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Debug|x86.ActiveCfg = Debug|Win32 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Debug|x86.Build.0 = Debug|Win32 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Release|x64.ActiveCfg = Release|x64 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Release|x64.Build.0 = Release|x64 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Release|x86.ActiveCfg = Release|Win32 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/GdiRadar/GdiRadar.cpp b/GdiRadar/GdiRadar.cpp deleted file mode 100644 index add5b72..0000000 --- a/GdiRadar/GdiRadar.cpp +++ /dev/null @@ -1,343 +0,0 @@ -#include "pch.h" -#include "GdiRadar.h" - -#include -#include - -#pragma comment(lib, "Gdi32.lib") - -#define INVALID_MAP_VALUE ((UINT64)0) - - -struct gdi_radar_drawing -{ - HBRUSH EnemyBrush; - HPEN DefaultPen; - COLORREF TextCOLOR; - RECT DC_Dimensions; - HDC hdc; - UINT64 GameMapWindowWidth; - UINT64 GameMapWindowHeight; - bool StickToBottom; -}; - -struct gdi_radar_context -{ - PWSTR className; - ATOM classAtom; - PWSTR windowName; - HWND myDrawWnd; - WNDCLASSW wc; - - double minimumUpdateTime; - UINT64 maximumRedrawFails; - clock_t lastTimeUpdated; - UINT64 GameMapWidth; - UINT64 GameMapHeight; - size_t reservedEntities; - - struct gdi_radar_drawing drawing; - std::vector entities; -}; - - -static void draw_entity(struct gdi_radar_context * const ctx, struct entity * const ent) -{ -#if 0 - RECT healthRect = { posx - 10, posy - 10, posx + 10, posy - 5 }; - FillRect(hdc, &rect, color); - - RECT textRect = { posx, posy, posx + 10, posy - 5 }; - DrawText(hdc, TEXT("Michael Morrison"), -1, &rect, - DT_SINGLELINE | DT_CENTER | DT_VCENTER); -#endif - - switch (ent->color) { - case EC_RED: - SelectObject(ctx->drawing.hdc, ctx->drawing.EnemyBrush); - break; - } - - float frealx = ent->pos[0] * ((float)ctx->drawing.GameMapWindowWidth / ctx->GameMapWidth); - float frealy = ent->pos[1] * ((float)ctx->drawing.GameMapWindowHeight / ctx->GameMapHeight); - int realx = (int)frealx; - int realy = (int)frealy; - Ellipse(ctx->drawing.hdc, realx - 5, realy - 5, realx + 5, realy + 5); -} - -static void CalcGameToWindowDimensions(struct gdi_radar_context * const ctx) -{ - float aspectRatio = (float)ctx->GameMapWidth / ctx->GameMapHeight; - if (ctx->drawing.StickToBottom) { - float newWidth = (float)ctx->drawing.DC_Dimensions.bottom / aspectRatio; - ctx->drawing.GameMapWindowHeight = ctx->drawing.DC_Dimensions.bottom - 1; - ctx->drawing.GameMapWindowWidth = (UINT64)newWidth; - } - else { - float newHeight = (float)ctx->drawing.DC_Dimensions.right / aspectRatio; - ctx->drawing.GameMapWindowHeight = (UINT64)newHeight; - ctx->drawing.GameMapWindowWidth = ctx->drawing.DC_Dimensions.right - 1; - } -} - -static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) -{ - struct gdi_radar_context * wnd_ctx = NULL; - - if (message == WM_CREATE) { - LONG_PTR pParent = (LONG_PTR)((LPCREATESTRUCTW)lparam)->lpCreateParams; - SetWindowLongPtrW(hwnd, -21, pParent); - wnd_ctx = (struct gdi_radar_context *)pParent; - } - else { - wnd_ctx = (struct gdi_radar_context *)GetWindowLongPtrW(hwnd, -21); - } - - if (!wnd_ctx) - { - std::cout << "WndProc: ctx NULL!\n"; - return DefWindowProc(hwnd, message, wparam, lparam); - } - - struct gdi_radar_drawing * const drawing = &wnd_ctx->drawing; - if (!drawing) - { - std::cout << "WndProc: drawing NULL!\n"; - return DefWindowProc(hwnd, message, wparam, lparam); - } - - switch (message) - { - case WM_CREATE: - std::cout << "WM_CREATE\n"; - drawing->hdc = GetDC(hwnd); - drawing->EnemyBrush = CreateSolidBrush(RGB(255, 0, 0)); - drawing->DefaultPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0)); - drawing->TextCOLOR = RGB(0, 255, 0); - SetBkMode(drawing->hdc, TRANSPARENT); - return 0; - case WM_DESTROY: - std::cout << "WM_DESTROY\n"; - DeleteObject(drawing->EnemyBrush); - DeleteObject(drawing->DefaultPen); - DeleteDC(drawing->hdc); - PostQuitMessage(0); - return 0; - - case WM_PAINT: - { - std::cout << "WM_PAINT\n"; - PAINTSTRUCT ps; - - BeginPaint(hwnd, &ps); - - SelectObject(drawing->hdc, drawing->DefaultPen); - POINT lines[] = { { 0,0 }, { (LONG)drawing->GameMapWindowWidth, 0 }, - { (LONG)drawing->GameMapWindowWidth, (LONG)drawing->GameMapWindowHeight }, - { 0, (LONG)drawing->GameMapWindowHeight }, { 0,0 } }; - Polyline(drawing->hdc, lines, 5); - for (auto& entity : wnd_ctx->entities) { - draw_entity(wnd_ctx, &entity); - } - EndPaint(hwnd, &ps); - - wnd_ctx->lastTimeUpdated = clock(); - break; - } - - case WM_LBUTTONDOWN: - std::cout << "WM_LBUTTONDOWN\n"; - break; - case WM_NCLBUTTONDOWN: - std::cout << "WM_NCLBUTTONDOWN\n"; - break; - case WM_CHAR: - std::cout << "WM_CHAR\n"; - break; - case WM_MOVE: - std::cout << "WM_MOVE\n"; - break; - case WM_SIZE: - std::cout << "WM_SIZE\n"; - GetClientRect(hwnd, &drawing->DC_Dimensions); - CalcGameToWindowDimensions(wnd_ctx); - break; - } - - //std::cout << "Default window proc for message 0x" << std::hex << message << std::endl; - return DefWindowProcW(hwnd, message, wparam, lparam); -} - -struct gdi_radar_context * const - gdi_radar_configure(struct gdi_radar_config const * const cfg, - HINSTANCE hInst) -{ - struct gdi_radar_context * result = new gdi_radar_context; - if (!result) - { - return NULL; - } - ZeroMemory(result, sizeof(*result)); - - /* config params */ - result->className = _wcsdup(cfg->className); - result->windowName = _wcsdup(cfg->windowName); - result->minimumUpdateTime = cfg->minimumUpdateTime; - result->maximumRedrawFails = cfg->maximumRedrawFails; - result->reservedEntities = cfg->reservedEntities; - result->entities.reserve(result->reservedEntities); - - /* other */ - result->wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); - result->wc.hCursor = LoadCursor(hInst, IDC_ARROW); - result->wc.hIcon = LoadIcon(hInst, IDI_APPLICATION); - result->wc.hInstance = hInst; - result->wc.lpfnWndProc = WndProc; - result->wc.lpszClassName = result->className; - result->wc.style = CS_HREDRAW | CS_VREDRAW; - result->GameMapWidth = INVALID_MAP_VALUE; - result->GameMapHeight = INVALID_MAP_VALUE; - - return result; -} - -bool gdi_radar_init(struct gdi_radar_context * const ctx) -{ - if (ctx->GameMapWidth == INVALID_MAP_VALUE || - ctx->GameMapHeight == INVALID_MAP_VALUE) - { - std::cout << "Invalid game map dimensions!\n"; - return false; - } - - UnregisterClassW(ctx->className, ctx->wc.hInstance); - ctx->classAtom = RegisterClassW(&ctx->wc); - if (!ctx->classAtom) - { - std::cout << "Register window class failed with 0x" - << std::hex << GetLastError() << "!\n"; - return false; - } - - ctx->myDrawWnd = CreateWindowW(ctx->className, ctx->windowName, - WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_EX_LAYERED | WS_VISIBLE | - WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_MAXIMIZEBOX | WS_SIZEBOX, - 50, 50, 640, 480, - NULL, NULL, ctx->wc.hInstance, ctx); - if (!ctx->myDrawWnd) - { - std::cout << "Create window failed!\n"; - return false; - } - if (!ShowWindow(ctx->myDrawWnd, SW_SHOWNORMAL)) - { - std::cout << "Show window failed!\n"; - } - if (!UpdateWindow(ctx->myDrawWnd)) - { - std::cout << "Update window failed!\n"; - return false; - } - - ctx->lastTimeUpdated = clock(); - return true; -} - -static void gdi_radar_check_entity_bounds(struct gdi_radar_context * const ctx, - struct entity * const ent) -{ - if (ent->pos[0] < 0) - { - ent->pos[0] = 0; - } - if (ent->pos[0] > ctx->GameMapWidth) - { - ent->pos[0] = (int)ctx->GameMapWidth; - } - if (ent->pos[1] < 0) - { - ent->pos[1] = 0; - } - if (ent->pos[1] > ctx->GameMapHeight) - { - ent->pos[1] = (int)ctx->GameMapHeight; - } -} - -void gdi_radar_add_entity(struct gdi_radar_context * const ctx, - struct entity * const ent) -{ - gdi_radar_check_entity_bounds(ctx, ent); - ctx->entities.push_back(*ent); -} - -void gdi_radar_set_entity(struct gdi_radar_context * const ctx, size_t i, - struct entity * const ent) -{ - struct entity& found_ent = ctx->entities.at(i); - gdi_radar_check_entity_bounds(ctx, ent); - found_ent = *ent; -} - -void gdi_radar_clear_entities(struct gdi_radar_context * const ctx) -{ - ctx->entities.clear(); -} - -bool gdi_radar_redraw_if_necessary(struct gdi_radar_context * const ctx) -{ - clock_t end; - double cpu_time_used; - - end = clock(); - cpu_time_used = ((double)(end - ctx->lastTimeUpdated)) / CLOCKS_PER_SEC; - std::cout << "Time past after last update: " << cpu_time_used << std::endl; - - if (cpu_time_used > ctx->minimumUpdateTime) { - if (cpu_time_used > ctx->minimumUpdateTime * ctx->maximumRedrawFails) { - std::cout << "ERROR: Redraw failed for the last " - << ctx->maximumRedrawFails << " times!\n"; - return false; - } - RedrawWindow(ctx->myDrawWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); - } - - return true; -} - -void gdi_radar_set_game_dimensions(struct gdi_radar_context * const ctx, - UINT64 GameMapWidth, UINT64 GameMapHeight, bool StickToBottom) -{ - ctx->GameMapWidth = GameMapWidth; - ctx->GameMapHeight = GameMapHeight; - ctx->drawing.StickToBottom = StickToBottom; -} - -static inline LRESULT -gdi_process_events(struct gdi_radar_context * const ctx, MSG * const msg) -{ - TranslateMessage(msg); - return DispatchMessageW(msg); -} - -LRESULT gdi_radar_process_window_events_blocking(struct gdi_radar_context * const ctx) -{ - LRESULT result = 0; - MSG msg; - while (GetMessageW(&msg, ctx->myDrawWnd, 0, 0)) - { - result = gdi_process_events(ctx, &msg); - } - return result; -} - -LRESULT gdi_radar_process_window_events_nonblocking(struct gdi_radar_context * const ctx) -{ - LRESULT result = 0; - MSG msg; - while (PeekMessageW(&msg, ctx->myDrawWnd, 0, 0, PM_REMOVE)) - { - result = gdi_process_events(ctx, &msg); - } - return result; -} \ No newline at end of file diff --git a/GdiRadar/GdiRadar.h b/GdiRadar/GdiRadar.h deleted file mode 100644 index da5258e..0000000 --- a/GdiRadar/GdiRadar.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include -#include - - -struct gdi_radar_config { - LPCWSTR className; - LPCWSTR windowName; - double minimumUpdateTime; - UINT64 maximumRedrawFails; - size_t reservedEntities; -}; - -struct gdi_radar_context; - - -static HINSTANCE gdi_radar_get_fake_hinstance() -{ - LONG_PTR hi = GetWindowLongW(GetActiveWindow(), -6); - return (HINSTANCE)hi; -} -struct gdi_radar_context * const - gdi_radar_configure(struct gdi_radar_config const * const cfg, - HINSTANCE hInst); -bool gdi_radar_init(struct gdi_radar_context * const ctx); - - -enum entity_color { - EC_RED -}; - -struct entity { - int pos[2]; - float health; - enum entity_color color; - const char *name; -}; - - -void gdi_radar_add_entity(struct gdi_radar_context * const ctx, - struct entity * const ent); -void gdi_radar_set_entity(struct gdi_radar_context * const ctx, size_t i, - struct entity * const ent); -void gdi_radar_clear_entities(struct gdi_radar_context * const ctx); -bool gdi_radar_redraw_if_necessary(struct gdi_radar_context * const ctx); -void gdi_radar_set_game_dimensions(struct gdi_radar_context * const ctx, - UINT64 GameMapWidth, UINT64 GameMapHeight, bool StickToBottom = true); -static void gdi_radar_set_game_dimensions(struct gdi_radar_context * const ctx, - float GameMapWidth, float GameMapHeight, bool StickToBottom = true) -{ - gdi_radar_set_game_dimensions(ctx, - (UINT64)GameMapWidth, (UINT64)GameMapHeight, StickToBottom); -} -LRESULT gdi_radar_process_window_events_blocking(struct gdi_radar_context * const ctx); -LRESULT gdi_radar_process_window_events_nonblocking(struct gdi_radar_context * const ctx); \ No newline at end of file diff --git a/GdiRadar/GdiRadar.vcxproj b/GdiRadar/GdiRadar.vcxproj index caec31e..f1f6c11 100644 --- a/GdiRadar/GdiRadar.vcxproj +++ b/GdiRadar/GdiRadar.vcxproj @@ -22,8 +22,9 @@ 15.0 {C9774084-968A-4F0A-96F7-B5F4E7B254A4} Win32Proj - GdiRadar + GdiRadarTest 10.0.17763.0 + GdiRadarTest @@ -77,12 +78,14 @@ true + $(Platform)\$(Configuration)\$(ProjectName)\ false false + $(Platform)\$(Configuration)\$(ProjectName)\ @@ -109,6 +112,7 @@ true pch.h MultiThreadedDebugDLL + $(SolutionDir)GdiRadarLib;%(AdditionalIncludeDirectories) Console @@ -145,6 +149,7 @@ NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true pch.h + $(SolutionDir)GdiRadarLib;%(AdditionalIncludeDirectories) Console @@ -155,11 +160,9 @@ - - Create @@ -168,6 +171,11 @@ Create + + + {846c5e70-36f1-4790-aad5-7de55345af2e} + + diff --git a/GdiRadar/GdiRadar.vcxproj.filters b/GdiRadar/GdiRadar.vcxproj.filters index c7b0464..a5c08dd 100644 --- a/GdiRadar/GdiRadar.vcxproj.filters +++ b/GdiRadar/GdiRadar.vcxproj.filters @@ -18,9 +18,6 @@ Header Files - - Header Files - @@ -29,8 +26,5 @@ Source Files - - Source Files - \ No newline at end of file diff --git a/GdiRadar/GdiRadarMain.cpp b/GdiRadar/GdiRadarMain.cpp index 3d3fe32..1df2ecb 100644 --- a/GdiRadar/GdiRadarMain.cpp +++ b/GdiRadar/GdiRadarMain.cpp @@ -1,5 +1,5 @@ #include "pch.h" -#include "GdiRadar.h" +#include #include #include diff --git a/GdiRadarLib/GdiRadar.cpp b/GdiRadarLib/GdiRadar.cpp new file mode 100644 index 0000000..c0b5f46 --- /dev/null +++ b/GdiRadarLib/GdiRadar.cpp @@ -0,0 +1,343 @@ +#include "stdafx.h" +#include "GdiRadar.h" + +#include +#include + +#pragma comment(lib, "Gdi32.lib") + +#define INVALID_MAP_VALUE ((UINT64)0) + + +struct gdi_radar_drawing +{ + HBRUSH EnemyBrush; + HPEN DefaultPen; + COLORREF TextCOLOR; + RECT DC_Dimensions; + HDC hdc; + UINT64 GameMapWindowWidth; + UINT64 GameMapWindowHeight; + bool StickToBottom; +}; + +struct gdi_radar_context +{ + PWSTR className; + ATOM classAtom; + PWSTR windowName; + HWND myDrawWnd; + WNDCLASSW wc; + + double minimumUpdateTime; + UINT64 maximumRedrawFails; + clock_t lastTimeUpdated; + UINT64 GameMapWidth; + UINT64 GameMapHeight; + size_t reservedEntities; + + struct gdi_radar_drawing drawing; + std::vector entities; +}; + + +static void draw_entity(struct gdi_radar_context * const ctx, struct entity * const ent) +{ +#if 0 + RECT healthRect = { posx - 10, posy - 10, posx + 10, posy - 5 }; + FillRect(hdc, &rect, color); + + RECT textRect = { posx, posy, posx + 10, posy - 5 }; + DrawText(hdc, TEXT("Michael Morrison"), -1, &rect, + DT_SINGLELINE | DT_CENTER | DT_VCENTER); +#endif + + switch (ent->color) { + case EC_RED: + SelectObject(ctx->drawing.hdc, ctx->drawing.EnemyBrush); + break; + } + + float frealx = ent->pos[0] * ((float)ctx->drawing.GameMapWindowWidth / ctx->GameMapWidth); + float frealy = ent->pos[1] * ((float)ctx->drawing.GameMapWindowHeight / ctx->GameMapHeight); + int realx = (int)frealx; + int realy = (int)frealy; + Ellipse(ctx->drawing.hdc, realx - 5, realy - 5, realx + 5, realy + 5); +} + +static void CalcGameToWindowDimensions(struct gdi_radar_context * const ctx) +{ + float aspectRatio = (float)ctx->GameMapWidth / ctx->GameMapHeight; + if (ctx->drawing.StickToBottom) { + float newWidth = (float)ctx->drawing.DC_Dimensions.bottom / aspectRatio; + ctx->drawing.GameMapWindowHeight = ctx->drawing.DC_Dimensions.bottom - 1; + ctx->drawing.GameMapWindowWidth = (UINT64)newWidth; + } + else { + float newHeight = (float)ctx->drawing.DC_Dimensions.right / aspectRatio; + ctx->drawing.GameMapWindowHeight = (UINT64)newHeight; + ctx->drawing.GameMapWindowWidth = ctx->drawing.DC_Dimensions.right - 1; + } +} + +static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + struct gdi_radar_context * wnd_ctx = NULL; + + if (message == WM_CREATE) { + LONG_PTR pParent = (LONG_PTR)((LPCREATESTRUCTW)lparam)->lpCreateParams; + SetWindowLongPtrW(hwnd, -21, pParent); + wnd_ctx = (struct gdi_radar_context *)pParent; + } + else { + wnd_ctx = (struct gdi_radar_context *)GetWindowLongPtrW(hwnd, -21); + } + + if (!wnd_ctx) + { + std::cout << "WndProc: ctx NULL!\n"; + return DefWindowProc(hwnd, message, wparam, lparam); + } + + struct gdi_radar_drawing * const drawing = &wnd_ctx->drawing; + if (!drawing) + { + std::cout << "WndProc: drawing NULL!\n"; + return DefWindowProc(hwnd, message, wparam, lparam); + } + + switch (message) + { + case WM_CREATE: + std::cout << "WM_CREATE\n"; + drawing->hdc = GetDC(hwnd); + drawing->EnemyBrush = CreateSolidBrush(RGB(255, 0, 0)); + drawing->DefaultPen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0)); + drawing->TextCOLOR = RGB(0, 255, 0); + SetBkMode(drawing->hdc, TRANSPARENT); + return 0; + case WM_DESTROY: + std::cout << "WM_DESTROY\n"; + DeleteObject(drawing->EnemyBrush); + DeleteObject(drawing->DefaultPen); + DeleteDC(drawing->hdc); + PostQuitMessage(0); + return 0; + + case WM_PAINT: + { + std::cout << "WM_PAINT\n"; + PAINTSTRUCT ps; + + BeginPaint(hwnd, &ps); + + SelectObject(drawing->hdc, drawing->DefaultPen); + POINT lines[] = { { 0,0 }, { (LONG)drawing->GameMapWindowWidth, 0 }, + { (LONG)drawing->GameMapWindowWidth, (LONG)drawing->GameMapWindowHeight }, + { 0, (LONG)drawing->GameMapWindowHeight }, { 0,0 } }; + Polyline(drawing->hdc, lines, 5); + for (auto& entity : wnd_ctx->entities) { + draw_entity(wnd_ctx, &entity); + } + EndPaint(hwnd, &ps); + + wnd_ctx->lastTimeUpdated = clock(); + break; + } + + case WM_LBUTTONDOWN: + std::cout << "WM_LBUTTONDOWN\n"; + break; + case WM_NCLBUTTONDOWN: + std::cout << "WM_NCLBUTTONDOWN\n"; + break; + case WM_CHAR: + std::cout << "WM_CHAR\n"; + break; + case WM_MOVE: + std::cout << "WM_MOVE\n"; + break; + case WM_SIZE: + std::cout << "WM_SIZE\n"; + GetClientRect(hwnd, &drawing->DC_Dimensions); + CalcGameToWindowDimensions(wnd_ctx); + break; + } + + //std::cout << "Default window proc for message 0x" << std::hex << message << std::endl; + return DefWindowProcW(hwnd, message, wparam, lparam); +} + +struct gdi_radar_context * const + gdi_radar_configure(struct gdi_radar_config const * const cfg, + HINSTANCE hInst) +{ + struct gdi_radar_context * result = new gdi_radar_context; + if (!result) + { + return NULL; + } + ZeroMemory(result, sizeof(*result)); + + /* config params */ + result->className = _wcsdup(cfg->className); + result->windowName = _wcsdup(cfg->windowName); + result->minimumUpdateTime = cfg->minimumUpdateTime; + result->maximumRedrawFails = cfg->maximumRedrawFails; + result->reservedEntities = cfg->reservedEntities; + result->entities.reserve(result->reservedEntities); + + /* other */ + result->wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); + result->wc.hCursor = LoadCursor(hInst, IDC_ARROW); + result->wc.hIcon = LoadIcon(hInst, IDI_APPLICATION); + result->wc.hInstance = hInst; + result->wc.lpfnWndProc = WndProc; + result->wc.lpszClassName = result->className; + result->wc.style = CS_HREDRAW | CS_VREDRAW; + result->GameMapWidth = INVALID_MAP_VALUE; + result->GameMapHeight = INVALID_MAP_VALUE; + + return result; +} + +bool gdi_radar_init(struct gdi_radar_context * const ctx) +{ + if (ctx->GameMapWidth == INVALID_MAP_VALUE || + ctx->GameMapHeight == INVALID_MAP_VALUE) + { + std::cout << "Invalid game map dimensions!\n"; + return false; + } + + UnregisterClassW(ctx->className, ctx->wc.hInstance); + ctx->classAtom = RegisterClassW(&ctx->wc); + if (!ctx->classAtom) + { + std::cout << "Register window class failed with 0x" + << std::hex << GetLastError() << "!\n"; + return false; + } + + ctx->myDrawWnd = CreateWindowW(ctx->className, ctx->windowName, + WS_OVERLAPPEDWINDOW | WS_THICKFRAME | WS_EX_LAYERED | WS_VISIBLE | + WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_MAXIMIZEBOX | WS_SIZEBOX, + 50, 50, 640, 480, + NULL, NULL, ctx->wc.hInstance, ctx); + if (!ctx->myDrawWnd) + { + std::cout << "Create window failed!\n"; + return false; + } + if (!ShowWindow(ctx->myDrawWnd, SW_SHOWNORMAL)) + { + std::cout << "Show window failed!\n"; + } + if (!UpdateWindow(ctx->myDrawWnd)) + { + std::cout << "Update window failed!\n"; + return false; + } + + ctx->lastTimeUpdated = clock(); + return true; +} + +static void gdi_radar_check_entity_bounds(struct gdi_radar_context * const ctx, + struct entity * const ent) +{ + if (ent->pos[0] < 0) + { + ent->pos[0] = 0; + } + if (ent->pos[0] > ctx->GameMapWidth) + { + ent->pos[0] = (int)ctx->GameMapWidth; + } + if (ent->pos[1] < 0) + { + ent->pos[1] = 0; + } + if (ent->pos[1] > ctx->GameMapHeight) + { + ent->pos[1] = (int)ctx->GameMapHeight; + } +} + +void gdi_radar_add_entity(struct gdi_radar_context * const ctx, + struct entity * const ent) +{ + gdi_radar_check_entity_bounds(ctx, ent); + ctx->entities.push_back(*ent); +} + +void gdi_radar_set_entity(struct gdi_radar_context * const ctx, size_t i, + struct entity * const ent) +{ + struct entity& found_ent = ctx->entities.at(i); + gdi_radar_check_entity_bounds(ctx, ent); + found_ent = *ent; +} + +void gdi_radar_clear_entities(struct gdi_radar_context * const ctx) +{ + ctx->entities.clear(); +} + +bool gdi_radar_redraw_if_necessary(struct gdi_radar_context * const ctx) +{ + clock_t end; + double cpu_time_used; + + end = clock(); + cpu_time_used = ((double)(end - ctx->lastTimeUpdated)) / CLOCKS_PER_SEC; + std::cout << "Time past after last update: " << cpu_time_used << std::endl; + + if (cpu_time_used > ctx->minimumUpdateTime) { + if (cpu_time_used > ctx->minimumUpdateTime * ctx->maximumRedrawFails) { + std::cout << "ERROR: Redraw failed for the last " + << ctx->maximumRedrawFails << " times!\n"; + return false; + } + RedrawWindow(ctx->myDrawWnd, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN); + } + + return true; +} + +void gdi_radar_set_game_dimensions(struct gdi_radar_context * const ctx, + UINT64 GameMapWidth, UINT64 GameMapHeight, bool StickToBottom) +{ + ctx->GameMapWidth = GameMapWidth; + ctx->GameMapHeight = GameMapHeight; + ctx->drawing.StickToBottom = StickToBottom; +} + +static inline LRESULT +gdi_process_events(struct gdi_radar_context * const ctx, MSG * const msg) +{ + TranslateMessage(msg); + return DispatchMessageW(msg); +} + +LRESULT gdi_radar_process_window_events_blocking(struct gdi_radar_context * const ctx) +{ + LRESULT result = 0; + MSG msg; + while (GetMessageW(&msg, ctx->myDrawWnd, 0, 0)) + { + result = gdi_process_events(ctx, &msg); + } + return result; +} + +LRESULT gdi_radar_process_window_events_nonblocking(struct gdi_radar_context * const ctx) +{ + LRESULT result = 0; + MSG msg; + while (PeekMessageW(&msg, ctx->myDrawWnd, 0, 0, PM_REMOVE)) + { + result = gdi_process_events(ctx, &msg); + } + return result; +} \ No newline at end of file diff --git a/GdiRadarLib/GdiRadar.h b/GdiRadarLib/GdiRadar.h new file mode 100644 index 0000000..da5258e --- /dev/null +++ b/GdiRadarLib/GdiRadar.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + + +struct gdi_radar_config { + LPCWSTR className; + LPCWSTR windowName; + double minimumUpdateTime; + UINT64 maximumRedrawFails; + size_t reservedEntities; +}; + +struct gdi_radar_context; + + +static HINSTANCE gdi_radar_get_fake_hinstance() +{ + LONG_PTR hi = GetWindowLongW(GetActiveWindow(), -6); + return (HINSTANCE)hi; +} +struct gdi_radar_context * const + gdi_radar_configure(struct gdi_radar_config const * const cfg, + HINSTANCE hInst); +bool gdi_radar_init(struct gdi_radar_context * const ctx); + + +enum entity_color { + EC_RED +}; + +struct entity { + int pos[2]; + float health; + enum entity_color color; + const char *name; +}; + + +void gdi_radar_add_entity(struct gdi_radar_context * const ctx, + struct entity * const ent); +void gdi_radar_set_entity(struct gdi_radar_context * const ctx, size_t i, + struct entity * const ent); +void gdi_radar_clear_entities(struct gdi_radar_context * const ctx); +bool gdi_radar_redraw_if_necessary(struct gdi_radar_context * const ctx); +void gdi_radar_set_game_dimensions(struct gdi_radar_context * const ctx, + UINT64 GameMapWidth, UINT64 GameMapHeight, bool StickToBottom = true); +static void gdi_radar_set_game_dimensions(struct gdi_radar_context * const ctx, + float GameMapWidth, float GameMapHeight, bool StickToBottom = true) +{ + gdi_radar_set_game_dimensions(ctx, + (UINT64)GameMapWidth, (UINT64)GameMapHeight, StickToBottom); +} +LRESULT gdi_radar_process_window_events_blocking(struct gdi_radar_context * const ctx); +LRESULT gdi_radar_process_window_events_nonblocking(struct gdi_radar_context * const ctx); \ No newline at end of file diff --git a/GdiRadarLib/GdiRadarLib.vcxproj b/GdiRadarLib/GdiRadarLib.vcxproj new file mode 100644 index 0000000..54330f2 --- /dev/null +++ b/GdiRadarLib/GdiRadarLib.vcxproj @@ -0,0 +1,168 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {846C5E70-36F1-4790-AAD5-7DE55345AF2E} + Win32Proj + GdiRadarLib + 10.0.17763.0 + + + + StaticLibrary + true + v141 + Unicode + + + StaticLibrary + false + v141 + true + Unicode + + + StaticLibrary + true + v141 + Unicode + false + + + StaticLibrary + false + v141 + true + Unicode + false + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + true + _DEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + Use + Level3 + Disabled + true + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + + + + + Use + Level3 + MaxSpeed + true + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + NDEBUG;_LIB;%(PreprocessorDefinitions) + true + + + Windows + true + true + true + + + + + + + + + + + Create + Create + Create + Create + + + + + + \ No newline at end of file diff --git a/GdiRadarLib/GdiRadarLib.vcxproj.filters b/GdiRadarLib/GdiRadarLib.vcxproj.filters new file mode 100644 index 0000000..0f35b1c --- /dev/null +++ b/GdiRadarLib/GdiRadarLib.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/GdiRadarLib/stdafx.cpp b/GdiRadarLib/stdafx.cpp new file mode 100644 index 0000000..fd4f341 --- /dev/null +++ b/GdiRadarLib/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/GdiRadarLib/stdafx.h b/GdiRadarLib/stdafx.h new file mode 100644 index 0000000..69f8872 --- /dev/null +++ b/GdiRadarLib/stdafx.h @@ -0,0 +1,14 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + + + +// reference additional headers your program requires here diff --git a/GdiRadarLib/targetver.h b/GdiRadarLib/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/GdiRadarLib/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include -- cgit v1.2.3