update to master, fix sdl music build

This commit is contained in:
Alula 2021-09-28 14:36:44 +02:00
commit 4ff2f97fa6
No known key found for this signature in database
GPG Key ID: 3E00485503A1D8BA
11 changed files with 315 additions and 174 deletions

View File

@ -3,6 +3,7 @@ project(SpaceCadetPinball)
set(CMAKE_CXX_STANDARD 11)
option(MUSIC_TSF "Use TinySoundFont for MIDI playback" ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/bin)
@ -175,12 +176,16 @@ set(SOURCE_FILES
SpaceCadetPinball/imstb_textedit.h
SpaceCadetPinball/imstb_rectpack.h
SpaceCadetPinball/imstb_truetype.h
SpaceCadetPinball/gm_sf2.cpp
SpaceCadetPinball/tsf.cpp
SpaceCadetPinball/tml.h
SpaceCadetPinball/tsf.h
)
if (MUSIC_TSF)
set(SOURCE_FILES ${SOURCE_FILES}
SpaceCadetPinball/gm_sf2.cpp
SpaceCadetPinball/tsf.cpp
SpaceCadetPinball/tml.h
SpaceCadetPinball/tsf.h)
endif()
add_executable(SpaceCadetPinball ${SOURCE_FILES})
# Skip pch on foreign code
@ -192,6 +197,9 @@ set_source_files_properties(
SpaceCadetPinball/imgui_tables.cpp
SpaceCadetPinball/imgui_demo.cpp
SpaceCadetPinball/imgui_impl_sdl.cpp
SpaceCadetPinball/gm_sf2.cpp
SpaceCadetPinball/tsf.cpp
PROPERTIES SKIP_PRECOMPILE_HEADERS 1
)
target_precompile_headers(SpaceCadetPinball
@ -199,8 +207,13 @@ target_precompile_headers(SpaceCadetPinball
SpaceCadetPinball/pch.h
)
if (MUSIC_TSF)
target_compile_definitions(SpaceCadetPinball PRIVATE -DMUSIC_TSF)
else()
target_compile_definitions(SpaceCadetPinball PRIVATE -DMUSIC_SDL)
endif()
target_link_libraries(SpaceCadetPinball ${SDL2_LIBRARY} ${SDL2_MIXER_LIBRARY})
target_compile_definitions(SpaceCadetPinball PRIVATE -DMUSIC_TSF)
if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
target_link_libraries(SpaceCadetPinball idbfs.js)

View File

@ -100,6 +100,12 @@ namespace
Clean();
}
void Reset()
{
Order.clear();
Container.clear();
}
private:
void Clean()
{
@ -149,6 +155,7 @@ namespace
struct Device
{
SDL_Renderer* Renderer;
bool CacheWasInvalidated = false;
struct ClipRect
{
@ -522,6 +529,14 @@ namespace
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)
{
ImGuiIO& io = ImGui::GetIO();
@ -531,6 +546,12 @@ namespace ImGuiSDL
ImGui::GetStyle().WindowRounding = 0.0f;
ImGui::GetStyle().AntiAliasedFill = 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.
unsigned char* pixels;
@ -545,6 +566,7 @@ namespace ImGuiSDL
io.Fonts->TexID = (void*)texture;
CurrentDevice = new Device(renderer);
SDL_AddEventWatch(ImGuiSDLEventWatch, nullptr);
}
void Deinitialize()
@ -555,10 +577,17 @@ namespace ImGuiSDL
delete texture;
delete CurrentDevice;
SDL_DelEventWatch(ImGuiSDLEventWatch, nullptr);
}
void Render(ImDrawData* drawData)
{
if (CurrentDevice->CacheWasInvalidated) {
CurrentDevice->CacheWasInvalidated = false;
CurrentDevice->GenericTriangleCache.Reset();
CurrentDevice->UniformColorTriangleCache.Reset();
}
SDL_BlendMode blendMode;
SDL_GetRenderDrawBlendMode(CurrentDevice->Renderer, &blendMode);
SDL_SetRenderDrawBlendMode(CurrentDevice->Renderer, SDL_BLENDMODE_BLEND);

View File

@ -10,6 +10,8 @@
#endif
midi_song midi::currentMidi = {false};
#ifdef MUSIC_TSF
tml_message* midi::currentMessage = nullptr;
static float midiTime = 0.0f;
static float sampPerSec = 1000.0 / 22050.0;
@ -62,6 +64,7 @@ void midi::sdl_audio_callback(void* data, Uint8 *stream, int len)
tsf_render_short(tsfSynth, (short*)stream, SampleBlock, 0);
}
}
#endif
constexpr uint32_t FOURCC(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
@ -93,7 +96,7 @@ int midi::play_pb_theme(int flag)
#ifdef MUSIC_SDL
int result = 0;
music_stop();
if (currentMidi)
if (currentMidi.valid)
result = Mix_PlayMusic(currentMidi.handle, -1);
return result;
@ -138,14 +141,23 @@ int midi::music_init()
return music_init_ft();
}
#ifdef MUSIC_SDL
currentMidi = Mix_LoadMUS(pinball::get_rc_string(156, 0));
return currentMidi != nullptr;
#if defined(MUSIC_SDL)
// 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);
auto song = Mix_LoadMUS(midiPath.c_str());
if (song) {
currentMidi = {true, song};
} else {
currentMidi = {false};
}
return currentMidi.valid;
#elif defined(MUSIC_TSF)
currentMessage = nullptr;
currentMidi = {false};
tsfSynth = tsf_load_memory(gm_sf2, (int)gm_sf2_len);
int sampleRate;
@ -209,18 +221,27 @@ void midi::music_shutdown_ft()
#ifdef MUSIC_SDL
if (active_track.valid)
Mix_HaltMusic();
/*while (TrackList->GetCount())
{
auto midi = TrackList->Get(0);
Mix_FreeMusic(midi.handle);
TrackList->Delete(midi);
}*/
for (auto& track : TrackList) {
if (track.valid) Mix_FreeMusic(track.handle);
}
TrackList.clear();
active_track = {false};
delete TrackList;
#elif defined(MUSIC_TSF)
if (active_track.valid) {
tsf_note_off_all(tsfSynth);
active_track = {false, nullptr};
currentMessage = nullptr;
midiTime = 0.0f;
}
active_track = {false};
for (auto& track : TrackList) {
//if (track.valid) tml_free(track.handle);
}
TrackList.clear();
#endif
}
@ -237,7 +258,7 @@ midi_song midi::load_track(std::string fileName)
fileName.insert(0, "SOUND");
}
fileName += ".MDS";
auto filePath = pinball::make_path_name(fileName);
auto midi = MdsToMidi(filePath);
if (!midi)
@ -283,14 +304,14 @@ int midi::play_ft(midi_song* midi)
}
#ifdef MUSIC_SDL
if (Mix_PlayMusic(midi.handle, -1))
if (Mix_PlayMusic(midi->handle, -1))
{
active_track = nullptr;
active_track = {false, nullptr};
result = 0;
}
else
{
active_track = midi;
active_track = *midi;
result = 1;
}
#elif defined(MUSIC_TSF)
@ -474,7 +495,7 @@ std::vector<uint8_t>* midi::MdsToMidi(std::string file)
midiBytes.insert(midiBytes.end(), metaEndTrack, metaEndTrack + 4);
// 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);
std::copy_n(lengthData, 4, midiBytes.begin() + lengthPos);
}

