From 67ed3ae3eb25e5bb0ec2d0369d042438bd9b2c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 22 Nov 2016 12:29:50 +0100 Subject: [build] move GLFW-related files to platform/glfw --- platform/default/glfw_view.cpp | 629 ------------------------------------ platform/default/settings_json.cpp | 41 --- platform/glfw/glfw_view.cpp | 630 +++++++++++++++++++++++++++++++++++++ platform/glfw/glfw_view.hpp | 111 +++++++ platform/glfw/main.cpp | 190 +++++++++++ platform/glfw/settings_json.cpp | 41 +++ platform/glfw/settings_json.hpp | 24 ++ 7 files changed, 996 insertions(+), 670 deletions(-) delete mode 100644 platform/default/glfw_view.cpp delete mode 100644 platform/default/settings_json.cpp create mode 100644 platform/glfw/glfw_view.cpp create mode 100644 platform/glfw/glfw_view.hpp create mode 100644 platform/glfw/main.cpp create mode 100644 platform/glfw/settings_json.cpp create mode 100644 platform/glfw/settings_json.hpp (limited to 'platform') diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp deleted file mode 100644 index 07959b2002..0000000000 --- a/platform/default/glfw_view.cpp +++ /dev/null @@ -1,629 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -void glfwError(int error, const char *description) { - mbgl::Log::Error(mbgl::Event::OpenGL, "GLFW error (%i): %s", error, description); - assert(false); -} - -GLFWView::GLFWView(bool fullscreen_, bool benchmark_) - : fullscreen(fullscreen_), benchmark(benchmark_) { - glfwSetErrorCallback(glfwError); - - std::srand(std::time(nullptr)); - - if (!glfwInit()) { - mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize glfw"); - exit(1); - } - - GLFWmonitor *monitor = nullptr; - if (fullscreen) { - monitor = glfwGetPrimaryMonitor(); - auto videoMode = glfwGetVideoMode(monitor); - width = videoMode->width; - height = videoMode->height; - } - -#ifdef DEBUG - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); -#endif - -#ifdef GL_ES_VERSION_2_0 - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); -#endif - - glfwWindowHint(GLFW_RED_BITS, 8); - glfwWindowHint(GLFW_GREEN_BITS, 8); - glfwWindowHint(GLFW_BLUE_BITS, 8); - glfwWindowHint(GLFW_ALPHA_BITS, 8); - glfwWindowHint(GLFW_STENCIL_BITS, 8); - glfwWindowHint(GLFW_DEPTH_BITS, 16); - - window = glfwCreateWindow(width, height, "Mapbox GL", monitor, nullptr); - if (!window) { - glfwTerminate(); - mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize window"); - exit(1); - } - - glfwSetWindowUserPointer(window, this); - glfwMakeContextCurrent(window); - if (benchmark) { - // Disables vsync on platforms that support it. - glfwSwapInterval(0); - } else { - glfwSwapInterval(1); - } - - - glfwSetCursorPosCallback(window, onMouseMove); - glfwSetMouseButtonCallback(window, onMouseClick); - glfwSetWindowSizeCallback(window, onWindowResize); - glfwSetFramebufferSizeCallback(window, onFramebufferResize); - glfwSetScrollCallback(window, onScroll); - glfwSetKeyCallback(window, onKey); - - mbgl::gl::InitializeExtensions(glfwGetProcAddress); - - glfwGetWindowSize(window, &width, &height); - glfwGetFramebufferSize(window, &fbWidth, &fbHeight); - pixelRatio = static_cast(fbWidth) / width; - - glfwMakeContextCurrent(nullptr); - - printf("\n"); - printf("================================================================================\n"); - printf("\n"); - printf("- Press `S` to cycle through bundled styles\n"); - printf("- Press `X` to reset the transform\n"); - printf("- Press `N` to reset north\n"); - printf("- Press `R` to toggle any available `night` style class\n"); - printf("- Press `Z` to cycle through north orientations\n"); - printf("- Prezz `X` to cycle through the viewport modes\n"); - printf("- Press `A` to cycle through Mapbox offices in the world + dateline monument\n"); - printf("- Press `B` to cycle through the color, stencil, and depth buffer\n"); - printf("\n"); - printf("- Press `1` through `6` to add increasing numbers of point annotations for testing\n"); - printf("- Press `7` through `0` to add increasing numbers of shape annotations for testing\n"); - printf("\n"); - printf("- Press `Q` to remove annotations\n"); - printf("- Press `P` to add a random custom runtime imagery annotation\n"); - printf("- Press `L` to add a random line annotation\n"); - printf("- Press `W` to pop the last-added annotation off\n"); - printf("\n"); - printf("- `Control` + mouse drag to rotate\n"); - printf("- `Shift` + mouse drag to tilt\n"); - printf("\n"); - printf("- Press `Tab` to cycle through the map debug options\n"); - printf("- Press `Esc` to quit\n"); - printf("\n"); - printf("================================================================================\n"); - printf("\n"); -} - -GLFWView::~GLFWView() { - glfwDestroyWindow(window); - glfwTerminate(); -} - -void GLFWView::setMap(mbgl::Map *map_) { - map = map_; - map->addAnnotationIcon("default_marker", makeSpriteImage(22, 22, 1)); -} - -void GLFWView::updateViewBinding() { - getContext().bindFramebuffer.setCurrentValue(0); - assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); - getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() }); - assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); -} - -void GLFWView::bind() { - getContext().bindFramebuffer = 0; - getContext().viewport = { 0, 0, getFramebufferSize() }; -} - -void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { - GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - - if (action == GLFW_RELEASE) { - switch (key) { - case GLFW_KEY_ESCAPE: - glfwSetWindowShouldClose(window, true); - break; - case GLFW_KEY_TAB: - view->map->cycleDebugOptions(); - break; - case GLFW_KEY_X: - if (!mods) - view->map->resetPosition(); - break; - case GLFW_KEY_S: - if (view->changeStyleCallback) - view->changeStyleCallback(); - break; - case GLFW_KEY_R: - if (!mods) { - static const mbgl::style::TransitionOptions transition { { mbgl::Milliseconds(300) } }; - view->map->setTransitionOptions(transition); - if (view->map->hasClass("night")) { - view->map->removeClass("night"); - } else { - view->map->addClass("night"); - } - } - break; -#if not MBGL_USE_GLES2 - case GLFW_KEY_B: { - auto debug = view->map->getDebug(); - if (debug & mbgl::MapDebugOptions::StencilClip) { - debug &= ~mbgl::MapDebugOptions::StencilClip; - debug |= mbgl::MapDebugOptions::DepthBuffer; - } else if (debug & mbgl::MapDebugOptions::DepthBuffer) { - debug &= ~mbgl::MapDebugOptions::DepthBuffer; - } else { - debug |= mbgl::MapDebugOptions::StencilClip; - } - view->map->setDebug(debug); - } break; -#endif // MBGL_USE_GLES2 - case GLFW_KEY_N: - if (!mods) - view->map->resetNorth(); - break; - case GLFW_KEY_Z: - view->nextOrientation(); - break; - case GLFW_KEY_Q: { - auto result = view->map->queryPointAnnotations({ {}, { double(view->getSize().width), double(view->getSize().height) } }); - printf("visible point annotations: %lu\n", result.size()); - } break; - case GLFW_KEY_C: - view->clearAnnotations(); - break; - case GLFW_KEY_P: - view->addRandomCustomPointAnnotations(1); - break; - case GLFW_KEY_L: - view->addRandomLineAnnotations(1); - break; - case GLFW_KEY_A: { - // XXX Fix precision loss in flyTo: - // https://github.com/mapbox/mapbox-gl-native/issues/4298 - static const std::vector places = { - mbgl::LatLng { -16.796665, -179.999983 }, // Dateline monument - mbgl::LatLng { 12.9810542, 77.6345551 }, // Mapbox Bengaluru, India - mbgl::LatLng { -13.15607,-74.21773 }, // Mapbox Peru - mbgl::LatLng { 37.77572, -122.4158818 }, // Mapbox SF, USA - mbgl::LatLng { 38.91318,-77.03255 }, // Mapbox DC, USA - }; - static size_t nextPlace = 0; - mbgl::CameraOptions cameraOptions; - cameraOptions.center = places[nextPlace++]; - cameraOptions.zoom = 20; - cameraOptions.pitch = 30; - - mbgl::AnimationOptions animationOptions(mbgl::Seconds(10)); - view->map->flyTo(cameraOptions, animationOptions); - nextPlace = nextPlace % places.size(); - } break; - } - } - - if (action == GLFW_RELEASE || action == GLFW_REPEAT) { - switch (key) { - case GLFW_KEY_W: view->popAnnotation(); break; - case GLFW_KEY_1: view->addRandomPointAnnotations(1); break; - case GLFW_KEY_2: view->addRandomPointAnnotations(10); break; - case GLFW_KEY_3: view->addRandomPointAnnotations(100); break; - case GLFW_KEY_4: view->addRandomPointAnnotations(1000); break; - case GLFW_KEY_5: view->addRandomPointAnnotations(10000); break; - case GLFW_KEY_6: view->addRandomPointAnnotations(100000); break; - case GLFW_KEY_7: view->addRandomShapeAnnotations(1); break; - case GLFW_KEY_8: view->addRandomShapeAnnotations(10); break; - case GLFW_KEY_9: view->addRandomShapeAnnotations(100); break; - case GLFW_KEY_0: view->addRandomShapeAnnotations(1000); break; - } - } -} - -mbgl::Color GLFWView::makeRandomColor() const { - const float r = 1.0f * (float(std::rand()) / RAND_MAX); - const float g = 1.0f * (float(std::rand()) / RAND_MAX); - const float b = 1.0f * (float(std::rand()) / RAND_MAX); - return { r, g, b, 1.0f }; -} - -mbgl::Point GLFWView::makeRandomPoint() const { - const double x = width * double(std::rand()) / RAND_MAX; - const double y = height * double(std::rand()) / RAND_MAX; - mbgl::LatLng latLng = map->latLngForPixel({ x, y }); - return { latLng.longitude, latLng.latitude }; -} - -std::shared_ptr -GLFWView::makeSpriteImage(int width, int height, float pixelRatio) { - const int r = 255 * (double(std::rand()) / RAND_MAX); - const int g = 255 * (double(std::rand()) / RAND_MAX); - const int b = 255 * (double(std::rand()) / RAND_MAX); - - const int w = std::ceil(pixelRatio * width); - const int h = std::ceil(pixelRatio * height); - - mbgl::PremultipliedImage image({ static_cast(w), static_cast(h) }); - auto data = reinterpret_cast(image.data.get()); - const int dist = (w / 2) * (w / 2); - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - const int dx = x - w / 2; - const int dy = y - h / 2; - const int diff = dist - (dx * dx + dy * dy); - if (diff > 0) { - const int a = std::min(0xFF, diff) * 0xFF / dist; - // Premultiply the rgb values with alpha - data[w * y + x] = - (a << 24) | ((a * r / 0xFF) << 16) | ((a * g / 0xFF) << 8) | (a * b / 0xFF); - } - } - } - - return std::make_shared(std::move(image), pixelRatio); -} - -void GLFWView::nextOrientation() { - using NO = mbgl::NorthOrientation; - switch (map->getNorthOrientation()) { - case NO::Upwards: map->setNorthOrientation(NO::Rightwards); break; - case NO::Rightwards: map->setNorthOrientation(NO::Downwards); break; - case NO::Downwards: map->setNorthOrientation(NO::Leftwards); break; - default: map->setNorthOrientation(NO::Upwards); break; - } -} - -void GLFWView::addRandomCustomPointAnnotations(int count) { - for (int i = 0; i < count; i++) { - static int spriteID = 1; - const auto name = std::string{ "marker-" } + mbgl::util::toString(spriteID++); - map->addAnnotationIcon(name, makeSpriteImage(22, 22, 1)); - spriteIDs.push_back(name); - annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), name })); - } -} - -void GLFWView::addRandomPointAnnotations(int count) { - for (int i = 0; i < count; ++i) { - annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), "default_marker" })); - } -} - -void GLFWView::addRandomLineAnnotations(int count) { - for (int i = 0; i < count; ++i) { - mbgl::LineString lineString; - for (int j = 0; j < 3; ++j) { - lineString.push_back(makeRandomPoint()); - } - annotationIDs.push_back(map->addAnnotation(mbgl::LineAnnotation { lineString, 1.0f, 2.0f, { makeRandomColor() } })); - } -} - -void GLFWView::addRandomShapeAnnotations(int count) { - for (int i = 0; i < count; ++i) { - mbgl::Polygon triangle; - triangle.push_back({ makeRandomPoint(), makeRandomPoint(), makeRandomPoint() }); - annotationIDs.push_back(map->addAnnotation(mbgl::FillAnnotation { triangle, 0.5f, { makeRandomColor() }, { makeRandomColor() } })); - } -} - -void GLFWView::clearAnnotations() { - for (const auto& id : annotationIDs) { - map->removeAnnotation(id); - } - - annotationIDs.clear(); -} - -void GLFWView::popAnnotation() { - if (annotationIDs.empty()) { - return; - } - - map->removeAnnotation(annotationIDs.back()); - annotationIDs.pop_back(); -} - -void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) { - GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - double delta = yOffset * 40; - - bool isWheel = delta != 0 && std::fmod(delta, 4.000244140625) == 0; - - double absDelta = delta < 0 ? -delta : delta; - double scale = 2.0 / (1.0 + std::exp(-absDelta / 100.0)); - - // Make the scroll wheel a bit slower. - if (!isWheel) { - scale = (scale - 1.0) / 2.0 + 1.0; - } - - // Zooming out. - if (delta < 0 && scale != 0) { - scale = 1.0 / scale; - } - - view->map->scaleBy(scale, mbgl::ScreenCoordinate { view->lastX, view->lastY }); -} - -void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { - GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - view->width = width; - view->height = height; - view->map->setSize({ static_cast(view->width), static_cast(view->height) }); -} - -void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { - GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - view->fbWidth = width; - view->fbHeight = height; - - // This is only triggered when the framebuffer is resized, but not the window. It can - // happen when you move the window between screens with a different pixel ratio. - // We are forcing a repaint my invalidating the view, which triggers a rerender with the - // new framebuffer dimensions. - view->invalidate(); -} - -void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) { - GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - - if (button == GLFW_MOUSE_BUTTON_RIGHT || - (button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) { - view->rotating = action == GLFW_PRESS; - view->map->setGestureInProgress(view->rotating); - } else if (button == GLFW_MOUSE_BUTTON_LEFT && (modifiers & GLFW_MOD_SHIFT)) { - view->pitching = action == GLFW_PRESS; - view->map->setGestureInProgress(view->pitching); - } else if (button == GLFW_MOUSE_BUTTON_LEFT) { - view->tracking = action == GLFW_PRESS; - view->map->setGestureInProgress(view->tracking); - - if (action == GLFW_RELEASE) { - double now = glfwGetTime(); - if (now - view->lastClick < 0.4 /* ms */) { - if (modifiers & GLFW_MOD_SHIFT) { - view->map->scaleBy(0.5, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::Milliseconds(500)); - } else { - view->map->scaleBy(2.0, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::Milliseconds(500)); - } - } - view->lastClick = now; - } - } -} - -void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) { - GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - if (view->tracking) { - double dx = x - view->lastX; - double dy = y - view->lastY; - if (dx || dy) { - view->map->setLatLng( - view->map->latLngForPixel(mbgl::ScreenCoordinate(x - dx, y - dy)), - mbgl::ScreenCoordinate(x, y)); - } - } else if (view->rotating) { - view->map->rotateBy({ view->lastX, view->lastY }, { x, y }); - } else if (view->pitching) { - const double dy = y - view->lastY; - if (dy) { - view->map->setPitch(view->map->getPitch() - dy / 2); - } - } - view->lastX = x; - view->lastY = y; -} - -void GLFWView::run() { - auto callback = [&] { - if (glfwWindowShouldClose(window)) { - runLoop.stop(); - return; - } - - glfwPollEvents(); - - if (dirty) { - const double started = glfwGetTime(); - - glfwMakeContextCurrent(window); - - updateViewBinding(); - map->render(*this); - - glfwSwapBuffers(window); - - report(1000 * (glfwGetTime() - started)); - if (benchmark) { - invalidate(); - } - - dirty = false; - } - }; - - frameTick.start(mbgl::Duration::zero(), mbgl::Milliseconds(1000 / 60), callback); -#if defined(__APPLE__) - while (!glfwWindowShouldClose(window)) runLoop.run(); -#else - runLoop.run(); -#endif -} - -float GLFWView::getPixelRatio() const { - return pixelRatio; -} - -mbgl::Size GLFWView::getSize() const { - return { static_cast(width), static_cast(height) }; -} - -mbgl::Size GLFWView::getFramebufferSize() const { - return { static_cast(fbWidth), static_cast(fbHeight) }; -} - -void GLFWView::activate() { - glfwMakeContextCurrent(window); -} - -void GLFWView::deactivate() { - glfwMakeContextCurrent(nullptr); -} - -void GLFWView::invalidate() { - dirty = true; - glfwPostEmptyEvent(); -} - -void GLFWView::report(float duration) { - frames++; - frameTime += duration; - - const double currentTime = glfwGetTime(); - if (currentTime - lastReported >= 1) { - frameTime /= frames; - mbgl::Log::Info(mbgl::Event::OpenGL, "Frame time: %6.2fms (%6.2f fps)", frameTime, - 1000 / frameTime); - frames = 0; - frameTime = 0; - lastReported = currentTime; - } -} - -void GLFWView::setChangeStyleCallback(std::function callback) { - changeStyleCallback = callback; -} - -void GLFWView::setShouldClose() { - glfwSetWindowShouldClose(window, true); - glfwPostEmptyEvent(); -} - -void GLFWView::setWindowTitle(const std::string& title) { - glfwSetWindowTitle(window, (std::string { "Mapbox GL: " } + title).c_str()); -} - -void GLFWView::setMapChangeCallback(std::function callback) { - this->mapChangeCallback = callback; -} - -void GLFWView::notifyMapChange(mbgl::MapChange change) { - if (mapChangeCallback) { - mapChangeCallback(change); - } -} - -namespace mbgl { -namespace platform { - -#ifndef GL_ES_VERSION_2_0 -void showDebugImage(std::string name, const char *data, size_t width, size_t height) { - glfwInit(); - - static GLFWwindow *debugWindow = nullptr; - if (!debugWindow) { - debugWindow = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr); - if (!debugWindow) { - glfwTerminate(); - fprintf(stderr, "Failed to initialize window\n"); - exit(1); - } - } - - GLFWwindow *currentWindow = glfwGetCurrentContext(); - - glfwSetWindowSize(debugWindow, width, height); - glfwMakeContextCurrent(debugWindow); - - int fbWidth, fbHeight; - glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight); - float scale = static_cast(fbWidth) / static_cast(width); - - { - gl::PreserveState pixelZoom; - gl::PreserveState rasterPos; - - MBGL_CHECK_ERROR(glPixelZoom(scale, -scale)); - MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f)); - MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data)); - } - - glfwSwapBuffers(debugWindow); - - glfwMakeContextCurrent(currentWindow); -} - -void showColorDebugImage(std::string name, const char *data, size_t logicalWidth, size_t logicalHeight, size_t width, size_t height) { - glfwInit(); - - static GLFWwindow *debugWindow = nullptr; - if (!debugWindow) { - debugWindow = glfwCreateWindow(logicalWidth, logicalHeight, name.c_str(), nullptr, nullptr); - if (!debugWindow) { - glfwTerminate(); - fprintf(stderr, "Failed to initialize window\n"); - exit(1); - } - } - - GLFWwindow *currentWindow = glfwGetCurrentContext(); - - glfwSetWindowSize(debugWindow, logicalWidth, logicalHeight); - glfwMakeContextCurrent(debugWindow); - - int fbWidth, fbHeight; - glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight); - float xScale = static_cast(fbWidth) / static_cast(width); - float yScale = static_cast(fbHeight) / static_cast(height); - - { - gl::PreserveState clearColor; - gl::PreserveState blend; - gl::PreserveState blendFunc; - gl::PreserveState pixelZoom; - gl::PreserveState rasterPos; - - MBGL_CHECK_ERROR(glClearColor(0.8, 0.8, 0.8, 1)); - MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT)); - MBGL_CHECK_ERROR(glEnable(GL_BLEND)); - MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - MBGL_CHECK_ERROR(glPixelZoom(xScale, -yScale)); - MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f)); - MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data)); - } - - glfwSwapBuffers(debugWindow); - - glfwMakeContextCurrent(currentWindow); -} -#endif - -} // namespace platform -} // namespace mbgl diff --git a/platform/default/settings_json.cpp b/platform/default/settings_json.cpp deleted file mode 100644 index ef53aa83e7..0000000000 --- a/platform/default/settings_json.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -namespace mbgl { - -Settings_JSON::Settings_JSON() { load(); } - -void Settings_JSON::load() { - std::ifstream file("/tmp/mbgl-native.cfg"); - if (file) { - file >> longitude; - file >> latitude; - file >> zoom; - file >> bearing; - file >> pitch; - file >> debug; - } -} - -void Settings_JSON::save() { - std::ofstream file("/tmp/mbgl-native.cfg"); - if (file) { - file << longitude << std::endl; - file << latitude << std::endl; - file << zoom << std::endl; - file << bearing << std::endl; - file << pitch << std::endl; - file << debug << std::endl; - } -} - -void Settings_JSON::clear() { - longitude = 0; - latitude = 0; - zoom = 0; - bearing = 0; - pitch = 0; - debug = 0; -} - -} // namespace mbgl diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp new file mode 100644 index 0000000000..ecc5e73da1 --- /dev/null +++ b/platform/glfw/glfw_view.cpp @@ -0,0 +1,630 @@ +#include "glfw_view.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +void glfwError(int error, const char *description) { + mbgl::Log::Error(mbgl::Event::OpenGL, "GLFW error (%i): %s", error, description); + assert(false); +} + +GLFWView::GLFWView(bool fullscreen_, bool benchmark_) + : fullscreen(fullscreen_), benchmark(benchmark_) { + glfwSetErrorCallback(glfwError); + + std::srand(std::time(nullptr)); + + if (!glfwInit()) { + mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize glfw"); + exit(1); + } + + GLFWmonitor *monitor = nullptr; + if (fullscreen) { + monitor = glfwGetPrimaryMonitor(); + auto videoMode = glfwGetVideoMode(monitor); + width = videoMode->width; + height = videoMode->height; + } + +#ifdef DEBUG + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); +#endif + +#ifdef GL_ES_VERSION_2_0 + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); +#endif + + glfwWindowHint(GLFW_RED_BITS, 8); + glfwWindowHint(GLFW_GREEN_BITS, 8); + glfwWindowHint(GLFW_BLUE_BITS, 8); + glfwWindowHint(GLFW_ALPHA_BITS, 8); + glfwWindowHint(GLFW_STENCIL_BITS, 8); + glfwWindowHint(GLFW_DEPTH_BITS, 16); + + window = glfwCreateWindow(width, height, "Mapbox GL", monitor, nullptr); + if (!window) { + glfwTerminate(); + mbgl::Log::Error(mbgl::Event::OpenGL, "failed to initialize window"); + exit(1); + } + + glfwSetWindowUserPointer(window, this); + glfwMakeContextCurrent(window); + if (benchmark) { + // Disables vsync on platforms that support it. + glfwSwapInterval(0); + } else { + glfwSwapInterval(1); + } + + + glfwSetCursorPosCallback(window, onMouseMove); + glfwSetMouseButtonCallback(window, onMouseClick); + glfwSetWindowSizeCallback(window, onWindowResize); + glfwSetFramebufferSizeCallback(window, onFramebufferResize); + glfwSetScrollCallback(window, onScroll); + glfwSetKeyCallback(window, onKey); + + mbgl::gl::InitializeExtensions(glfwGetProcAddress); + + glfwGetWindowSize(window, &width, &height); + glfwGetFramebufferSize(window, &fbWidth, &fbHeight); + pixelRatio = static_cast(fbWidth) / width; + + glfwMakeContextCurrent(nullptr); + + printf("\n"); + printf("================================================================================\n"); + printf("\n"); + printf("- Press `S` to cycle through bundled styles\n"); + printf("- Press `X` to reset the transform\n"); + printf("- Press `N` to reset north\n"); + printf("- Press `R` to toggle any available `night` style class\n"); + printf("- Press `Z` to cycle through north orientations\n"); + printf("- Prezz `X` to cycle through the viewport modes\n"); + printf("- Press `A` to cycle through Mapbox offices in the world + dateline monument\n"); + printf("- Press `B` to cycle through the color, stencil, and depth buffer\n"); + printf("\n"); + printf("- Press `1` through `6` to add increasing numbers of point annotations for testing\n"); + printf("- Press `7` through `0` to add increasing numbers of shape annotations for testing\n"); + printf("\n"); + printf("- Press `Q` to remove annotations\n"); + printf("- Press `P` to add a random custom runtime imagery annotation\n"); + printf("- Press `L` to add a random line annotation\n"); + printf("- Press `W` to pop the last-added annotation off\n"); + printf("\n"); + printf("- `Control` + mouse drag to rotate\n"); + printf("- `Shift` + mouse drag to tilt\n"); + printf("\n"); + printf("- Press `Tab` to cycle through the map debug options\n"); + printf("- Press `Esc` to quit\n"); + printf("\n"); + printf("================================================================================\n"); + printf("\n"); +} + +GLFWView::~GLFWView() { + glfwDestroyWindow(window); + glfwTerminate(); +} + +void GLFWView::setMap(mbgl::Map *map_) { + map = map_; + map->addAnnotationIcon("default_marker", makeSpriteImage(22, 22, 1)); +} + +void GLFWView::updateViewBinding() { + getContext().bindFramebuffer.setCurrentValue(0); + assert(mbgl::gl::value::BindFramebuffer::Get() == getContext().bindFramebuffer.getCurrentValue()); + getContext().viewport.setCurrentValue({ 0, 0, getFramebufferSize() }); + assert(mbgl::gl::value::Viewport::Get() == getContext().viewport.getCurrentValue()); +} + +void GLFWView::bind() { + getContext().bindFramebuffer = 0; + getContext().viewport = { 0, 0, getFramebufferSize() }; +} + +void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + + if (action == GLFW_RELEASE) { + switch (key) { + case GLFW_KEY_ESCAPE: + glfwSetWindowShouldClose(window, true); + break; + case GLFW_KEY_TAB: + view->map->cycleDebugOptions(); + break; + case GLFW_KEY_X: + if (!mods) + view->map->resetPosition(); + break; + case GLFW_KEY_S: + if (view->changeStyleCallback) + view->changeStyleCallback(); + break; + case GLFW_KEY_R: + if (!mods) { + static const mbgl::style::TransitionOptions transition { { mbgl::Milliseconds(300) } }; + view->map->setTransitionOptions(transition); + if (view->map->hasClass("night")) { + view->map->removeClass("night"); + } else { + view->map->addClass("night"); + } + } + break; +#if not MBGL_USE_GLES2 + case GLFW_KEY_B: { + auto debug = view->map->getDebug(); + if (debug & mbgl::MapDebugOptions::StencilClip) { + debug &= ~mbgl::MapDebugOptions::StencilClip; + debug |= mbgl::MapDebugOptions::DepthBuffer; + } else if (debug & mbgl::MapDebugOptions::DepthBuffer) { + debug &= ~mbgl::MapDebugOptions::DepthBuffer; + } else { + debug |= mbgl::MapDebugOptions::StencilClip; + } + view->map->setDebug(debug); + } break; +#endif // MBGL_USE_GLES2 + case GLFW_KEY_N: + if (!mods) + view->map->resetNorth(); + break; + case GLFW_KEY_Z: + view->nextOrientation(); + break; + case GLFW_KEY_Q: { + auto result = view->map->queryPointAnnotations({ {}, { double(view->getSize().width), double(view->getSize().height) } }); + printf("visible point annotations: %lu\n", result.size()); + } break; + case GLFW_KEY_C: + view->clearAnnotations(); + break; + case GLFW_KEY_P: + view->addRandomCustomPointAnnotations(1); + break; + case GLFW_KEY_L: + view->addRandomLineAnnotations(1); + break; + case GLFW_KEY_A: { + // XXX Fix precision loss in flyTo: + // https://github.com/mapbox/mapbox-gl-native/issues/4298 + static const std::vector places = { + mbgl::LatLng { -16.796665, -179.999983 }, // Dateline monument + mbgl::LatLng { 12.9810542, 77.6345551 }, // Mapbox Bengaluru, India + mbgl::LatLng { -13.15607,-74.21773 }, // Mapbox Peru + mbgl::LatLng { 37.77572, -122.4158818 }, // Mapbox SF, USA + mbgl::LatLng { 38.91318,-77.03255 }, // Mapbox DC, USA + }; + static size_t nextPlace = 0; + mbgl::CameraOptions cameraOptions; + cameraOptions.center = places[nextPlace++]; + cameraOptions.zoom = 20; + cameraOptions.pitch = 30; + + mbgl::AnimationOptions animationOptions(mbgl::Seconds(10)); + view->map->flyTo(cameraOptions, animationOptions); + nextPlace = nextPlace % places.size(); + } break; + } + } + + if (action == GLFW_RELEASE || action == GLFW_REPEAT) { + switch (key) { + case GLFW_KEY_W: view->popAnnotation(); break; + case GLFW_KEY_1: view->addRandomPointAnnotations(1); break; + case GLFW_KEY_2: view->addRandomPointAnnotations(10); break; + case GLFW_KEY_3: view->addRandomPointAnnotations(100); break; + case GLFW_KEY_4: view->addRandomPointAnnotations(1000); break; + case GLFW_KEY_5: view->addRandomPointAnnotations(10000); break; + case GLFW_KEY_6: view->addRandomPointAnnotations(100000); break; + case GLFW_KEY_7: view->addRandomShapeAnnotations(1); break; + case GLFW_KEY_8: view->addRandomShapeAnnotations(10); break; + case GLFW_KEY_9: view->addRandomShapeAnnotations(100); break; + case GLFW_KEY_0: view->addRandomShapeAnnotations(1000); break; + } + } +} + +mbgl::Color GLFWView::makeRandomColor() const { + const float r = 1.0f * (float(std::rand()) / RAND_MAX); + const float g = 1.0f * (float(std::rand()) / RAND_MAX); + const float b = 1.0f * (float(std::rand()) / RAND_MAX); + return { r, g, b, 1.0f }; +} + +mbgl::Point GLFWView::makeRandomPoint() const { + const double x = width * double(std::rand()) / RAND_MAX; + const double y = height * double(std::rand()) / RAND_MAX; + mbgl::LatLng latLng = map->latLngForPixel({ x, y }); + return { latLng.longitude, latLng.latitude }; +} + +std::shared_ptr +GLFWView::makeSpriteImage(int width, int height, float pixelRatio) { + const int r = 255 * (double(std::rand()) / RAND_MAX); + const int g = 255 * (double(std::rand()) / RAND_MAX); + const int b = 255 * (double(std::rand()) / RAND_MAX); + + const int w = std::ceil(pixelRatio * width); + const int h = std::ceil(pixelRatio * height); + + mbgl::PremultipliedImage image({ static_cast(w), static_cast(h) }); + auto data = reinterpret_cast(image.data.get()); + const int dist = (w / 2) * (w / 2); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + const int dx = x - w / 2; + const int dy = y - h / 2; + const int diff = dist - (dx * dx + dy * dy); + if (diff > 0) { + const int a = std::min(0xFF, diff) * 0xFF / dist; + // Premultiply the rgb values with alpha + data[w * y + x] = + (a << 24) | ((a * r / 0xFF) << 16) | ((a * g / 0xFF) << 8) | (a * b / 0xFF); + } + } + } + + return std::make_shared(std::move(image), pixelRatio); +} + +void GLFWView::nextOrientation() { + using NO = mbgl::NorthOrientation; + switch (map->getNorthOrientation()) { + case NO::Upwards: map->setNorthOrientation(NO::Rightwards); break; + case NO::Rightwards: map->setNorthOrientation(NO::Downwards); break; + case NO::Downwards: map->setNorthOrientation(NO::Leftwards); break; + default: map->setNorthOrientation(NO::Upwards); break; + } +} + +void GLFWView::addRandomCustomPointAnnotations(int count) { + for (int i = 0; i < count; i++) { + static int spriteID = 1; + const auto name = std::string{ "marker-" } + mbgl::util::toString(spriteID++); + map->addAnnotationIcon(name, makeSpriteImage(22, 22, 1)); + spriteIDs.push_back(name); + annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), name })); + } +} + +void GLFWView::addRandomPointAnnotations(int count) { + for (int i = 0; i < count; ++i) { + annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), "default_marker" })); + } +} + +void GLFWView::addRandomLineAnnotations(int count) { + for (int i = 0; i < count; ++i) { + mbgl::LineString lineString; + for (int j = 0; j < 3; ++j) { + lineString.push_back(makeRandomPoint()); + } + annotationIDs.push_back(map->addAnnotation(mbgl::LineAnnotation { lineString, 1.0f, 2.0f, { makeRandomColor() } })); + } +} + +void GLFWView::addRandomShapeAnnotations(int count) { + for (int i = 0; i < count; ++i) { + mbgl::Polygon triangle; + triangle.push_back({ makeRandomPoint(), makeRandomPoint(), makeRandomPoint() }); + annotationIDs.push_back(map->addAnnotation(mbgl::FillAnnotation { triangle, 0.5f, { makeRandomColor() }, { makeRandomColor() } })); + } +} + +void GLFWView::clearAnnotations() { + for (const auto& id : annotationIDs) { + map->removeAnnotation(id); + } + + annotationIDs.clear(); +} + +void GLFWView::popAnnotation() { + if (annotationIDs.empty()) { + return; + } + + map->removeAnnotation(annotationIDs.back()); + annotationIDs.pop_back(); +} + +void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + double delta = yOffset * 40; + + bool isWheel = delta != 0 && std::fmod(delta, 4.000244140625) == 0; + + double absDelta = delta < 0 ? -delta : delta; + double scale = 2.0 / (1.0 + std::exp(-absDelta / 100.0)); + + // Make the scroll wheel a bit slower. + if (!isWheel) { + scale = (scale - 1.0) / 2.0 + 1.0; + } + + // Zooming out. + if (delta < 0 && scale != 0) { + scale = 1.0 / scale; + } + + view->map->scaleBy(scale, mbgl::ScreenCoordinate { view->lastX, view->lastY }); +} + +void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + view->width = width; + view->height = height; + view->map->setSize({ static_cast(view->width), static_cast(view->height) }); +} + +void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + view->fbWidth = width; + view->fbHeight = height; + + // This is only triggered when the framebuffer is resized, but not the window. It can + // happen when you move the window between screens with a different pixel ratio. + // We are forcing a repaint my invalidating the view, which triggers a rerender with the + // new framebuffer dimensions. + view->invalidate(); +} + +void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + + if (button == GLFW_MOUSE_BUTTON_RIGHT || + (button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) { + view->rotating = action == GLFW_PRESS; + view->map->setGestureInProgress(view->rotating); + } else if (button == GLFW_MOUSE_BUTTON_LEFT && (modifiers & GLFW_MOD_SHIFT)) { + view->pitching = action == GLFW_PRESS; + view->map->setGestureInProgress(view->pitching); + } else if (button == GLFW_MOUSE_BUTTON_LEFT) { + view->tracking = action == GLFW_PRESS; + view->map->setGestureInProgress(view->tracking); + + if (action == GLFW_RELEASE) { + double now = glfwGetTime(); + if (now - view->lastClick < 0.4 /* ms */) { + if (modifiers & GLFW_MOD_SHIFT) { + view->map->scaleBy(0.5, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::Milliseconds(500)); + } else { + view->map->scaleBy(2.0, mbgl::ScreenCoordinate { view->lastX, view->lastY }, mbgl::Milliseconds(500)); + } + } + view->lastClick = now; + } + } +} + +void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) { + GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); + if (view->tracking) { + double dx = x - view->lastX; + double dy = y - view->lastY; + if (dx || dy) { + view->map->setLatLng( + view->map->latLngForPixel(mbgl::ScreenCoordinate(x - dx, y - dy)), + mbgl::ScreenCoordinate(x, y)); + } + } else if (view->rotating) { + view->map->rotateBy({ view->lastX, view->lastY }, { x, y }); + } else if (view->pitching) { + const double dy = y - view->lastY; + if (dy) { + view->map->setPitch(view->map->getPitch() - dy / 2); + } + } + view->lastX = x; + view->lastY = y; +} + +void GLFWView::run() { + auto callback = [&] { + if (glfwWindowShouldClose(window)) { + runLoop.stop(); + return; + } + + glfwPollEvents(); + + if (dirty) { + const double started = glfwGetTime(); + + glfwMakeContextCurrent(window); + + updateViewBinding(); + map->render(*this); + + glfwSwapBuffers(window); + + report(1000 * (glfwGetTime() - started)); + if (benchmark) { + invalidate(); + } + + dirty = false; + } + }; + + frameTick.start(mbgl::Duration::zero(), mbgl::Milliseconds(1000 / 60), callback); +#if defined(__APPLE__) + while (!glfwWindowShouldClose(window)) runLoop.run(); +#else + runLoop.run(); +#endif +} + +float GLFWView::getPixelRatio() const { + return pixelRatio; +} + +mbgl::Size GLFWView::getSize() const { + return { static_cast(width), static_cast(height) }; +} + +mbgl::Size GLFWView::getFramebufferSize() const { + return { static_cast(fbWidth), static_cast(fbHeight) }; +} + +void GLFWView::activate() { + glfwMakeContextCurrent(window); +} + +void GLFWView::deactivate() { + glfwMakeContextCurrent(nullptr); +} + +void GLFWView::invalidate() { + dirty = true; + glfwPostEmptyEvent(); +} + +void GLFWView::report(float duration) { + frames++; + frameTime += duration; + + const double currentTime = glfwGetTime(); + if (currentTime - lastReported >= 1) { + frameTime /= frames; + mbgl::Log::Info(mbgl::Event::OpenGL, "Frame time: %6.2fms (%6.2f fps)", frameTime, + 1000 / frameTime); + frames = 0; + frameTime = 0; + lastReported = currentTime; + } +} + +void GLFWView::setChangeStyleCallback(std::function callback) { + changeStyleCallback = callback; +} + +void GLFWView::setShouldClose() { + glfwSetWindowShouldClose(window, true); + glfwPostEmptyEvent(); +} + +void GLFWView::setWindowTitle(const std::string& title) { + glfwSetWindowTitle(window, (std::string { "Mapbox GL: " } + title).c_str()); +} + +void GLFWView::setMapChangeCallback(std::function callback) { + this->mapChangeCallback = callback; +} + +void GLFWView::notifyMapChange(mbgl::MapChange change) { + if (mapChangeCallback) { + mapChangeCallback(change); + } +} + +namespace mbgl { +namespace platform { + +#ifndef GL_ES_VERSION_2_0 +void showDebugImage(std::string name, const char *data, size_t width, size_t height) { + glfwInit(); + + static GLFWwindow *debugWindow = nullptr; + if (!debugWindow) { + debugWindow = glfwCreateWindow(width, height, name.c_str(), nullptr, nullptr); + if (!debugWindow) { + glfwTerminate(); + fprintf(stderr, "Failed to initialize window\n"); + exit(1); + } + } + + GLFWwindow *currentWindow = glfwGetCurrentContext(); + + glfwSetWindowSize(debugWindow, width, height); + glfwMakeContextCurrent(debugWindow); + + int fbWidth, fbHeight; + glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight); + float scale = static_cast(fbWidth) / static_cast(width); + + { + gl::PreserveState pixelZoom; + gl::PreserveState rasterPos; + + MBGL_CHECK_ERROR(glPixelZoom(scale, -scale)); + MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f)); + MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_LUMINANCE, GL_UNSIGNED_BYTE, data)); + } + + glfwSwapBuffers(debugWindow); + + glfwMakeContextCurrent(currentWindow); +} + +void showColorDebugImage(std::string name, const char *data, size_t logicalWidth, size_t logicalHeight, size_t width, size_t height) { + glfwInit(); + + static GLFWwindow *debugWindow = nullptr; + if (!debugWindow) { + debugWindow = glfwCreateWindow(logicalWidth, logicalHeight, name.c_str(), nullptr, nullptr); + if (!debugWindow) { + glfwTerminate(); + fprintf(stderr, "Failed to initialize window\n"); + exit(1); + } + } + + GLFWwindow *currentWindow = glfwGetCurrentContext(); + + glfwSetWindowSize(debugWindow, logicalWidth, logicalHeight); + glfwMakeContextCurrent(debugWindow); + + int fbWidth, fbHeight; + glfwGetFramebufferSize(debugWindow, &fbWidth, &fbHeight); + float xScale = static_cast(fbWidth) / static_cast(width); + float yScale = static_cast(fbHeight) / static_cast(height); + + { + gl::PreserveState clearColor; + gl::PreserveState blend; + gl::PreserveState blendFunc; + gl::PreserveState pixelZoom; + gl::PreserveState rasterPos; + + MBGL_CHECK_ERROR(glClearColor(0.8, 0.8, 0.8, 1)); + MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT)); + MBGL_CHECK_ERROR(glEnable(GL_BLEND)); + MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + MBGL_CHECK_ERROR(glPixelZoom(xScale, -yScale)); + MBGL_CHECK_ERROR(glRasterPos2f(-1.0f, 1.0f)); + MBGL_CHECK_ERROR(glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data)); + } + + glfwSwapBuffers(debugWindow); + + glfwMakeContextCurrent(currentWindow); +} +#endif + +} // namespace platform +} // namespace mbgl diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp new file mode 100644 index 0000000000..c640f188f9 --- /dev/null +++ b/platform/glfw/glfw_view.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include +#include + +#if MBGL_USE_GLES2 +#define GLFW_INCLUDE_ES2 +#endif +#define GL_GLEXT_PROTOTYPES +#include + +class GLFWView : public mbgl::View, public mbgl::Backend { +public: + GLFWView(bool fullscreen = false, bool benchmark = false); + ~GLFWView() override; + + float getPixelRatio() const; + + void setMap(mbgl::Map*); + + // Callback called when the user presses the key mapped to style change. + // The expected action is to set a new style, different to the current one. + void setChangeStyleCallback(std::function callback); + + void setShouldClose(); + + void setWindowTitle(const std::string&); + + void run(); + + // mbgl::View implementation + void updateViewBinding(); + void bind() override; + mbgl::Size getSize() const; + mbgl::Size getFramebufferSize() const; + + // mbgl::Backend implementation + void activate() override; + void deactivate() override; + void invalidate() override; + +private: + // Window callbacks + static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods); + static void onScroll(GLFWwindow *window, double xoffset, double yoffset); + static void onWindowResize(GLFWwindow *window, int width, int height); + static void onFramebufferResize(GLFWwindow *window, int width, int height); + static void onMouseClick(GLFWwindow *window, int button, int action, int modifiers); + static void onMouseMove(GLFWwindow *window, double x, double y); + + // Internal + void report(float duration); + + void setMapChangeCallback(std::function callback); + void notifyMapChange(mbgl::MapChange change) override; + + mbgl::Color makeRandomColor() const; + mbgl::Point makeRandomPoint() const; + static std::shared_ptr + makeSpriteImage(int width, int height, float pixelRatio); + + void nextOrientation(); + + void addRandomPointAnnotations(int count); + void addRandomLineAnnotations(int count); + void addRandomShapeAnnotations(int count); + void addRandomCustomPointAnnotations(int count); + + void clearAnnotations(); + void popAnnotation(); + + mbgl::AnnotationIDs annotationIDs; + std::vector spriteIDs; + + std::function mapChangeCallback; + +private: + mbgl::Map* map = nullptr; + + bool fullscreen = false; + const bool benchmark = false; + bool tracking = false; + bool rotating = false; + bool pitching = false; + + // Frame timer + int frames = 0; + float frameTime = 0; + double lastReported = 0; + + int width = 1024; + int height = 768; + int fbWidth; + int fbHeight; + float pixelRatio; + + double lastX = 0, lastY = 0; + + double lastClick = -1; + + std::function changeStyleCallback; + + mbgl::util::RunLoop runLoop; + mbgl::util::Timer frameTick; + + GLFWwindow *window = nullptr; + bool dirty = false; +}; diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp new file mode 100644 index 0000000000..6e4b324c43 --- /dev/null +++ b/platform/glfw/main.cpp @@ -0,0 +1,190 @@ +#include "glfw_view.hpp" +#include "settings_json.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace { + +GLFWView* view = nullptr; + +} + +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[]) { + bool fullscreen = false; + bool benchmark = false; + std::string style; + double latitude = 0, longitude = 0; + double bearing = 0, zoom = 1, pitch = 0; + bool skipConfig = false; + + const struct option long_options[] = { + {"fullscreen", no_argument, 0, 'f'}, + {"benchmark", no_argument, 0, 'b'}, + {"style", required_argument, 0, 's'}, + {"lon", required_argument, 0, 'x'}, + {"lat", required_argument, 0, 'y'}, + {"zoom", required_argument, 0, 'z'}, + {"bearing", required_argument, 0, 'r'}, + {"pitch", required_argument, 0, 'p'}, + {0, 0, 0, 0} + }; + + while (true) { + int option_index = 0; + int opt = getopt_long(argc, argv, "fbs:", long_options, &option_index); + if (opt == -1) break; + switch (opt) + { + case 0: + if (long_options[option_index].flag != 0) + break; + case 'f': + fullscreen = true; + break; + case 'b': + benchmark = true; + break; + case 's': + style = std::string("asset://") + std::string(optarg); + break; + case 'x': + longitude = atof(optarg); + skipConfig = true; + break; + case 'y': + latitude = atof(optarg); + skipConfig = true; + break; + case 'z': + zoom = atof(optarg); + skipConfig = true; + break; + case 'r': + bearing = atof(optarg); + skipConfig = true; + break; + case 'p': + pitch = atof(optarg); + skipConfig = true; + break; + default: + break; + } + + } + + // sigint handling + struct sigaction sigIntHandler; + sigIntHandler.sa_handler = quit_handler; + sigemptyset(&sigIntHandler.sa_mask); + sigIntHandler.sa_flags = 0; + sigaction(SIGINT, &sigIntHandler, NULL); + + if (benchmark) { + mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled."); + } + + GLFWView backend(fullscreen, benchmark); + view = &backend; + + mbgl::DefaultFileSource fileSource("/tmp/mbgl-cache.db", "."); + + // Set access token if present + const char *token = getenv("MAPBOX_ACCESS_TOKEN"); + if (token == nullptr) { + mbgl::Log::Warning(mbgl::Event::Setup, "no access token set. mapbox.com tiles won't work."); + } else { + fileSource.setAccessToken(std::string(token)); + } + + mbgl::ThreadPool threadPool(4); + + mbgl::Map map(backend, view->getSize(), view->getPixelRatio(), fileSource, threadPool); + + backend.setMap(&map); + + // Load settings + mbgl::Settings_JSON settings; + + if (skipConfig) { + map.setLatLngZoom(mbgl::LatLng(latitude, longitude), zoom); + map.setBearing(bearing); + map.setPitch(pitch); + mbgl::Log::Info(mbgl::Event::General, "Location: %f/%f (z%.2f, %.2f deg)", latitude, longitude, zoom, bearing); + } else { + map.setLatLngZoom(mbgl::LatLng(settings.latitude, settings.longitude), settings.zoom); + map.setBearing(settings.bearing); + map.setPitch(settings.pitch); + map.setDebug(mbgl::MapDebugOptions(settings.debug)); + } + + view->setChangeStyleCallback([&map] () { + static uint8_t currentStyleIndex; + + if (++currentStyleIndex == mbgl::util::default_styles::numOrderedStyles) { + currentStyleIndex = 0; + } + + mbgl::util::default_styles::DefaultStyle newStyle = mbgl::util::default_styles::orderedStyles[currentStyleIndex]; + map.setStyleURL(newStyle.url); + view->setWindowTitle(newStyle.name); + + mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: %s", newStyle.name); + }); + + // Load style + if (style.empty()) { + const char *url = getenv("MAPBOX_STYLE_URL"); + if (url == nullptr) { + mbgl::util::default_styles::DefaultStyle newStyle = mbgl::util::default_styles::orderedStyles[0]; + style = newStyle.url; + view->setWindowTitle(newStyle.name); + } else { + style = url; + view->setWindowTitle(url); + } + } + + map.setStyleURL(style); + + view->run(); + + // Save settings + mbgl::LatLng latLng = map.getLatLng(); + settings.latitude = latLng.latitude; + settings.longitude = latLng.longitude; + settings.zoom = map.getZoom(); + settings.bearing = map.getBearing(); + settings.pitch = map.getPitch(); + settings.debug = mbgl::EnumType(map.getDebug()); + if (!skipConfig) { + settings.save(); + } + mbgl::Log::Info(mbgl::Event::General, + "Exit location: --lat=\"%f\" --lon=\"%f\" --zoom=\"%f\" --bearing \"%f\"", + settings.latitude, settings.longitude, settings.zoom, settings.bearing); + + view = nullptr; + return 0; +} diff --git a/platform/glfw/settings_json.cpp b/platform/glfw/settings_json.cpp new file mode 100644 index 0000000000..2ba1038dc7 --- /dev/null +++ b/platform/glfw/settings_json.cpp @@ -0,0 +1,41 @@ +#include "settings_json.hpp" +#include + +namespace mbgl { + +Settings_JSON::Settings_JSON() { load(); } + +void Settings_JSON::load() { + std::ifstream file("/tmp/mbgl-native.cfg"); + if (file) { + file >> longitude; + file >> latitude; + file >> zoom; + file >> bearing; + file >> pitch; + file >> debug; + } +} + +void Settings_JSON::save() { + std::ofstream file("/tmp/mbgl-native.cfg"); + if (file) { + file << longitude << std::endl; + file << latitude << std::endl; + file << zoom << std::endl; + file << bearing << std::endl; + file << pitch << std::endl; + file << debug << std::endl; + } +} + +void Settings_JSON::clear() { + longitude = 0; + latitude = 0; + zoom = 0; + bearing = 0; + pitch = 0; + debug = 0; +} + +} // namespace mbgl diff --git a/platform/glfw/settings_json.hpp b/platform/glfw/settings_json.hpp new file mode 100644 index 0000000000..eb23b28bc8 --- /dev/null +++ b/platform/glfw/settings_json.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +namespace mbgl { + +class Settings_JSON { +public: + Settings_JSON(); + void load(); + void save(); + void clear(); + +public: + double longitude = 0; + double latitude = 0; + double zoom = 0; + double bearing = 0; + double pitch = 0; + + EnumType debug = 0; +}; + +} // namespace mbgl -- cgit v1.2.1