#include "glfw_view.hpp" #include "glfw_renderer_frontend.hpp" #include "settings_json.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { GLFWView* view = nullptr; } // namespace void quit_handler(int) { if (view) { mbgl::Log::Info(mbgl::Event::Setup, "waiting for quit..."); view->setShouldClose(); } else { exit(0); } } int main(int argc, char* argv[]) { args::ArgumentParser argumentParser("MapLibre Native GLFW example"); args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", {'h', "help"}); args::Flag fullscreenFlag(argumentParser, "fullscreen", "Toggle fullscreen", {'f', "fullscreen"}); args::Flag benchmarkFlag(argumentParser, "benchmark", "Toggle benchmark", {'b', "benchmark"}); args::Flag offlineFlag(argumentParser, "offline", "Toggle offline", {'o', "offline"}); args::ValueFlag testDirValue( argumentParser, "directory", "Root directory for test generation", {"testDir"}); args::ValueFlag backendValue(argumentParser, "backend", "Rendering backend", {"backend"}); args::ValueFlag apikeyValue(argumentParser, "key", "API key", {'t', "apikey"}); args::ValueFlag styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"}); args::ValueFlag cacheDBValue(argumentParser, "file", "Cache database file name", {'c', "cache"}); args::ValueFlag actionJournalDirValue( argumentParser, "directory", "Action journal log directory", {"actionJournalDir"}); args::ValueFlag lonValue(argumentParser, "degrees", "Longitude", {'x', "lon"}); args::ValueFlag latValue(argumentParser, "degrees", "Latitude", {'y', "lat"}); args::ValueFlag altValue(argumentParser, "degrees", "Altitude", {'a', "alt"}); args::ValueFlag fovValue(argumentParser, "degrees", "FOV", {'F', "fov"}); args::ValueFlag zoomValue(argumentParser, "number", "Zoom level", {'z', "zoom"}); args::ValueFlag bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"}); args::ValueFlag pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"}); args::ValueFlag rollValue(argumentParser, "degrees", "Roll", {'r', "roll"}); args::ValueFlag maxPitchValue(argumentParser, "degrees", "Max Pitch", {'P', "maxPitch"}); try { argumentParser.ParseCLI(argc, argv); } catch (const args::Help&) { std::cout << argumentParser; exit(0); } catch (const args::ParseError& e) { std::cerr << e.what() << std::endl; std::cerr << argumentParser; exit(1); } catch (const args::ValidationError& e) { std::cerr << e.what() << std::endl; std::cerr << argumentParser; exit(2); } // Load settings mbgl::Settings_JSON settings; settings.online = !offlineFlag; if (lonValue) settings.longitude = args::get(lonValue); if (latValue) settings.latitude = args::get(latValue); if (altValue) settings.altitude = args::get(altValue); if (fovValue) settings.fov = args::get(fovValue); if (maxPitchValue) settings.maxPitch = args::get(maxPitchValue); if (zoomValue) settings.zoom = args::get(zoomValue); if (bearingValue) settings.bearing = args::get(bearingValue); if (pitchValue) settings.pitch = args::get(pitchValue); if (rollValue) settings.roll = args::get(rollValue); const bool fullscreen = fullscreenFlag ? args::get(fullscreenFlag) : false; const bool benchmark = benchmarkFlag ? args::get(benchmarkFlag) : false; std::string style = styleValue ? args::get(styleValue) : ""; const std::string cacheDB = cacheDBValue ? args::get(cacheDBValue) : "/tmp/mbgl-cache.db"; // sigint handling #ifdef WIN32 signal(SIGINT, &quit_handler); #else struct sigaction sigIntHandler; sigIntHandler.sa_handler = quit_handler; sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags = 0; sigaction(SIGINT, &sigIntHandler, nullptr); #endif if (benchmark) { mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled."); } // Set access token if present const char* apikeyEnv = getenv("MLN_API_KEY"); const std::string apikey = apikeyValue ? args::get(apikeyValue) : (apikeyEnv ? apikeyEnv : std::string()); auto mapTilerConfiguration = mbgl::TileServerOptions::MapTilerConfiguration(); mbgl::ResourceOptions resourceOptions; resourceOptions.withCachePath(cacheDB).withApiKey(apikey).withTileServerOptions(mapTilerConfiguration); mbgl::ClientOptions clientOptions; auto orderedStyles = mapTilerConfiguration.defaultStyles(); GLFWView backend(fullscreen, benchmark, resourceOptions, clientOptions); view = &backend; std::shared_ptr onlineFileSource = mbgl::FileSourceManager::get()->getFileSource( mbgl::FileSourceType::Network, resourceOptions, clientOptions); if (!settings.online) { if (onlineFileSource) { onlineFileSource->setProperty("online-status", false); mbgl::Log::Warning(mbgl::Event::Setup, "Application is offline. Press `O` to toggle online status."); } else { mbgl::Log::Warning(mbgl::Event::Setup, "Network resource provider is not available, only local " "requests are supported."); } } GLFWRendererFrontend rendererFrontend{ std::make_unique(view->getRendererBackend(), view->getPixelRatio()), *view}; // Configure action journal options if directory is specified mbgl::util::ActionJournalOptions actionJournalOptions; if (actionJournalDirValue) { const std::string actionJournalDir = args::get(actionJournalDirValue); actionJournalOptions.enable(true).withPath(actionJournalDir); mbgl::Log::Info(mbgl::Event::General, "Action journal enabled. Logs will be written to: " + actionJournalDir); } mbgl::Map map(rendererFrontend, *view, mbgl::MapOptions().withSize(view->getSize()).withPixelRatio(view->getPixelRatio()), resourceOptions, clientOptions, actionJournalOptions); map.setBounds(mbgl::BoundOptions().withMaxPitch(settings.maxPitch)); backend.setMap(&map); if (!style.empty() && style.find("://") == std::string::npos) { style = std::string("file://") + style; } map.jumpTo(mbgl::CameraOptions() .withCenter(mbgl::LatLng{settings.latitude, settings.longitude}) .withCenterAltitude(settings.altitude) .withZoom(settings.zoom) .withBearing(settings.bearing) .withPitch(settings.pitch) .withRoll(settings.roll) .withFov(settings.fov)); map.setDebug(mbgl::MapDebugOptions(settings.debug)); if (testDirValue) view->setTestDirectory(args::get(testDirValue)); view->setOnlineStatusCallback([&settings, onlineFileSource]() { if (!onlineFileSource) { mbgl::Log::Warning(mbgl::Event::Setup, "Cannot change online status. Network resource provider is not " "available."); return; } settings.online = !settings.online; onlineFileSource->setProperty("online-status", settings.online); mbgl::Log::Info(mbgl::Event::Setup, std::string("Application is ") + (settings.online ? "online" : "offline") + ". Press `O` to toggle online status."); }); view->setChangeStyleCallback([&map, &orderedStyles]() { static uint8_t currentStyleIndex; if (++currentStyleIndex == orderedStyles.size()) { currentStyleIndex = 0; } mbgl::util::DefaultStyle newStyle = orderedStyles[currentStyleIndex]; map.getStyle().loadURL(newStyle.getUrl()); view->setWindowTitle(newStyle.getName()); mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: " + newStyle.getName()); }); // Resource loader controls top-level request processing and can resume / // pause all managed sources simultaneously. std::shared_ptr resourceLoader = mbgl::FileSourceManager::get()->getFileSource( mbgl::FileSourceType::ResourceLoader, resourceOptions, clientOptions); view->setPauseResumeCallback([resourceLoader]() { static bool isPaused = false; if (isPaused) { resourceLoader->resume(); } else { resourceLoader->pause(); } isPaused = !isPaused; }); // Database file source. auto databaseFileSource = std::static_pointer_cast(std::shared_ptr( mbgl::FileSourceManager::get()->getFileSource(mbgl::FileSourceType::Database, resourceOptions, clientOptions))); view->setResetCacheCallback([databaseFileSource]() { databaseFileSource->resetDatabase([](const std::exception_ptr& ex) { if (ex) { mbgl::Log::Error(mbgl::Event::Database, "Failed to reset cache: " + mbgl::util::toString(ex)); } }); }); // Load style if (style.empty()) { const char* url = getenv("MLN_STYLE_URL"); if (url == nullptr) { style = "https://tiles.openfreemap.org/styles/liberty"; view->setWindowTitle("OpenFreeMap Liberty"); } else { style = url; view->setWindowTitle(url); } } map.getStyle().loadURL(style); view->run(); // Save settings mbgl::CameraOptions camera = map.getCameraOptions(); settings.latitude = camera.center->latitude(); settings.longitude = camera.center->longitude(); settings.altitude = *camera.centerAltitude; settings.zoom = *camera.zoom; settings.bearing = *camera.bearing; settings.pitch = *camera.pitch; settings.roll = *camera.roll; settings.fov = *camera.fov; settings.debug = mbgl::EnumType(map.getDebug()); settings.save(); mbgl::Log::Info(mbgl::Event::General, "Exit location: --lat=\"" + std::to_string(settings.latitude) + "\" --lon=\"" + std::to_string(settings.longitude) + "\" --alt=\"" + std::to_string(settings.altitude) + "\" --zoom=\"" + std::to_string(settings.zoom) + "\" --bearing=\"" + std::to_string(settings.bearing) + "\" --roll=\"" + std::to_string(settings.roll) + "\" --fov=\"" + std::to_string(settings.fov) + "\" --maxPitch=\"" + std::to_string(settings.maxPitch) + "\""); view = nullptr; return 0; }