View File

@ -44,6 +44,7 @@ short options::vk_list[28]
std::map<std::string, std::string> options::settings{};
constexpr int options::MaxUps, options::MaxFps, options::MinUps, options::MinFps, options::DefUps, options::DefFps;
void options::init()
{
@ -100,6 +101,11 @@ void options::init()
ImGui::GetIO().FontGlobalScale = get_float("UI Scale", 1.0f);
Options.Resolution = get_int("Screen Resolution", -1);
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);
@ -125,6 +131,8 @@ void options::uninit()
set_int("Uniform scaling", Options.UniformScaling);
set_float("UI Scale", ImGui::GetIO().FontGlobalScale);
set_int("Linear Filtering", Options.LinearFiltering);
set_int("Frames Per Second", Options.FramesPerSecond);
set_int("Updates Per Second", Options.UpdatesPerSecond);
}

View File

@ -49,12 +49,17 @@ struct optionsStruct
int Resolution;
bool UniformScaling;
bool LinearFiltering;
int FramesPerSecond;
int UpdatesPerSecond;
};
class options
{
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 void init();

View File

@ -214,24 +214,27 @@ void pb::ballset(int x, int y)
ball->Speed = maths::normalize_2d(&ball->Acceleration);
}
int pb::frame(int time)
void pb::frame(int dtMilliSec)
{
if (time > 100)
time = 100;
float timeMul = time * 0.001f;
if (!mode_countdown(time))
if (dtMilliSec > 100)
dtMilliSec = 100;
if (dtMilliSec <= 0)
return;
float dtMicroSec = dtMilliSec * 0.001f;
if (!mode_countdown(dtMilliSec))
{
time_next = time_now + timeMul;
timed_frame(time_now, timeMul, true);
time_next = time_now + dtMicroSec;
timed_frame(time_now, dtMicroSec, true);
time_now = time_next;
time_ticks += time;
time_ticks += dtMilliSec;
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
{
auto nudgeDec = nudge::nudge_count - timeMul;
auto nudgeDec = nudge::nudge_count - dtMicroSec;
if (nudgeDec <= 0.0f)
nudgeDec = 0.0;
nudge::nudge_count = nudgeDec;
@ -249,7 +252,6 @@ int pb::frame(int time)
MainTable->tilt(time_now);
}
}
return 1;
}
void pb::timed_frame(float timeNow, float timeDelta, bool drawBalls)

