mirror of
https://github.com/k4zmu2a/SpaceCadetPinball.git
synced 2024-11-22 02:32:39 +01:00
winmain: reworked main loop for smoother frame times.
imgui_sdl: added handling for device lost. midi: load PINBALL.MID in uppercase and using absolute path. Added UPS/FPS options, by default 120/60.
This commit is contained in:
parent
22ce8ac538
commit
b4cb827d73
@ -100,6 +100,12 @@ namespace
|
|||||||
|
|
||||||
Clean();
|
Clean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
Order.clear();
|
||||||
|
Container.clear();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
void Clean()
|
void Clean()
|
||||||
{
|
{
|
||||||
@ -149,6 +155,7 @@ namespace
|
|||||||
struct Device
|
struct Device
|
||||||
{
|
{
|
||||||
SDL_Renderer* Renderer;
|
SDL_Renderer* Renderer;
|
||||||
|
bool CacheWasInvalidated = false;
|
||||||
|
|
||||||
struct ClipRect
|
struct ClipRect
|
||||||
{
|
{
|
||||||
@ -522,6 +529,14 @@ namespace
|
|||||||
|
|
||||||
namespace ImGuiSDL
|
namespace ImGuiSDL
|
||||||
{
|
{
|
||||||
|
static int ImGuiSDLEventWatch(void* userdata, SDL_Event* event) {
|
||||||
|
if (event->type == SDL_RENDER_TARGETS_RESET) {
|
||||||
|
// Device lost event, applies to DirectX and some mobile devices.
|
||||||
|
CurrentDevice->CacheWasInvalidated = true;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void Initialize(SDL_Renderer* renderer, int windowWidth, int windowHeight)
|
void Initialize(SDL_Renderer* renderer, int windowWidth, int windowHeight)
|
||||||
{
|
{
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
@ -531,6 +546,12 @@ namespace ImGuiSDL
|
|||||||
ImGui::GetStyle().WindowRounding = 0.0f;
|
ImGui::GetStyle().WindowRounding = 0.0f;
|
||||||
ImGui::GetStyle().AntiAliasedFill = false;
|
ImGui::GetStyle().AntiAliasedFill = false;
|
||||||
ImGui::GetStyle().AntiAliasedLines = false;
|
ImGui::GetStyle().AntiAliasedLines = false;
|
||||||
|
ImGui::GetStyle().ChildRounding = 0.0f;
|
||||||
|
ImGui::GetStyle().PopupRounding = 0.0f;
|
||||||
|
ImGui::GetStyle().FrameRounding = 0.0f;
|
||||||
|
ImGui::GetStyle().ScrollbarRounding = 0.0f;
|
||||||
|
ImGui::GetStyle().GrabRounding = 0.0f;
|
||||||
|
ImGui::GetStyle().TabRounding = 0.0f;
|
||||||
|
|
||||||
// Loads the font texture.
|
// Loads the font texture.
|
||||||
unsigned char* pixels;
|
unsigned char* pixels;
|
||||||
@ -545,6 +566,7 @@ namespace ImGuiSDL
|
|||||||
io.Fonts->TexID = (void*)texture;
|
io.Fonts->TexID = (void*)texture;
|
||||||
|
|
||||||
CurrentDevice = new Device(renderer);
|
CurrentDevice = new Device(renderer);
|
||||||
|
SDL_AddEventWatch(ImGuiSDLEventWatch, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Deinitialize()
|
void Deinitialize()
|
||||||
@ -555,10 +577,17 @@ namespace ImGuiSDL
|
|||||||
delete texture;
|
delete texture;
|
||||||
|
|
||||||
delete CurrentDevice;
|
delete CurrentDevice;
|
||||||
|
SDL_DelEventWatch(ImGuiSDLEventWatch, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Render(ImDrawData* drawData)
|
void Render(ImDrawData* drawData)
|
||||||
{
|
{
|
||||||
|
if (CurrentDevice->CacheWasInvalidated) {
|
||||||
|
CurrentDevice->CacheWasInvalidated = false;
|
||||||
|
CurrentDevice->GenericTriangleCache.Reset();
|
||||||
|
CurrentDevice->UniformColorTriangleCache.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
SDL_BlendMode blendMode;
|
SDL_BlendMode blendMode;
|
||||||
SDL_GetRenderDrawBlendMode(CurrentDevice->Renderer, &blendMode);
|
SDL_GetRenderDrawBlendMode(CurrentDevice->Renderer, &blendMode);
|
||||||
SDL_SetRenderDrawBlendMode(CurrentDevice->Renderer, SDL_BLENDMODE_BLEND);
|
SDL_SetRenderDrawBlendMode(CurrentDevice->Renderer, SDL_BLENDMODE_BLEND);
|
||||||
|
@ -59,7 +59,11 @@ int midi::music_init()
|
|||||||
return music_init_ft();
|
return music_init_ft();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentMidi = Mix_LoadMUS(pinball::get_rc_string(156, 0));
|
// File name is in lower case, while game data is in upper case.
|
||||||
|
std::string fileName = pinball::get_rc_string(156, 0);
|
||||||
|
std::transform(fileName.begin(), fileName.end(), fileName.begin(), [](unsigned char c) { return std::toupper(c); });
|
||||||
|
auto midiPath = pinball::make_path_name(fileName);
|
||||||
|
currentMidi = Mix_LoadMUS(midiPath.c_str());
|
||||||
return currentMidi != nullptr;
|
return currentMidi != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +125,7 @@ Mix_Music* midi::load_track(std::string fileName)
|
|||||||
fileName.insert(0, "SOUND");
|
fileName.insert(0, "SOUND");
|
||||||
}
|
}
|
||||||
fileName += ".MDS";
|
fileName += ".MDS";
|
||||||
|
|
||||||
auto filePath = pinball::make_path_name(fileName);
|
auto filePath = pinball::make_path_name(fileName);
|
||||||
auto midi = MdsToMidi(filePath);
|
auto midi = MdsToMidi(filePath);
|
||||||
if (!midi)
|
if (!midi)
|
||||||
@ -138,7 +142,7 @@ Mix_Music* midi::load_track(std::string fileName)
|
|||||||
delete midi;
|
delete midi;
|
||||||
if (!audio)
|
if (!audio)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
TrackList->Add(audio);
|
TrackList->Add(audio);
|
||||||
return audio;
|
return audio;
|
||||||
}
|
}
|
||||||
@ -329,7 +333,7 @@ std::vector<uint8_t>* midi::MdsToMidi(std::string file)
|
|||||||
midiBytes.insert(midiBytes.end(), metaEndTrack, metaEndTrack + 4);
|
midiBytes.insert(midiBytes.end(), metaEndTrack, metaEndTrack + 4);
|
||||||
|
|
||||||
// Set final MTrk size
|
// Set final MTrk size
|
||||||
auto lengthBE = SwapByteOrderInt((uint32_t)midiBytes.size() - sizeof header - sizeof track);
|
auto lengthBE = SwapByteOrderInt(static_cast<uint32_t>(midiBytes.size()) - sizeof header - sizeof track);
|
||||||
auto lengthData = reinterpret_cast<const uint8_t*>(&lengthBE);
|
auto lengthData = reinterpret_cast<const uint8_t*>(&lengthBE);
|
||||||
std::copy_n(lengthData, 4, midiBytes.begin() + lengthPos);
|
std::copy_n(lengthData, 4, midiBytes.begin() + lengthPos);
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,11 @@ void options::init()
|
|||||||
ImGui::GetIO().FontGlobalScale = get_float("UI Scale", 1.0f);
|
ImGui::GetIO().FontGlobalScale = get_float("UI Scale", 1.0f);
|
||||||
Options.Resolution = get_int("Screen Resolution", -1);
|
Options.Resolution = get_int("Screen Resolution", -1);
|
||||||
Options.LinearFiltering = get_int("Linear Filtering", true);
|
Options.LinearFiltering = get_int("Linear Filtering", true);
|
||||||
|
Options.FramesPerSecond = std::min(MaxFps, std::max(MinUps, get_int("Frames Per Second", DefFps)));
|
||||||
|
Options.UpdatesPerSecond = std::min(MaxUps, std::max(MinUps, get_int("Updates Per Second", DefUps)));
|
||||||
|
Options.UpdatesPerSecond = std::max(Options.UpdatesPerSecond, Options.FramesPerSecond);
|
||||||
|
|
||||||
|
winmain::UpdateFrameRate();
|
||||||
|
|
||||||
Sound::Enable(0, 7, Options.Sounds);
|
Sound::Enable(0, 7, Options.Sounds);
|
||||||
|
|
||||||
@ -125,6 +130,8 @@ void options::uninit()
|
|||||||
set_int("Uniform scaling", Options.UniformScaling);
|
set_int("Uniform scaling", Options.UniformScaling);
|
||||||
set_float("UI Scale", ImGui::GetIO().FontGlobalScale);
|
set_float("UI Scale", ImGui::GetIO().FontGlobalScale);
|
||||||
set_int("Linear Filtering", Options.LinearFiltering);
|
set_int("Linear Filtering", Options.LinearFiltering);
|
||||||
|
set_int("Frames Per Second", Options.FramesPerSecond);
|
||||||
|
set_int("Updates Per Second", Options.UpdatesPerSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,12 +49,17 @@ struct optionsStruct
|
|||||||
int Resolution;
|
int Resolution;
|
||||||
bool UniformScaling;
|
bool UniformScaling;
|
||||||
bool LinearFiltering;
|
bool LinearFiltering;
|
||||||
|
int FramesPerSecond;
|
||||||
|
int UpdatesPerSecond;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class options
|
class options
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// Original does ~120 updates per second.
|
||||||
|
static constexpr int MaxUps = 360, MaxFps = MaxUps, MinUps = 60, MinFps = MinUps,
|
||||||
|
DefUps = 120, DefFps = 60;
|
||||||
static optionsStruct Options;
|
static optionsStruct Options;
|
||||||
|
|
||||||
static void init();
|
static void init();
|
||||||
|
@ -214,24 +214,27 @@ void pb::ballset(int x, int y)
|
|||||||
ball->Speed = maths::normalize_2d(&ball->Acceleration);
|
ball->Speed = maths::normalize_2d(&ball->Acceleration);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pb::frame(int time)
|
void pb::frame(int dtMilliSec)
|
||||||
{
|
{
|
||||||
if (time > 100)
|
|
||||||
time = 100;
|
if (dtMilliSec > 100)
|
||||||
float timeMul = time * 0.001f;
|
dtMilliSec = 100;
|
||||||
if (!mode_countdown(time))
|
if (dtMilliSec <= 0)
|
||||||
|
return;
|
||||||
|
float dtMicroSec = dtMilliSec * 0.001f;
|
||||||
|
if (!mode_countdown(dtMilliSec))
|
||||||
{
|
{
|
||||||
time_next = time_now + timeMul;
|
time_next = time_now + dtMicroSec;
|
||||||
timed_frame(time_now, timeMul, true);
|
timed_frame(time_now, dtMicroSec, true);
|
||||||
time_now = time_next;
|
time_now = time_next;
|
||||||
time_ticks += time;
|
time_ticks += dtMilliSec;
|
||||||
if (nudge::nudged_left || nudge::nudged_right || nudge::nudged_up)
|
if (nudge::nudged_left || nudge::nudged_right || nudge::nudged_up)
|
||||||
{
|
{
|
||||||
nudge::nudge_count = timeMul * 4.0f + nudge::nudge_count;
|
nudge::nudge_count = dtMicroSec * 4.0f + nudge::nudge_count;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto nudgeDec = nudge::nudge_count - timeMul;
|
auto nudgeDec = nudge::nudge_count - dtMicroSec;
|
||||||
if (nudgeDec <= 0.0f)
|
if (nudgeDec <= 0.0f)
|
||||||
nudgeDec = 0.0;
|
nudgeDec = 0.0;
|
||||||
nudge::nudge_count = nudgeDec;
|
nudge::nudge_count = nudgeDec;
|
||||||
@ -249,7 +252,6 @@ int pb::frame(int time)
|
|||||||
MainTable->tilt(time_now);
|
MainTable->tilt(time_now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
|
void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)
|
||||||
|
@ -48,7 +48,7 @@ public:
|
|||||||
static void toggle_demo();
|
static void toggle_demo();
|
||||||
static void replay_level(int demoMode);
|
static void replay_level(int demoMode);
|
||||||
static void ballset(int x, int y);
|
static void ballset(int x, int y);
|
||||||
static int frame(int time);
|
static void frame(int dtMilliSec);
|
||||||
static void timed_frame(float timeNow, float timeDelta, bool drawBalls);
|
static void timed_frame(float timeNow, float timeDelta, bool drawBalls);
|
||||||
static void window_size(int* width, int* height);
|
static void window_size(int* width, int* height);
|
||||||
static void pause_continue();
|
static void pause_continue();
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#define SDL_MAIN_HANDLED
|
#define SDL_MAIN_HANDLED
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
const double TargetFps = 60, TargetFrameTime = 1000 / TargetFps;
|
|
||||||
|
|
||||||
SDL_Window* winmain::MainWindow = nullptr;
|
SDL_Window* winmain::MainWindow = nullptr;
|
||||||
SDL_Renderer* winmain::Renderer = nullptr;
|
SDL_Renderer* winmain::Renderer = nullptr;
|
||||||
ImGuiIO* winmain::ImIO = nullptr;
|
ImGuiIO* winmain::ImIO = nullptr;
|
||||||
@ -28,8 +26,6 @@ int winmain::last_mouse_y;
|
|||||||
int winmain::mouse_down;
|
int winmain::mouse_down;
|
||||||
int winmain::no_time_loss;
|
int winmain::no_time_loss;
|
||||||
|
|
||||||
DWORD winmain::then;
|
|
||||||
DWORD winmain::now;
|
|
||||||
bool winmain::restart = false;
|
bool winmain::restart = false;
|
||||||
|
|
||||||
gdrv_bitmap8 winmain::gfr_display{};
|
gdrv_bitmap8 winmain::gfr_display{};
|
||||||
@ -42,15 +38,8 @@ bool winmain::HighScoresEnabled = true;
|
|||||||
bool winmain::DemoActive = false;
|
bool winmain::DemoActive = false;
|
||||||
char* winmain::BasePath;
|
char* winmain::BasePath;
|
||||||
std::string winmain::FpsDetails;
|
std::string winmain::FpsDetails;
|
||||||
|
double winmain::UpdateToFrameRatio;
|
||||||
|
winmain::DurationMs winmain::TargetFrameTime;
|
||||||
uint32_t timeGetTimeAlt()
|
|
||||||
{
|
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
|
||||||
auto duration = now.time_since_epoch();
|
|
||||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
|
|
||||||
return static_cast<uint32_t>(millis);
|
|
||||||
}
|
|
||||||
|
|
||||||
int winmain::WinMain(LPCSTR lpCmdLine)
|
int winmain::WinMain(LPCSTR lpCmdLine)
|
||||||
{
|
{
|
||||||
@ -167,60 +156,57 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
|||||||
else
|
else
|
||||||
pb::replay_level(0);
|
pb::replay_level(0);
|
||||||
|
|
||||||
DWORD updateCounter = 300u, frameCounter = 0, prevTime = 0u;
|
DWORD dtHistoryCounter = 300u, updateCounter = 0, frameCounter = 0;
|
||||||
then = timeGetTimeAlt();
|
|
||||||
|
|
||||||
double sdlTimerResMs = 1000.0 / static_cast<double>(SDL_GetPerformanceFrequency());
|
auto frameStart = Clock::now();
|
||||||
auto frameStart = static_cast<double>(SDL_GetPerformanceCounter());
|
double frameDuration = TargetFrameTime.count(), UpdateToFrameCounter = 0;
|
||||||
|
DurationMs sleepRemainder(0);
|
||||||
|
auto prevTime = frameStart;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (!updateCounter)
|
if (DispFrameRate)
|
||||||
{
|
{
|
||||||
updateCounter = 300;
|
auto curTime = Clock::now();
|
||||||
if (DispFrameRate)
|
if (curTime - prevTime > DurationMs(1000))
|
||||||
{
|
{
|
||||||
auto curTime = timeGetTimeAlt();
|
char buf[60];
|
||||||
if (prevTime)
|
auto elapsedSec = DurationMs(curTime - prevTime).count() * 0.001;
|
||||||
{
|
snprintf(buf, sizeof buf, "Updates/sec = %02.02f Frames/sec = %02.02f ",
|
||||||
char buf[60];
|
updateCounter / elapsedSec, frameCounter / elapsedSec);
|
||||||
auto elapsedSec = static_cast<float>(curTime - prevTime) * 0.001f;
|
SDL_SetWindowTitle(window, buf);
|
||||||
snprintf(buf, sizeof buf, "Updates/sec = %02.02f Frames/sec = %02.02f ",
|
FpsDetails = buf;
|
||||||
300.0f / elapsedSec, frameCounter / elapsedSec);
|
frameCounter = updateCounter = 0;
|
||||||
SDL_SetWindowTitle(window, buf);
|
|
||||||
FpsDetails = buf;
|
|
||||||
frameCounter = 0;
|
|
||||||
|
|
||||||
if (DispGRhistory)
|
|
||||||
{
|
|
||||||
if (!gfr_display.BmpBufPtr1)
|
|
||||||
{
|
|
||||||
auto plt = static_cast<ColorRgba*>(malloc(1024u));
|
|
||||||
auto pltPtr = &plt[10];
|
|
||||||
for (int i1 = 0, i2 = 0; i1 < 256 - 10; ++i1, i2 += 8)
|
|
||||||
{
|
|
||||||
unsigned char blue = i2, redGreen = i2;
|
|
||||||
if (i2 > 255)
|
|
||||||
{
|
|
||||||
blue = 255;
|
|
||||||
redGreen = i1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*pltPtr++ = ColorRgba{Rgba{redGreen, redGreen, blue, 0}};
|
|
||||||
}
|
|
||||||
gdrv::display_palette(plt);
|
|
||||||
free(plt);
|
|
||||||
gdrv::create_bitmap(&gfr_display, 400, 15, 400, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
gdrv::copy_bitmap(&render::vscreen, 300, 10, 0, 30, &gfr_display, 0, 0);
|
|
||||||
gdrv::fill_bitmap(&gfr_display, 300, 10, 0, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevTime = curTime;
|
prevTime = curTime;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
if (DispGRhistory)
|
||||||
|
{
|
||||||
|
if (!gfr_display.BmpBufPtr1)
|
||||||
{
|
{
|
||||||
prevTime = 0;
|
auto plt = static_cast<ColorRgba*>(malloc(1024u));
|
||||||
|
auto pltPtr = &plt[10];
|
||||||
|
for (int i1 = 0, i2 = 0; i1 < 256 - 10; ++i1, i2 += 8)
|
||||||
|
{
|
||||||
|
unsigned char blue = i2, redGreen = i2;
|
||||||
|
if (i2 > 255)
|
||||||
|
{
|
||||||
|
blue = 255;
|
||||||
|
redGreen = i1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pltPtr++ = ColorRgba{Rgba{redGreen, redGreen, blue, 0}};
|
||||||
|
}
|
||||||
|
gdrv::display_palette(plt);
|
||||||
|
free(plt);
|
||||||
|
gdrv::create_bitmap(&gfr_display, 400, 15, 400, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dtHistoryCounter)
|
||||||
|
{
|
||||||
|
dtHistoryCounter = 300;
|
||||||
|
gdrv::copy_bitmap(&render::vscreen, 300, 10, 0, 30, &gfr_display, 0, 0);
|
||||||
|
gdrv::fill_bitmap(&gfr_display, 300, 10, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,53 +217,33 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
|||||||
{
|
{
|
||||||
if (mouse_down)
|
if (mouse_down)
|
||||||
{
|
{
|
||||||
now = timeGetTimeAlt();
|
int x, y;
|
||||||
if (now - then >= 2)
|
SDL_GetMouseState(&x, &y);
|
||||||
{
|
pb::ballset(last_mouse_x - x, y - last_mouse_y);
|
||||||
int x, y;
|
SDL_WarpMouseInWindow(window, last_mouse_x, last_mouse_y);
|
||||||
SDL_GetMouseState(&x, &y);
|
|
||||||
pb::ballset(last_mouse_x - x, y - last_mouse_y);
|
|
||||||
SDL_WarpMouseInWindow(window, last_mouse_x, last_mouse_y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!single_step)
|
if (!single_step)
|
||||||
{
|
{
|
||||||
auto curTime = timeGetTimeAlt();
|
auto deltaT = static_cast<int>(frameDuration);
|
||||||
now = curTime;
|
frameDuration -= deltaT;
|
||||||
if (no_time_loss)
|
pb::frame(deltaT);
|
||||||
|
if (gfr_display.BmpBufPtr1)
|
||||||
{
|
{
|
||||||
then = curTime;
|
auto deltaTPal = deltaT + 10;
|
||||||
no_time_loss = 0;
|
auto fillChar = static_cast<uint8_t>(deltaTPal);
|
||||||
}
|
if (deltaTPal > 236)
|
||||||
|
|
||||||
if (curTime == then)
|
|
||||||
{
|
|
||||||
SDL_Delay(8);
|
|
||||||
}
|
|
||||||
else if (pb::frame(curTime - then))
|
|
||||||
{
|
|
||||||
if (gfr_display.BmpBufPtr1)
|
|
||||||
{
|
{
|
||||||
auto deltaT = now - then + 10;
|
fillChar = 1;
|
||||||
auto fillChar = static_cast<uint8_t>(deltaT);
|
|
||||||
if (deltaT > 236)
|
|
||||||
{
|
|
||||||
fillChar = 1;
|
|
||||||
}
|
|
||||||
gdrv::fill_bitmap(&gfr_display, 1, 10, 300 - updateCounter, 0, fillChar);
|
|
||||||
}
|
}
|
||||||
--updateCounter;
|
gdrv::fill_bitmap(&gfr_display, 1, 10, 300 - dtHistoryCounter, 0, fillChar);
|
||||||
then = now;
|
--dtHistoryCounter;
|
||||||
}
|
}
|
||||||
|
updateCounter++;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto frameEnd = static_cast<double>(SDL_GetPerformanceCounter());
|
if (UpdateToFrameCounter >= UpdateToFrameRatio)
|
||||||
auto elapsedMs = (frameEnd - frameStart) * sdlTimerResMs;
|
|
||||||
if (elapsedMs >= TargetFrameTime)
|
|
||||||
{
|
{
|
||||||
// Keep track of remainder, limited to one frame time.
|
UpdateToFrameCounter -= UpdateToFrameRatio;
|
||||||
frameStart = frameEnd - std::min(elapsedMs - TargetFrameTime, TargetFrameTime) / sdlTimerResMs;
|
|
||||||
|
|
||||||
ImGui_ImplSDL2_NewFrame();
|
ImGui_ImplSDL2_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
@ -299,6 +265,28 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
|||||||
SDL_ClearError();
|
SDL_ClearError();
|
||||||
printf("SDL Error: %s\n", sdlError);
|
printf("SDL Error: %s\n", sdlError);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto updateEnd = Clock::now();
|
||||||
|
auto targetTimeDelta = TargetFrameTime - DurationMs(updateEnd - frameStart) - sleepRemainder;
|
||||||
|
|
||||||
|
TimePoint frameEnd;
|
||||||
|
if (targetTimeDelta > DurationMs::zero())
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(targetTimeDelta);
|
||||||
|
frameEnd = Clock::now();
|
||||||
|
sleepRemainder = DurationMs(frameEnd - updateEnd) - targetTimeDelta;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frameEnd = updateEnd;
|
||||||
|
sleepRemainder = DurationMs(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit duration to 2 * target time
|
||||||
|
frameDuration = std::min(frameDuration + DurationMs(frameEnd - frameStart).count(),
|
||||||
|
2 * TargetFrameTime.count());
|
||||||
|
frameStart = frameEnd;
|
||||||
|
UpdateToFrameCounter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,7 +418,7 @@ void winmain::RenderUi()
|
|||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginMenu("Window"))
|
if (ImGui::BeginMenu("Graphics"))
|
||||||
{
|
{
|
||||||
if (ImGui::MenuItem("Uniform Scaling", nullptr, options::Options.UniformScaling))
|
if (ImGui::MenuItem("Uniform Scaling", nullptr, options::Options.UniformScaling))
|
||||||
{
|
{
|
||||||
@ -440,8 +428,35 @@ void winmain::RenderUi()
|
|||||||
{
|
{
|
||||||
options::toggle(Menu1::WindowLinearFilter);
|
options::toggle(Menu1::WindowLinearFilter);
|
||||||
}
|
}
|
||||||
ImGui::DragFloat("", &ImIO->FontGlobalScale, 0.005f, 0.8f, 5,
|
ImGui::DragFloat("UI Scale", &ImIO->FontGlobalScale, 0.005f, 0.8f, 5,
|
||||||
"UI Scale %.2f", ImGuiSliderFlags_AlwaysClamp);
|
"%.2f", ImGuiSliderFlags_AlwaysClamp);
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
auto changed = false;
|
||||||
|
if (ImGui::MenuItem("Set Default UPS/FPS"))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
options::Options.UpdatesPerSecond = options::DefUps;
|
||||||
|
options::Options.FramesPerSecond = options::DefFps;
|
||||||
|
}
|
||||||
|
if (ImGui::DragInt("UPS", &options::Options.UpdatesPerSecond, 1, options::MinUps, options::MaxUps,
|
||||||
|
"%d", ImGuiSliderFlags_AlwaysClamp))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
options::Options.FramesPerSecond = std::min(options::Options.UpdatesPerSecond,
|
||||||
|
options::Options.FramesPerSecond);
|
||||||
|
}
|
||||||
|
if (ImGui::DragInt("FPS", &options::Options.FramesPerSecond, 1, options::MinFps, options::MaxFps,
|
||||||
|
"%d", ImGuiSliderFlags_AlwaysClamp))
|
||||||
|
{
|
||||||
|
changed = true;
|
||||||
|
options::Options.UpdatesPerSecond = std::max(options::Options.UpdatesPerSecond,
|
||||||
|
options::Options.FramesPerSecond);
|
||||||
|
}
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
UpdateFrameRate();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
@ -760,3 +775,11 @@ void winmain::Restart()
|
|||||||
SDL_Event event{SDL_QUIT};
|
SDL_Event event{SDL_QUIT};
|
||||||
SDL_PushEvent(&event);
|
SDL_PushEvent(&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void winmain::UpdateFrameRate()
|
||||||
|
{
|
||||||
|
// UPS >= FPS
|
||||||
|
auto fps = options::Options.FramesPerSecond, ups = options::Options.UpdatesPerSecond;
|
||||||
|
UpdateToFrameRatio = static_cast<double>(ups) / fps;
|
||||||
|
TargetFrameTime = DurationMs(1000.0 / ups);
|
||||||
|
}
|
||||||
|
@ -1,8 +1,44 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "gdrv.h"
|
#include "gdrv.h"
|
||||||
|
|
||||||
|
struct SdlTickClock
|
||||||
|
{
|
||||||
|
using duration = std::chrono::milliseconds;
|
||||||
|
using rep = duration::rep;
|
||||||
|
using period = duration::period;
|
||||||
|
using time_point = std::chrono::time_point<SdlTickClock>;
|
||||||
|
static constexpr bool is_steady = true;
|
||||||
|
|
||||||
|
static time_point now() noexcept
|
||||||
|
{
|
||||||
|
return time_point{duration{SDL_GetTicks()}};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SdlPerformanceClock
|
||||||
|
{
|
||||||
|
using duration = std::chrono::duration<uint64_t, std::nano>;
|
||||||
|
using rep = duration::rep;
|
||||||
|
using period = duration::period;
|
||||||
|
using time_point = std::chrono::time_point<SdlPerformanceClock>;
|
||||||
|
static constexpr bool is_steady = true;
|
||||||
|
|
||||||
|
static time_point now() noexcept
|
||||||
|
{
|
||||||
|
const auto freq = SDL_GetPerformanceFrequency();
|
||||||
|
const auto ctr = SDL_GetPerformanceCounter();
|
||||||
|
const auto whole = (ctr / freq) * period::den;
|
||||||
|
const auto part = (ctr % freq) * period::den / freq;
|
||||||
|
return time_point(duration(whole + part));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class winmain
|
class winmain
|
||||||
{
|
{
|
||||||
|
using Clock = SdlPerformanceClock; // Or std::chrono::steady_clock.
|
||||||
|
using DurationMs = std::chrono::duration<double, std::milli>;
|
||||||
|
using TimePoint = std::chrono::time_point<Clock>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static std::string DatFileName;
|
static std::string DatFileName;
|
||||||
static int single_step;
|
static int single_step;
|
||||||
@ -24,16 +60,18 @@ public:
|
|||||||
static void pause();
|
static void pause();
|
||||||
static void Restart();
|
static void Restart();
|
||||||
static bool RestartRequested() { return restart; }
|
static bool RestartRequested() { return restart; }
|
||||||
|
static void UpdateFrameRate();
|
||||||
private:
|
private:
|
||||||
static int return_value, bQuit, DispFrameRate, DispGRhistory, activated;
|
static int return_value, bQuit, DispFrameRate, DispGRhistory, activated;
|
||||||
static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss;
|
static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss;
|
||||||
static DWORD then, now;
|
|
||||||
static gdrv_bitmap8 gfr_display;
|
static gdrv_bitmap8 gfr_display;
|
||||||
static std::string FpsDetails;
|
static std::string FpsDetails;
|
||||||
static bool restart;
|
static bool restart;
|
||||||
static bool ShowAboutDialog;
|
static bool ShowAboutDialog;
|
||||||
static bool ShowImGuiDemo;
|
static bool ShowImGuiDemo;
|
||||||
static bool ShowSpriteViewer;
|
static bool ShowSpriteViewer;
|
||||||
|
static double UpdateToFrameRatio;
|
||||||
|
static DurationMs TargetFrameTime;
|
||||||
|
|
||||||
static void RenderUi();
|
static void RenderUi();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user