diff --git a/CMakeLists.txt b/CMakeLists.txt index 5042649..2abe16a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,8 @@ add_executable(${PROJECT_NAME} main.cpp def.cpp TestCode.h TextureManager.cpp - TextureManager.h) + TextureManager.h + exception.cpp) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) include(CPack) diff --git a/Chars.h b/Chars.h index bbe6ae2..d0b68b7 100644 --- a/Chars.h +++ b/Chars.h @@ -15,10 +15,10 @@ ret += *string - L'0'; } else if (*string >= L'A' && *string <= L'F') { ret <<= 4; - ret += *string - 0x41; // L'A' - 10 + ret += *string - 0x41;// 'A' - 10 } else if (*string >= L'a' && *string <= L'f') { ret <<= 4; - ret += *string - 0x61; // L'a' - 10 + ret += *string - 0x61;// 'a' - 10 } else return 0xffffffff; ++string; } @@ -35,16 +35,17 @@ ret += string[i] - L'0'; } else if (string[i] >= L'A' && string[i] <= L'F') { ret <<= 4; - ret += string[i] - 0x41; // L'A' - 10 + ret += string[i] - 0x41;// L'A' - 10 } else if (string[i] >= L'a' && string[i] <= L'f') { ret <<= 4; - ret += string[i] - 0x61; // L'a' - 10 + ret += string[i] - 0x61;// L'a' - 10 } else return 0xffffffff; ++i; } return ret; } +static constexpr wchar Table16[17] = L"0123456789ABCDEF"; /** * 将数字转换为字符串 * @param value 要转换的数字 @@ -52,20 +53,56 @@ * @return String类型 */ [[nodiscard]] inline String uitowb16(unsigned int value, const unsigned int fills = 1) noexcept { - static constexpr const wchar* const table = L"0123456789ABCDEF"; String ret; if (value < static_cast(1) << fills - 1) { ret.assign(fills, L'0'); - for (unsigned int i = fills - 1; i != 0; --i) { - ret[i] = table[value & 0xf]; + for (unsigned int i = fills - 1; i != 0 && value; --i) { + ret[i] = Table16[value & 0xf]; value >>= 4; } - } - else { - while (value) { - ret.push_back(table[value & 0xf]); - value >>= 4; + } else { + unsigned int i = 0; + while (i < 8) { + if ((value >> i) & 0xf) break; + ++i; } + while (i < 8) { + ret.push_back(Table16[(value >> i) & 0xf]); + ++i; + } + if (ret.empty()) ret = L"0"; + } + return ret; +} + +static constexpr wchar Table10[11] = L"0123456789"; +static constexpr QWORD Compare10[20] = { + 0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + 100000000, 1000000000, 10000000000, 100000000000, + 1000000000000, 10000000000000, 100000000000000, + 1000000000000000, 10000000000000000, 100000000000000000, + 1000000000000000000, 10000000000000000000 +}; +[[nodiscard]] inline String qwtowb10(QWORD value, const unsigned int fills = 1) noexcept { + String ret; + if (value < Compare10[fills]) { + ret.assign(fills, L'0'); + for (unsigned int i = fills - 1; i != 0 && value; --i) { + ret[i] = Table10[value % 10]; + value /= 10; + } + } else { + unsigned int i = 0; + while (i < 19) { + if (value >= Compare10[i]) break; + ++i; + } + while (i < 19) { + ret.push_back(Table10[value / Compare10[i]]); + value %= Compare10[i]; + ++i; + } + if (ret.empty()) ret = L"0"; } return ret; } diff --git a/Game.cpp b/Game.cpp index 5351045..2e116f4 100644 --- a/Game.cpp +++ b/Game.cpp @@ -4,5 +4,11 @@ #include "Game.h" + void Game::initialize() noexcept { renderer.setGame(game); } +Game::Game() : floatWindow{ new FloatWindow() } { Logger.put(L"Game created"); } + +Game::~Game() { delete floatWindow; } + +inline Game game = Game(); diff --git a/Game.h b/Game.h index 8a9597c..6dd6848 100644 --- a/Game.h +++ b/Game.h @@ -8,15 +8,22 @@ #include "Window.h" class Game : public IRenderable { + friend void gameThread(); Hud hud = Hud(); Window* window = nullptr; - + FloatWindow* floatWindow; + QWORD currentTick = 0; public: - explicit Game() = default; + explicit Game(); + ~Game() override; static void initialize() noexcept; + void render() const noexcept override { - if (window) window->render(); + renderer.gameStartRender(); hud.render(); + if (window) window->render(); + if (floatWindow) floatWindow->render(); + renderer.gameEndRender(); } int setWindow(Window* window) noexcept { @@ -31,6 +38,14 @@ public: } [[nodiscard]] Window* getWindow() const noexcept { return window; } + [[nodiscard]] QWORD getTick() const noexcept { return currentTick; } + + void tick() noexcept { + ++currentTick; + hud.tick(); + if (window) window->tick(); + if (floatWindow) floatWindow->tick(); + } }; -inline static Game game = Game(); +extern Game game; diff --git a/Hud.cpp b/Hud.cpp index 7a0a998..bc030c0 100644 --- a/Hud.cpp +++ b/Hud.cpp @@ -5,3 +5,4 @@ #include "Hud.h" void Hud::render() const noexcept {} +void Hud::tick() noexcept {} diff --git a/Hud.h b/Hud.h index c017942..8b97a71 100644 --- a/Hud.h +++ b/Hud.h @@ -5,8 +5,9 @@ #pragma once #include "Renderer.h" -class Hud : public IRenderable { +class Hud final : public IRenderable, public ITickable { public: void render() const noexcept override; + void tick() noexcept override; }; diff --git a/InteractManager.h b/InteractManager.h index b314e1b..b2567b0 100644 --- a/InteractManager.h +++ b/InteractManager.h @@ -21,7 +21,25 @@ struct KeyStatus { pressTimes = 0; } - [[nodiscard]] String toString() const noexcept { return L"KeyStatus: { name = \"" + name + L"\"; pressTimes = " + std::to_wstring(pressTimes) + L"; pressed = " + (pressed ? L"true }" : L"false }"); } + [[nodiscard]] String toString() const noexcept { return L"KeyStatus: { name = \"" + name + L"\"; pressTimes = " + std::to_wstring(pressTimes) + L"; pressed = " + (pressed ? L"true; }" : L"false; }"); } +}; + +struct MouseStatus { + String name; + unsigned int pressTimes = 0; + bool pressed = false; + bool notDealt = false; + bool longHold = false; + + [[nodiscard]] bool isPressed() const noexcept { return pressed; } + [[nodiscard]] unsigned int wasPressed() const noexcept { return pressTimes; } + + void deals() noexcept { + notDealt = false; + pressTimes = 0; + } + + [[nodiscard]] String toString() const noexcept { return L"MouseStatus: { name = \""+ name + L"\"; pressTimes = " + std::to_wstring(pressTimes) + L"; pressed = " + (pressed ? L"true, longHold = " : L"false, longHold = ") + (longHold ? L"true; }" : L"false; }") ; } }; struct KeyBinding; diff --git a/Renderer.cpp b/Renderer.cpp index dd2f996..9ff466f 100644 --- a/Renderer.cpp +++ b/Renderer.cpp @@ -7,7 +7,10 @@ #include "Game.h" #include "hbp.h" -void Renderer::initialize() noexcept { MainDC = GetDC(MainWindowHandle); } +void Renderer::initialize() noexcept { + MainDC = GetDC(MainWindowHandle); + assistDC = CreateCompatibleDC(MainDC); +} void Renderer::resize(const int width, const int height) noexcept(false) { windowWidth = width; @@ -19,3 +22,5 @@ void Renderer::resize(const int width, const int height) noexcept(false) { } if (game.getWindow()) game.getWindow()->onResize(); } + +inline Renderer renderer = Renderer(); diff --git a/Renderer.h b/Renderer.h index 04f3054..43bdfff 100644 --- a/Renderer.h +++ b/Renderer.h @@ -4,7 +4,10 @@ #pragma once +#include + #include "def.h" +#include "exception.h" class Game; /** @@ -22,18 +25,50 @@ interface ITickable { virtual void tick() noexcept = 0; }; -class Renderer : public ITickable { +struct Color { + unsigned int inactive = 0xff777777; + unsigned int active = 0xff000000; + unsigned int hover = 0xff444444; + unsigned int clicked = 0xffeeeeee; +}; + +inline static constexpr Color TextColor = { + .inactive = 0xff333333, + .active = 0xffeeeeee, + .hover = 0xffeeeeee, + .clicked = 0xff000000 +}; + +class Renderer final : public ITickable { /** * 后续可能用不到,可能可删 */ Game* pGame = nullptr; + + friend class Game; inline static HDC MainDC; + inline static HDC assistDC; + inline static BLENDFUNCTION blendFunction = { + .BlendOp = AC_SRC_OVER,// Only + .BlendFlags = 0,// Must 0 + .SourceConstantAlpha = 255,// 预乘 + .AlphaFormat = AC_SRC_ALPHA,// Only + }; + std::thread::id renderThread = std::this_thread::get_id(); int windowWidth = 0, windowHeight = 0; int resizeTime = 0; + bool isRendering = false; + + void gameStartRender() noexcept { + isRendering = true; + renderThread = std::this_thread::get_id(); + } + + void gameEndRender() noexcept { isRendering = false; } public: static void initialize() noexcept; - explicit Renderer() = default; + explicit Renderer() { Logger.put(L"Renderer created"); } void resize(int width, int height) noexcept(false); void setGame(Game& game) noexcept { pGame = &game; } [[nodiscard]] int getWidth() const noexcept { return windowWidth; } @@ -47,6 +82,36 @@ public: resizeTime = -1; } } + + /** + * @attention 会忽略A透明度值 + * @param argb ARGB式颜色 + * @return int BGR式颜色 + */ + [[nodiscard]] static unsigned int changeColorFormat(const unsigned int argb) { return (argb & 0xff) << 16 | (argb & 0xff00) | (argb & 0xff0000) >> 16; } + + void assertRendering() const noexcept(false) { if (!isRendering) throw InvalidOperationException(L"Operation should be done while rendering"); } + + void assertRenderThread() const noexcept(false) { if (std::this_thread::get_id() != renderThread) throw InvalidOperationException(L"Operation should be done in render thread"); } + + void fill(const int x, const int y, const int w, const int h, const unsigned int color) const { + assertRendering(); + //assertRenderThread(); + if (color & 0xff000000 == 0) return; + const RECT rect{ + .left = x, + .top = y, + .right = x + w, + .bottom = y + h + }; + HBRUSH clr = CreateSolidBrush(changeColorFormat(color)); + if ((color & 0xff000000) == 0xff000000) FillRect(MainDC, &rect, clr); + else { + FillRect(assistDC, &rect, clr); + AlphaBlend(MainDC, x, y, w, h, assistDC, x, y, w, h, blendFunction); + } + DeleteObject(clr); + } }; -inline static Renderer renderer = Renderer(); +extern Renderer renderer; diff --git a/TestCode.h b/TestCode.h index 0009536..ede3af6 100644 --- a/TestCode.h +++ b/TestCode.h @@ -4,21 +4,5 @@ #pragma once -struct B { - int a = 1; - B() { std::wcout << L"common constructor\n"; } - B(B&) { std::wcout << L"copy constructor\n"; } - // B(B&& other) noexcept { std::wcout << L"move constructor\n"; } -}; - -struct A { - B b; - - explicit A(B&& other) : b(other) {} -}; - inline void test() { - B b; - A a{ B() }; - a = A(std::move(a.b)); } diff --git a/TextureManager.h b/TextureManager.h index 8ab76ba..bff6638 100644 --- a/TextureManager.h +++ b/TextureManager.h @@ -62,19 +62,21 @@ class TextureManager { Font* defaultFont = nullptr; using IterFont = Map::const_iterator; using IterTexture = Map>::const_iterator; + public: TextureManager() { try { fonts.insert(std::make_pair(0, Font(L"Arial"))); defaultFont = &fonts.at(0); - } - catch (...) { + } catch (const std::out_of_range& e) { - } + } catch (const ArrayIndexOutOfBoundException& e){} } - Font& getFont(const int id) const noexcept { + + const Font& getFont(const int id) const noexcept { IterFont iterator = fonts.find(id); - if (iterator == fonts.cend()) return + if (iterator == fonts.cend()) return *defaultFont; + return iterator->second; } }; diff --git a/Window.cpp b/Window.cpp index 8d38040..3a555b0 100644 --- a/Window.cpp +++ b/Window.cpp @@ -3,3 +3,11 @@ // #include "Window.h" +void Window::render() const noexcept {} +void Window::tick() noexcept {} +void Window::onResize() {} +void FloatWindow::render() const noexcept { + renderer.fill(20, 20, 40, 40, 0xffeeeeee); +} + +void Button::render() const noexcept {} diff --git a/Window.h b/Window.h index 367eea6..1f38036 100644 --- a/Window.h +++ b/Window.h @@ -12,13 +12,11 @@ enum class MouseActionCode : char { MAC_MOVE, MAC_HOVER, MAC_DOWN, MAC_UP, MAC_DOUBLE }; -class Widget : public IRenderable { +class Widget : public IRenderable, public ITickable { protected: int left = 0, top = 0, width = 0, height = 0; - mutable bool hasMouse = false; public: - Location location; using Action = Function; double x, y, w, h; Action hover;// 传入int忽略 @@ -27,8 +25,24 @@ public: Action mouseUp;// 传入int表示变更按键。0左, 1中, 2右 Action mouseLeave;// 传入int忽略 Action mouseClick;// 传入int表示变更按键。0x0左, 0x1中, 0x2右;0xf表示是否双击 + Color backgroundColor; + Color foregroundColor; + +protected: + mutable bool hasMouse = false; + +public: + Location location; + +protected: + char unused[6] {}; + +public: + unsigned int colorSelector(const Color& clr, const Widget& widget) const { + return hasMouse ? clr.hover : clr.inactive; + } + explicit Widget(const double x, const double y, const double w, const double h, Location location) : x(x), y(y), w(w), h(h), location(location) {} - void render() const noexcept override {} virtual void onResize() {} virtual bool isMouseIn(int x, int y) noexcept { @@ -44,7 +58,7 @@ public: virtual void onMouseLeave(const int value) noexcept { if (mouseLeave) mouseLeave(value); } virtual void onMouseClick(const int value) noexcept { if (mouseClick) mouseClick(value); } - virtual void passEvent(int action, int value, int x, int y) noexcept { + virtual void passEvent(const int action, const int value, const int x, const int y) noexcept { if (!isMouseIn(x, y)) { if (hasMouse) onMouseLeave(0); hasMouse = false; @@ -72,7 +86,7 @@ public: } }; -class Window : public IRenderable { +class Window : public IRenderable, public ITickable { protected: List widgets; @@ -81,6 +95,8 @@ protected: ~Window() override { for (Widget*& widget : widgets) { delete widget; } } public: + void render() const noexcept override; + void tick() noexcept override; /** * 在Game.setWindow()时,本窗口开启时调用。 * 不应当外部调用。 @@ -104,8 +120,10 @@ public: void onClose() override {} }; -class Button final : public Widget { +class Button : public Widget { public: ObjectHolder name; - explicit Button(const double x, const double y, const double w, const double h, Location location, ObjectHolder text) : Widget(x, y, w, h, location), name(text) {} + explicit Button(const double x, const double y, const double w, const double h, const Location location, const ObjectHolder& text) : Widget(x, y, w, h, location), name(text) {} + void render() const noexcept override; + void tick() noexcept override {} }; diff --git a/def.h b/def.h index 2501274..c519fd7 100644 --- a/def.h +++ b/def.h @@ -10,10 +10,12 @@ #include #include #include +#include using wchar = wchar_t; using QWORD = unsigned long long int; using String = std::wstring; +using Thread = std::thread; template, typename Alloc = std::allocator>> using Map = std::map; template> using List = std::list; template using Function = std::function; @@ -48,6 +50,7 @@ template using Function = std::function; #include #include +#pragma comment(lib, "Msimg32.lib") #pragma comment(lib, "ws2_32.lib") #pragma comment(lib, "dwmapi.lib") #pragma comment(lib, "Uxtheme.lib") diff --git a/exception.cpp b/exception.cpp new file mode 100644 index 0000000..fe36747 --- /dev/null +++ b/exception.cpp @@ -0,0 +1,71 @@ +// +// Created by EmsiaetKadosh on 25-1-22. +// + +#pragma once + +#include "def.h" +#include "exception.h" +#include "Game.h" + +ILogger& PublicLogger::trace(const String& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Trace] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::trace(String&& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Trace] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::debug(const String& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Debug] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::debug(String&& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Debug] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::log(const String& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Log] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::log(String&& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Log] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::info(const String& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Info] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::info(String&& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Info] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::warn(const String& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Warn] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::warn(String&& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Warn] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::error(const String& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Error] " + msg + L"\n"; + return *this; +} + +ILogger& PublicLogger::error(String&& msg) noexcept { + std::wcout << L"T-" + qwtowb10(game.getTick(), 8) + L" [Error] " + msg + L"\n"; + return *this; +} + +inline PublicLogger Logger{}; diff --git a/exception.h b/exception.h index 2653726..82c68c6 100644 --- a/exception.h +++ b/exception.h @@ -16,7 +16,7 @@ protected: public: [[nodiscard]] String getMessage() const noexcept { return msg; } [[nodiscard]] const String* getType() const noexcept { return type; } - [[nodiscard]] const char* what() const override { return "Use Exception::getMessage() instead.";} + [[nodiscard]] const char* what() const override { return "Use Exception::getMessage() instead."; } }; class NullPointerException final : public Exception { @@ -34,3 +34,57 @@ public: explicit ArrayIndexOutOfBoundException(String&& msg) : Exception(std::move(msg), &type) {} explicit ArrayIndexOutOfBoundException(const String& msg) : Exception(msg, &type) {} }; + +class InvalidOperationException final : public Exception { + inline static const String type = L"InvalidOperationException"; + +public: + explicit InvalidOperationException(String&& msg) : Exception(std::move(msg), &type) {} + explicit InvalidOperationException(const String& msg) : Exception(msg, &type) {} +}; + +interface ILogger { + virtual ~ILogger() = default; + virtual ILogger& trace(const String&) noexcept = 0; + virtual ILogger& trace(String&&) noexcept = 0; + virtual ILogger& debug(const String&) noexcept = 0; + virtual ILogger& debug(String&&) noexcept = 0; + virtual ILogger& log(const String&) noexcept = 0; + virtual ILogger& log(String&&) noexcept = 0; + virtual ILogger& info(const String&) noexcept = 0; + virtual ILogger& info(String&&) noexcept = 0; + virtual ILogger& warn(const String&) noexcept = 0; + virtual ILogger& warn(String&&) noexcept = 0; + virtual ILogger& error(const String&) noexcept = 0; + virtual ILogger& error(String&&) noexcept = 0; +}; + +struct PublicLogger final : ILogger { + PublicLogger() { std::wcout << L"PublicLogger created\n"; } + + PublicLogger& put(const String& msg) noexcept { + std::wcout << L"[] [Root] " + msg + L"\n"; + return * this; + } + + PublicLogger& put(String&& msg) noexcept { + std::wcout << L"[] [Root] " + msg + L"\n"; + return *this; + } + + ILogger& trace(const String&) noexcept override; + ILogger& trace(String&&) noexcept override; + ILogger& debug(const String&) noexcept override; + ILogger& debug(String&&) noexcept override; + ILogger& log(const String&) noexcept override; + ILogger& log(String&&) noexcept override; + ILogger& info(const String&) noexcept override; + ILogger& info(String&&) noexcept override; + ILogger& warn(const String&) noexcept override; + ILogger& warn(String&&) noexcept override; + ILogger& error(const String&) noexcept override; + ILogger& error(String&&) noexcept override; +}; + +extern PublicLogger Logger; + diff --git a/hbp.h b/hbp.h index 8d21ccb..20124e0 100644 --- a/hbp.h +++ b/hbp.h @@ -14,14 +14,18 @@ inline BOOL NewProcess(const String& cmdline) noexcept { inline HRESULT RemoveDefaultCaption(HWND hWnd, const MARGINS* p) noexcept { return DwmExtendFrameIntoClientArea(hWnd, p); } -inline void ShowConsoleIO() noexcept { +inline bool ShowConsoleIO() noexcept { AllocConsole(); FILE* pCout; freopen_s(&pCout, "CONOUT$", "w", stdout); FILE* pCin; freopen_s(&pCin, "CONIN$", "r", stdin); + return true; } inline const String ApplicationName = L"Hyblud Presher"; inline HINSTANCE MainInstance; inline HWND MainWindowHandle; +inline Thread GameThread; +inline Thread RenderThread; +inline static bool isRunning = ShowConsoleIO(); diff --git a/includes.h b/includes.h index 0f86135..ba46918 100644 --- a/includes.h +++ b/includes.h @@ -7,9 +7,11 @@ #include "def.h" #include "exception.h" #include "hbp.h" +#include "Chars.h" #include "Renderer.h" #include "InteractManager.h" #include "TextureManager.h" +#include "IText.h" #include "Hud.h" #include "Window.h" diff --git a/main.cpp b/main.cpp index 4d16224..67b403e 100644 --- a/main.cpp +++ b/main.cpp @@ -26,7 +26,7 @@ LRESULT __stdcall WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if (renderer.getWidth() - xPos < 30) { if (yPos < 30) return HTTOPRIGHT; if (renderer.getHeight() - yPos < 30) return HTBOTTOMRIGHT; - return HTBOTTOM; + return HTRIGHT; } if (yPos < 30) return HTTOP; if (renderer.getHeight() - yPos < 30) return HTBOTTOM; @@ -128,6 +128,7 @@ LRESULT __stdcall WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { _UNLIKELY case WM_DESTROY: PostQuitMessage(0); + isRunning = false; return 0; _UNLIKELY case WM_CREATE: @@ -139,8 +140,39 @@ LRESULT __stdcall WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hwnd, uMsg, wParam, lParam); } +void gameThread() { + using namespace std::chrono; + using Time = time_point; + Time lastTick = system_clock::now(); + Time thisTime; + while (isRunning) { + thisTime = system_clock::now(); + if (thisTime - lastTick < milliseconds(45)) { + Sleep(1); + continue; + } + game.tick(); + lastTick = thisTime; + } +} + +void renderThread() { + using namespace std::chrono; + using Time = time_point; + Time lastRender = system_clock::now(); + Time thisTime; + while (isRunning) { + thisTime = system_clock::now(); + if (thisTime - lastRender < milliseconds(12)) { + Sleep(1); + continue; + } + game.render(); + lastRender = thisTime; + } +} + int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { - ShowConsoleIO(); WNDCLASSEX wc = {}; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; @@ -175,6 +207,8 @@ int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCm } HACCEL hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCE(109)); MSG msg = { nullptr }; + GameThread = Thread(gameThread); + RenderThread = Thread(renderThread); while (GetMessageW(&msg, nullptr, 0, 0)) { if (!TranslateAcceleratorW(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); @@ -182,5 +216,8 @@ int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCm } } DestroyAcceleratorTable(hAccelTable); + if (GameThread.joinable()) GameThread.join(); + if (RenderThread.joinable()) RenderThread.join(); + _wsystem(L"pause"); return (int) msg.wParam; }