View File

@ -48,7 +48,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 dtMilliSec);
static void timed_frame(float timeNow, float timeDelta, bool drawBalls);
static void window_size(int* width, int* height);
static void pause_continue();

View File

@ -27,6 +27,7 @@
#include <algorithm>
#include <cstring>
#include <string>
#include <thread>
#define SDL_MAIN_HANDLED
#include "SDL.h"

View File

@ -17,8 +17,6 @@
#include <unistd.h>
#endif
const double TargetFps = 60, TargetFrameTime = 1000 / TargetFps;
SDL_Window *winmain::MainWindow = nullptr;
SDL_Renderer *winmain::Renderer = nullptr;
ImGuiIO *winmain::ImIO = nullptr;
@ -35,8 +33,6 @@ int winmain::last_mouse_y;
int winmain::mouse_down;
int winmain::no_time_loss;
DWORD winmain::then;
DWORD winmain::now;
bool winmain::restart = false;
gdrv_bitmap8 winmain::gfr_display{};
@ -49,14 +45,8 @@ bool winmain::HighScoresEnabled = true;
bool winmain::DemoActive = false;
char *winmain::BasePath;
std::string winmain::FpsDetails;
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);
}
double winmain::UpdateToFrameRatio;
winmain::DurationMs winmain::TargetFrameTime;
static bool loop_stop = false;
@ -201,144 +191,140 @@ int winmain::WinMain(LPCSTR lpCmdLine)
else
pb::replay_level(0);
DWORD updateCounter = 300u, frameCounter = 0, prevTime = 0u;
then = timeGetTimeAlt();
DWORD dtHistoryCounter = 300u, updateCounter = 0, frameCounter = 0;
double sdlTimerResMs = 1000.0 / static_cast<double>(SDL_GetPerformanceFrequency());
auto frameStart = static_cast<double>(SDL_GetPerformanceCounter());
auto frameStart = Clock::now();
double frameDuration = TargetFrameTime.count(), UpdateToFrameCounter = 0;
DurationMs sleepRemainder(0);
auto prevTime = frameStart;
run_loop([&]() {
if (DispFrameRate)
{
auto curTime = Clock::now();
if (curTime - prevTime > DurationMs(1000))
{
char buf[60];
auto elapsedSec = DurationMs(curTime - prevTime).count() * 0.001;
snprintf(buf, sizeof buf, "Updates/sec = %02.02f Frames/sec = %02.02f ",
updateCounter / elapsedSec, frameCounter / elapsedSec);
SDL_SetWindowTitle(window, buf);
FpsDetails = buf;
frameCounter = updateCounter = 0;
prevTime = curTime;
}
}
run_loop([&]
{
if (!updateCounter)
{
updateCounter = 300;
if (DispFrameRate)
{
auto curTime = timeGetTimeAlt();
if (prevTime)
{
char buf[60];
auto elapsedSec = static_cast<float>(curTime - prevTime) * 0.001f;
snprintf(buf, sizeof buf, "Updates/sec = %02.02f Frames/sec = %02.02f ",
300.0f / elapsedSec, frameCounter / elapsedSec);
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;
}
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);
}
*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);
}
}
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;
}
else
{
prevTime = 0;
}
}
if (!ProcessWindowMessages() || bQuit) {
loop_stop = true;
return;
}
if (!ProcessWindowMessages() || bQuit)
{
loop_stop = true;
return;
}
if (has_focus)
{
if (mouse_down)
{
int x, 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)
{
auto deltaT = static_cast<int>(frameDuration);
frameDuration -= deltaT;
pb::frame(deltaT);
if (gfr_display.BmpBufPtr1)
{
auto deltaTPal = deltaT + 10;
auto fillChar = static_cast<uint8_t>(deltaTPal);
if (deltaTPal > 236)
{
fillChar = 1;
}
gdrv::fill_bitmap(&gfr_display, 1, 10, 300 - dtHistoryCounter, 0, fillChar);
--dtHistoryCounter;
}
updateCounter++;
}
if (has_focus)
{
if (mouse_down)
{
now = timeGetTimeAlt();
if (now - then >= 2)
{
int x, 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)
{
auto curTime = timeGetTimeAlt();
now = curTime;
if (no_time_loss)
{
then = curTime;
no_time_loss = 0;
}
if (UpdateToFrameCounter >= UpdateToFrameRatio)
{
UpdateToFrameCounter -= UpdateToFrameRatio;
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
if (curTime == then)
{
SDL_Delay(8);
}
else if (pb::frame(curTime - then))
{
if (gfr_display.BmpBufPtr1)
{
auto deltaT = now - then + 10;
auto fillChar = static_cast<uint8_t>(deltaT);
if (deltaT > 236)
{
fillChar = 1;
}
gdrv::fill_bitmap(&gfr_display, 1, 10, 300 - updateCounter, 0, fillChar);
}
--updateCounter;
then = now;
}
}
RenderUi();
auto frameEnd = static_cast<double>(SDL_GetPerformanceCounter());
auto elapsedMs = (frameEnd - frameStart) * sdlTimerResMs;
if (elapsedMs >= TargetFrameTime)
{
// Keep track of remainder, limited to one frame time.
frameStart = frameEnd - std::min(elapsedMs - TargetFrameTime, TargetFrameTime) / sdlTimerResMs;
SDL_RenderClear(renderer);
render::PresentVScreen();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
ImGui::Render();
ImGuiSDL::Render(ImGui::GetDrawData());
RenderUi();
SDL_RenderPresent(renderer);
frameCounter++;
}
SDL_RenderClear(renderer);
render::PresentVScreen();
auto sdlError = SDL_GetError();
if (sdlError[0])
{
SDL_ClearError();
printf("SDL Error: %s\n", sdlError);
}
ImGui::Render();
ImGuiSDL::Render(ImGui::GetDrawData());
auto updateEnd = Clock::now();
auto targetTimeDelta = TargetFrameTime - DurationMs(updateEnd - frameStart) - sleepRemainder;
SDL_RenderPresent(renderer);
frameCounter++;
}
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);
}
auto sdlError = SDL_GetError();
if (sdlError[0])
{
SDL_ClearError();
printf("SDL Error: %s\n", sdlError);
}
}
});
// Limit duration to 2 * target time
frameDuration = std::min(frameDuration + DurationMs(frameEnd - frameStart).count(),
2 * TargetFrameTime.count());
frameStart = frameEnd;
UpdateToFrameCounter++;
}
});
gdrv::destroy_bitmap(&gfr_display);
options::uninit();
@ -472,7 +458,7 @@ void winmain::RenderUi()
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Window"))
if (ImGui::BeginMenu("Graphics"))
{
if (ImGui::MenuItem("Uniform Scaling", nullptr, options::Options.UniformScaling))
{
@ -482,8 +468,35 @@ void winmain::RenderUi()
{
options::toggle(Menu1::WindowLinearFilter);
}
ImGui::DragFloat("", &ImIO->FontGlobalScale, 0.005f, 0.8f, 5,
"UI Scale %.2f", ImGuiSliderFlags_AlwaysClamp);
ImGui::DragFloat("UI Scale", &ImIO->FontGlobalScale, 0.005f, 0.8f, 5,
"%.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();
}
@ -814,3 +827,11 @@ void winmain::Restart()
SDL_Event event{SDL_QUIT};
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);
}

View File

@ -1,8 +1,44 @@
#pragma once
#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
{
using Clock = SdlPerformanceClock; // Or std::chrono::steady_clock.
using DurationMs = std::chrono::duration<double, std::milli>;
using TimePoint = std::chrono::time_point<Clock>;
public:
static std::string DatFileName;
static int single_step;
@ -24,16 +60,18 @@ public:
static void pause();
static void Restart();
static bool RestartRequested() { return restart; }
static void UpdateFrameRate();
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 gdrv_bitmap8 gfr_display;
static std::string FpsDetails;
static bool restart;
static bool ShowAboutDialog;
static bool ShowImGuiDemo;
static bool ShowSpriteViewer;
static double UpdateToFrameRatio;
static DurationMs TargetFrameTime;
static void RenderUi();
};

View File

@ -0,0 +1,3 @@
This directory is used for emscripten builds.
Place all game files, excluding the .exe in this directory.