#include "Entrypoint/Backend.hpp" #include "Model/GlobalStates.hpp" #include "UI/Localization.hpp" #include "UI/States.hpp" #include "UI/UI.hpp" #include "Utils/I18n.hpp" #include "Utils/ScopeGuard.hpp" #include "Utils/Sigslot.hpp" #include #include #include #include #include #include #include #include #include namespace fs = std::filesystem; using namespace std::literals::string_literals; using namespace std::literals::string_view_literals; static std::unique_ptr CreateDefaultBackend() { #if PLATFORM_WIN32 # if BUILD_CORE_WITH_DX12_BACKEND if (auto backend = RenderingBackend::CreateDx12Backend()) { return backend; } # endif # if BUILD_CORE_WITH_DX11_BACKEND if (auto backend = RenderingBackend::CreateDx11Backend()) { return backend; } # endif # if BUILD_CORE_WITH_VULKAN_BACKEND if (auto backend = RenderingBackend::CreateVulkanBackend()) { return backend; } # endif # if BUILD_CORE_WITH_OPENGL3_BACKEND if (auto backend = RenderingBackend::CreateOpenGL3Backend()) { return backend; } # endif # if BUILD_CORE_WITH_OPENGL2_BACKEND if (auto backend = RenderingBackend::CreateOpenGL2Backend()) { return backend; } # endif #elif PLATFORM_MACOS // We currently only support using metal on macos return RenderingBackend::CreateMetalBackend(); #elif PLATFORM_LINUX # if BUILD_CORE_WITH_VULKAN_BACKEND if (auto backend = RenderingBackend::CreateVulkanBackend()) { return backend; } # endif # if BUILD_CORE_WITH_OPENGL3_BACKEND if (auto backend = RenderingBackend::CreateOpenGL3Backend()) { return backend; } # endif # if BUILD_CORE_WITH_OPENGL2_BACKEND if (auto backend = RenderingBackend::CreateOpenGL2Backend()) { return backend; } # endif #endif return nullptr; } static std::unique_ptr CreateBackend(std::string_view option) { if (option == "default") { return CreateDefaultBackend(); } else if (option == "opengl2") { return RenderingBackend::CreateOpenGL2Backend(); } else if (option == "opengl3") { return RenderingBackend::CreateOpenGL3Backend(); } else if (option == "vulkan") { return RenderingBackend::CreateVulkanBackend(); } else if (option == "dx11") { return RenderingBackend::CreateDx11Backend(); } else if (option == "dx12") { return RenderingBackend::CreateDx12Backend(); } else if (option == "metal") { return RenderingBackend::CreateMetalBackend(); } else { std::string message; message += "Unknown backend '"; message += option; message += "'.\n"; throw std::runtime_error(message); } } int main(int argc, char* argv[]) { argparse::ArgumentParser parser; parser.add_argument("--global-data-directory") .help("Directory in which global data (such as recently used projects) are saved to. Use 'default' to use the default directory on each platform.") .default_value("default"s); parser.add_argument("--rendering-backend") .help("Which rendering backend to use. If equals 'default', the preferred API for each platform will be used") .default_value("default"s); try { parser.parse_args(argc, argv); } catch (const std::runtime_error& error) { std::cout << error.what() << '\n'; std::cout << parser; return -1; } auto backendOption = parser.get("--rendering-backend"); auto backend = CreateBackend(backendOption); auto& io = ImGui::GetIO(); // Disable saving window positions io.IniFilename = nullptr; // Disable log (dump widget tree) file, we don't trigger it but just to be safe io.LogFilename = nullptr; // Light mode because all major OS's default theme is white // TODO follow system theme ImGui::StyleColorsLight(); // Configure default fonts { // Includes latin alphabet, although for some reason smaller than if rendered using 18 point NotoSans regular io.Fonts->AddFontFromFileTTF("fonts/NotoSansSC-Regular.otf", 18, nullptr, io.Fonts->GetGlyphRangesChineseFull()); ImWchar iconRanges[] = { ICON_MIN_FA, ICON_MAX_FA }; ImFontConfig config; config.MergeMode = true; io.Fonts->AddFontFromFileTTF("fonts/FontAwesome5-Solid.otf", 14, &config, iconRanges); } // Initialize localization utilities { I18n::OnLanguageChange.Connect([]() { LocaleStrings::Instance = std::make_unique(); }); // Do i18n initialization after linking reload signals, so that when SetLanguage() is called, the locale strings will be initialized (without us writing the code another time outside the slot) I18n::Init(); I18n::SetLanguage("zh_CN"); // All of our usage are cached in XxxTranslation objects, no need to keep key -> entry mappings anymore I18n::Unload(); } auto dataDirOption = parser.get("--global-data-directory"); if (dataDirOption == "default") { GlobalStates::Init(); } else { fs::path path(dataDirOption); if (fs::exists(path)) { GlobalStates::Init(std::move(path)); } else { GlobalStates::Init(); } } DEFER { GlobalStates::Shutdown(); }; UIState::Init(); DEFER { UIState::Shutdown(); }; // Main loop backend->RunUntilWindowClose(&UI::MainWindow); return 0; }