From ec13bca129fd00f6abfba1983b2b5012926825e3 Mon Sep 17 00:00:00 2001 From: Muzychenko Andrey <33288308+k4zmu2a@users.noreply.github.com> Date: Thu, 11 Nov 2021 18:03:23 +0300 Subject: [PATCH] Stabilized main loop. Cherry picked timeBeginPeriod. Ref PR #85. --- SpaceCadetPinball/pb.cpp | 6 +- SpaceCadetPinball/pb.h | 2 +- SpaceCadetPinball/winmain.cpp | 110 +++++++++++++++++----------------- SpaceCadetPinball/winmain.h | 5 +- 4 files changed, 64 insertions(+), 59 deletions(-) diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index 4f0b2e1..1c74b16 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -225,12 +225,15 @@ void pb::ballset(int x, int y) ball->Speed = maths::normalize_2d(&ball->Acceleration); } -int pb::frame(int time) +void pb::frame(int time) { static int frameTime = 0; if (time > 100) time = 100; + if (time <= 0) + return; + float timeMul = time * 0.001f; if (!mode_countdown(time)) { @@ -284,7 +287,6 @@ int pb::frame(int time) MainTable->tilt(time_now); } } - return 1; } void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls) diff --git a/SpaceCadetPinball/pb.h b/SpaceCadetPinball/pb.h index 97106e6..e8625bc 100644 --- a/SpaceCadetPinball/pb.h +++ b/SpaceCadetPinball/pb.h @@ -26,7 +26,7 @@ public: static void toggle_demo(); static void replay_level(int demoMode); static void ballset(int x, int y); - static int frame(int time); + static void frame(int time); static void timed_frame(float timeNow, float timeDelta, bool drawBalls); static void window_size(int* width, int* height); static void pause_continue(); diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 138a3c6..3d2aec2 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -12,6 +12,8 @@ #include "splash.h" #include "render.h" +const int TargetFrameTime = 8; + HINSTANCE winmain::hinst = nullptr; HWND winmain::hwnd_frame = nullptr; HCURSOR winmain::mouse_hsave; @@ -28,8 +30,6 @@ int winmain::last_mouse_y; int winmain::mouse_down; int winmain::no_time_loss; -DWORD winmain::then; -DWORD winmain::now; UINT winmain::iFrostUniqueMsg; bool winmain::restart = false; @@ -51,6 +51,10 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi options::ReadOptions(); auto regSpaceCadet = pinball::get_rc_string(166, 0); + // Needed for sub 16ms sleep + if (timeBeginPeriod(1) == TIMERR_NOERROR) + atexit(ResetTimer); + if (options::get_int(regSpaceCadet, "Table Version", 1) <= 1) { auto tmpBuf = memory::allocate(0x1F4u); @@ -221,7 +225,7 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi pb::replay_level(0); DWORD someTimeCounter = 300u, prevTime = 0u; - then = timeGetTime(); + int sleepRemainder = 0, frameDuration = TargetFrameTime; while (true) { if (!someTimeCounter) @@ -259,68 +263,64 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi if (has_focus) { - if (mouse_down) + if (mouse_down && frameDuration >= 2) { - now = timeGetTime(); - if (now - then >= 2) - { - /*last_mouse_n is in client coordinates*/ - POINT Point; - GetCursorPos(&Point); - ScreenToClient(hwnd_frame, &Point); - pb::ballset(last_mouse_x - Point.x, Point.y - last_mouse_y); - Point = POINT{last_mouse_x, last_mouse_y}; - ClientToScreen(hwnd_frame, &Point); - SetCursorPos(Point.x, Point.y); - } + /*last_mouse_n is in client coordinates*/ + POINT Point; + GetCursorPos(&Point); + ScreenToClient(hwnd_frame, &Point); + pb::ballset(last_mouse_x - Point.x, Point.y - last_mouse_y); + Point = POINT{ last_mouse_x, last_mouse_y }; + ClientToScreen(hwnd_frame, &Point); + SetCursorPos(Point.x, Point.y); } + if (!single_step) { - now = timeGetTime(); - if (no_time_loss) - { - then = now; - no_time_loss = 0; - } - - if (now == then) - { - Sleep(8u); - } - else - { - auto dt = now - then; + auto frameStart = timeGetTime(); + auto dt = frameDuration; + if (!no_time_loss) pb::frame(dt); + else + no_time_loss = 0; - if (DispGRhistory) + if (DispGRhistory) + { + auto width = render::vscreen.Width / 2; + auto height = 64; + if (!gfr_display.BmpBufPtr1) { - auto width = render::vscreen.Width / 2; - auto height = 64; - if (!gfr_display.BmpBufPtr1) - { - gdrv::create_bitmap(&gfr_display, width, height); - } - - gdrv::ScrollBitmapHorizontal(&gfr_display, -1); - - auto target = 8.0f; - auto scale = height / target / 2; - gdrv::fill_bitmap(&gfr_display, 1, height, width - 1, 0, 0); // Background - - auto targetVal = dt < target ? dt : target; - auto targetHeight = min(static_cast(std::round(targetVal * scale)), height); - gdrv::fill_bitmap(&gfr_display, 1, targetHeight, width - 1, height - targetHeight, -1); // Target - - auto diffVal = dt < target ? target - dt : dt - target; - auto diffHeight = min(static_cast(std::round(diffVal * scale)), height); - gdrv::fill_bitmap(&gfr_display, 1, diffHeight, width - 1, height - targetHeight - diffHeight, 1); // Target diff - - gdrv::blit(&gfr_display, 0, 0, render::vscreen.Width - width, 0, width, height); + gdrv::create_bitmap(&gfr_display, width, height); } - --someTimeCounter; - then = now; + gdrv::ScrollBitmapHorizontal(&gfr_display, -1); + + float target = TargetFrameTime; + auto scale = height / target / 2; + gdrv::fill_bitmap(&gfr_display, 1, height, width - 1, 0, 0); // Background + + auto targetVal = dt < target ? dt : target; + auto targetHeight = min(static_cast(std::round(targetVal * scale)), height); + gdrv::fill_bitmap(&gfr_display, 1, targetHeight, width - 1, height - targetHeight, -1); // Target + + auto diffVal = dt < target ? target - dt : dt - target; + auto diffHeight = min(static_cast(std::round(diffVal * scale)), height); + gdrv::fill_bitmap(&gfr_display, 1, diffHeight, width - 1, height - targetHeight - diffHeight, 1); // Target diff + + gdrv::blit(&gfr_display, 0, 0, render::vscreen.Width - width, 0, width, height); } + + auto updateEnd = timeGetTime(); + auto sleepDuration = TargetFrameTime - (int)(updateEnd - frameStart) - sleepRemainder; + + if (sleepDuration > 0) + Sleep(sleepDuration); + + auto frameEnd = timeGetTime(); + sleepRemainder = (frameEnd - updateEnd) - sleepDuration; + frameDuration = min(frameEnd - frameStart, TargetFrameTime * 2); + + --someTimeCounter; } } } diff --git a/SpaceCadetPinball/winmain.h b/SpaceCadetPinball/winmain.h index ff49949..bbe5e3c 100644 --- a/SpaceCadetPinball/winmain.h +++ b/SpaceCadetPinball/winmain.h @@ -26,11 +26,14 @@ public: private: static int return_value, bQuit, DispFrameRate, DispGRhistory, activated; static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss; - static DWORD then, now; static UINT iFrostUniqueMsg; static gdrv_bitmap8 gfr_display; static HCURSOR mouse_hsave; static bool restart; static HDC _BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); + static void ResetTimer() + { + timeEndPeriod(1u); + } };