151 lines
3.5 KiB
C++
151 lines
3.5 KiB
C++
#include <chrono>
|
|
#include <cstdint>
|
|
#include <iostream>
|
|
#include <thread>
|
|
|
|
#include "DefaultHardware.h"
|
|
#include "DrawContext.h"
|
|
#include "IDisplay.h"
|
|
#include "TimeSource.h"
|
|
#include "Timer.h"
|
|
#include "app/DesktopApp.h"
|
|
#include "ui/GameLauncher.h"
|
|
|
|
#ifdef TARGET_IMX
|
|
#include "FBDisplay.h"
|
|
#endif
|
|
#ifdef TARGET_PC
|
|
#include "SDLDisplay.h"
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
const int32_t ScreenWidth = 1024;
|
|
const int32_t ScreenHeight = 600;
|
|
const int32_t RestoreRetryCount = 5;
|
|
const uint32_t RestoreRetryDelayMs = 300;
|
|
|
|
static Platform::IDisplay* CreateDisplay()
|
|
{
|
|
#ifdef TARGET_IMX
|
|
return new Platform::FBDisplay();
|
|
#endif
|
|
#ifdef TARGET_PC
|
|
return new Platform::SDLDisplay();
|
|
#endif
|
|
}
|
|
|
|
static void SleepRemainingFrameTime(const Core::Timer& timer, const Platform::ITimeSource& timeSource)
|
|
{
|
|
const uint32_t sleepMs = timer.remaining_frame_ms(timeSource.get_time_ms());
|
|
if (sleepMs > 0u)
|
|
{
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
|
|
}
|
|
}
|
|
|
|
static bool RestoreDesktopHardware(
|
|
Platform::IDisplay* display,
|
|
Platform::DefaultPointerInput& pointerInput)
|
|
{
|
|
for (int32_t attempt = 1; attempt <= RestoreRetryCount; ++attempt)
|
|
{
|
|
if (display->init(ScreenWidth, ScreenHeight))
|
|
{
|
|
if (!pointerInput.init("", ScreenWidth, ScreenHeight))
|
|
{
|
|
std::cerr << "[WARN] Pointer input restore failed; desktop touch is disabled." << std::endl;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::cerr << "[WARN] Failed to restore desktop display, retry "
|
|
<< attempt << "/" << RestoreRetryCount << "." << std::endl;
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(RestoreRetryDelayMs));
|
|
}
|
|
|
|
std::cerr << "[ERROR] Failed to restore desktop display after retries." << std::endl;
|
|
return false;
|
|
}
|
|
|
|
static bool LaunchGameAndRestoreDesktop(
|
|
const Desktop::GameEntry& game,
|
|
Desktop::GameLauncher& launcher,
|
|
Platform::IDisplay* display,
|
|
Platform::DefaultPointerInput& pointerInput)
|
|
{
|
|
pointerInput.shutdown();
|
|
display->shutdown();
|
|
|
|
const bool launched = launcher.launch_and_wait(game);
|
|
if (!launched)
|
|
{
|
|
std::cerr << "[WARN] Game launch failed: " << (game.title ? game.title : "(unnamed)") << std::endl;
|
|
}
|
|
|
|
return RestoreDesktopHardware(display, pointerInput);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
Platform::IDisplay* display = CreateDisplay();
|
|
if (!display->init(ScreenWidth, ScreenHeight))
|
|
{
|
|
delete display;
|
|
return -1;
|
|
}
|
|
|
|
Platform::DefaultPointerInput pointerInput;
|
|
if (!pointerInput.init("", ScreenWidth, ScreenHeight))
|
|
{
|
|
std::cerr << "[WARN] Pointer input init failed; desktop touch is disabled." << std::endl;
|
|
}
|
|
|
|
Core::DrawContext ctx(ScreenWidth, ScreenHeight);
|
|
Core::Timer timer(30);
|
|
Platform::SteadyTimeSource timeSource;
|
|
Desktop::DesktopApp app(ScreenWidth, ScreenHeight, &pointerInput);
|
|
Desktop::GameLauncher launcher;
|
|
|
|
std::cout << "[INFO] Desktop started. Target FPS: " << timer.target_fps() << std::endl;
|
|
|
|
bool isRunning = true;
|
|
while (isRunning)
|
|
{
|
|
timer.begin_frame(timeSource.get_time_ms());
|
|
|
|
bool shouldQuit = false;
|
|
display->poll_events(shouldQuit);
|
|
if (shouldQuit)
|
|
{
|
|
isRunning = false;
|
|
}
|
|
|
|
app.update(timer.fixed_delta_ms());
|
|
const Desktop::GameEntry* launchGame = app.consume_pending_launch();
|
|
if (launchGame != nullptr)
|
|
{
|
|
if (!LaunchGameAndRestoreDesktop(*launchGame, launcher, display, pointerInput))
|
|
{
|
|
isRunning = false;
|
|
break;
|
|
}
|
|
timer.begin_frame(timeSource.get_time_ms());
|
|
}
|
|
|
|
app.draw(ctx);
|
|
ctx.present(display);
|
|
SleepRemainingFrameTime(timer, timeSource);
|
|
}
|
|
|
|
pointerInput.shutdown();
|
|
display->shutdown();
|
|
delete display;
|
|
return 0;
|
|
}
|