psemek/libs/sdl2/source/main.cpp

156 lines
4.3 KiB
C++

#include <psemek/app/application.hpp>
#include <psemek/app/resource.hpp>
#include <psemek/gfx/init.hpp>
#include <psemek/sdl2/init.hpp>
#include <psemek/sdl2/window.hpp>
#include <psemek/sdl2/events.hpp>
#include <psemek/util/clock.hpp>
#include <psemek/util/pretty_print.hpp>
#include <psemek/log/log.hpp>
#include <psemek/log/colored_stream.hpp>
#include <psemek/io/synchronized.hpp>
#include <psemek/util/exception.hpp>
#include <psemek/util/terminal_color.hpp>
#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <emscripten.h>
#include <emscripten/wasmfs.h>
struct em_state
{
std::unique_ptr<psemek::app::application> application;
std::unique_ptr<psemek::sdl2::window> window;
psemek::app::application::context context;
} em_state;
#endif
#undef main
int main(int argc, char ** argv) try
{
using namespace psemek;
util::clock<std::chrono::milliseconds, std::chrono::high_resolution_clock> clock;
#ifdef PSEMEK_PACKAGE_MODE
log::level const stdio_log_level = log::level::info;
#else
log::level const stdio_log_level = log::level::debug;
#endif
std::vector<std::unique_ptr<io::ostream>> synchronized_stdout_stderr;
synchronized_stdout_stderr.push_back(io::std_out());
synchronized_stdout_stderr.push_back(io::std_err());
synchronized_stdout_stderr = io::synchronized(std::move(synchronized_stdout_stderr));
if (util::terminal_color::supported())
synchronized_stdout_stderr[1] = log::colored_stream(std::move(synchronized_stdout_stderr[1]), std::string{util::terminal_color::red()}, std::string{util::terminal_color::normal()});
log::add_sink(log::default_sink(std::move(synchronized_stdout_stderr[0]), stdio_log_level, log::level::info));
log::add_sink(log::default_sink(std::move(synchronized_stdout_stderr[1]), log::level::warning, log::level::error));
log::register_thread("main");
#ifdef __EMSCRIPTEN__
// In web builds, resources are stored in
// the Emscripten virtual filesystem
app::set_resource_root("/resources");
#endif
auto const factory = app::make_application_factory();
auto const options = factory->options();
#ifdef __EMSCRIPTEN__
em_state.window = std::make_unique<sdl2::window>(options);
auto & window = *em_state.window;
#else
sdl2::window window(options);
#endif
#ifdef __EMSCRIPTEN__
auto & context = em_state.context;
#else
app::application::context context;
#endif
for (int i = 0; i < argc; ++i)
context.args.push_back(argv[i]);
context.show_cursor = [&](bool show){ window.show_cursor(show); };
context.relative_mouse_mode = [&](bool mode){ window.relative_mouse_mode(mode); };
context.windowed = [&](bool on){ window.windowed(on); };
context.text_input = [](bool on){ if (on) SDL_StartTextInput(); else SDL_StopTextInput(); };
#if defined(PSEMEK_GRAPHICS_API_OPENGL)
context.vsync = [&](bool on){ window.vsync(on); };
#endif
#if defined(PSEMEK_GRAPHICS_API_WEBGPU)
context.instance = window.wgpu_instance();
context.adapter = window.wgpu_adapter();
context.surface = window.wgpu_surface();
context.device = window.wgpu_device();
#endif
#ifdef __EMSCRIPTEN__
em_state.application = factory->create(options, context);
auto application = em_state.application.get();
#else
auto application = factory->create(options, context);
#endif
if (!application)
return EXIT_FAILURE;
application->on_event(app::resize_event{window.size()});
window.show();
log::info() << "Started in " << util::pretty(clock.duration(), std::chrono::milliseconds{1});
log::info() << "Running";
SDL_StopTextInput();
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop([]{
if (sdl2::poll_events(*em_state.application))
em_state.application->stop();
if (!em_state.application->running())
emscripten_cancel_main_loop();
em_state.application->update();
em_state.application->present();
em_state.window->swap();
}, 0, 1);
#else
while (application->running())
{
if (sdl2::poll_events(*application))
application->stop();
if (!application->running()) break;
application->update();
application->present();
window.swap();
}
log::info() << "Quitting";
#endif
return EXIT_SUCCESS;
}
catch (psemek::util::exception const & e)
{
psemek::log::error() << e;
return EXIT_FAILURE;
}
catch (std::exception const & e)
{
psemek::log::error() << e.what();
return EXIT_FAILURE;
}
catch (...)
{
psemek::log::error() << "Unknown exception";
throw;
}