#include #include #include GLFWView::GLFWView(bool fullscreen_) : fullscreen(fullscreen_) { #ifdef NVIDIA glDiscardFramebufferEXT = reinterpret_cast(glfwGetProcAddress("glDiscardFramebufferEXT")); #endif } GLFWView::~GLFWView() { glfwTerminate(); } void glfwError(int error, const char *description) { mbgl::Log::Error(mbgl::Event::OpenGL, "GLFW error (%i): %s", error, description); assert(false); } void GLFWView::initialize(mbgl::Map *map_) { View::initialize(map_); glfwSetErrorCallback(glfwError); if (!glfwInit()) { fprintf(stderr, "Failed to initialize glfw\n"); exit(1); } GLFWmonitor *monitor = nullptr; if (fullscreen) { monitor = glfwGetPrimaryMonitor(); } #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(1024, 768, "Mapbox GL", monitor, NULL); if (!window) { glfwTerminate(); fprintf(stderr, "Failed to initialize window\n"); exit(1); } glfwSetWindowUserPointer(window, this); glfwMakeContextCurrent(window); glfwSwapInterval(1); int width, height; glfwGetWindowSize(window, &width, &height); resize(window, width, height); glfwSetCursorPosCallback(window, mouseMove); glfwSetMouseButtonCallback(window, mouseClick); glfwSetWindowSizeCallback(window, resize); glfwSetFramebufferSizeCallback(window, resize); glfwSetScrollCallback(window, scroll); glfwSetKeyCallback(window, key); const std::string extensions = reinterpret_cast(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS))); { using namespace mbgl; if (extensions.find("GL_KHR_debug") != std::string::npos) { gl::DebugMessageControl = reinterpret_cast(glfwGetProcAddress("glDebugMessageControl")); gl::DebugMessageInsert = reinterpret_cast(glfwGetProcAddress("glDebugMessageInsert")); gl::DebugMessageCallback = reinterpret_cast(glfwGetProcAddress("glDebugMessageCallback")); gl::GetDebugMessageLog = reinterpret_cast(glfwGetProcAddress("glGetDebugMessageLog")); gl::GetPointerv = reinterpret_cast(glfwGetProcAddress("glGetPointerv")); gl::PushDebugGroup = reinterpret_cast(glfwGetProcAddress("glPushDebugGroup")); gl::PopDebugGroup = reinterpret_cast(glfwGetProcAddress("glPopDebugGroup")); gl::ObjectLabel = reinterpret_cast(glfwGetProcAddress("glObjectLabel")); gl::GetObjectLabel = reinterpret_cast(glfwGetProcAddress("glGetObjectLabel")); gl::ObjectPtrLabel = reinterpret_cast(glfwGetProcAddress("glObjectPtrLabel")); gl::GetObjectPtrLabel = reinterpret_cast(glfwGetProcAddress("glGetObjectPtrLabel")); assert(gl::DebugMessageControl != nullptr); assert(gl::DebugMessageInsert != nullptr); assert(gl::DebugMessageCallback != nullptr); assert(gl::GetDebugMessageLog != nullptr); assert(gl::GetPointerv != nullptr); assert(gl::PushDebugGroup != nullptr); assert(gl::PopDebugGroup != nullptr); assert(gl::ObjectLabel != nullptr); assert(gl::GetObjectLabel != nullptr); assert(gl::ObjectPtrLabel != nullptr); assert(gl::GetObjectPtrLabel != nullptr); } else { if (extensions.find("GL_ARB_debug_output") != std::string::npos) { gl::DebugMessageControl = reinterpret_cast(glfwGetProcAddress("glDebugMessageControlARB")); gl::DebugMessageInsert = reinterpret_cast(glfwGetProcAddress("glDebugMessageInsertARB")); gl::DebugMessageCallback = reinterpret_cast(glfwGetProcAddress("glDebugMessageCallbackARB")); gl::GetDebugMessageLog = reinterpret_cast(glfwGetProcAddress("glGetDebugMessageLogARB")); gl::GetPointerv = reinterpret_cast(glfwGetProcAddress("glGetPointerv")); assert(gl::DebugMessageControl != nullptr); assert(gl::DebugMessageInsert != nullptr); assert(gl::DebugMessageCallback != nullptr); assert(gl::GetDebugMessageLog != nullptr); assert(gl::GetPointerv != nullptr); } if (extensions.find("GL_EXT_debug_marker") != std::string::npos) { gl::InsertEventMarkerEXT = reinterpret_cast(glfwGetProcAddress("glInsertEventMarkerEXT")); gl::PushGroupMarkerEXT = reinterpret_cast(glfwGetProcAddress("glPushGroupMarkerEXT")); gl::PopGroupMarkerEXT = reinterpret_cast(glfwGetProcAddress("glPopGroupMarkerEXT")); assert(gl::InsertEventMarkerEXT != nullptr); assert(gl::PushGroupMarkerEXT != nullptr); assert(gl::PopGroupMarkerEXT != nullptr); } if (extensions.find("GL_EXT_debug_label") != std::string::npos) { gl::LabelObjectEXT = reinterpret_cast(glfwGetProcAddress("glLabelObjectEXT")); gl::GetObjectLabelEXT = reinterpret_cast(glfwGetProcAddress("glGetObjectLabelEXT")); assert(gl::LabelObjectEXT != nullptr); assert(gl::GetObjectLabelEXT != nullptr); } } if (extensions.find("GL_ARB_vertex_array_object") != std::string::npos) { gl::BindVertexArray = reinterpret_cast(glfwGetProcAddress("glBindVertexArray")); gl::DeleteVertexArrays = reinterpret_cast(glfwGetProcAddress("glDeleteVertexArrays")); gl::GenVertexArrays = reinterpret_cast(glfwGetProcAddress("glGenVertexArrays")); gl::IsVertexArray = reinterpret_cast(glfwGetProcAddress("glIsVertexArray")); assert(gl::BindVertexArray != nullptr); assert(gl::DeleteVertexArrays != nullptr); assert(gl::GenVertexArrays != nullptr); assert(gl::IsVertexArray != nullptr); } else if (extensions.find("GL_APPLE_vertex_array_object") != std::string::npos) { gl::BindVertexArray = reinterpret_cast(glfwGetProcAddress("glBindVertexArrayAPPLE")); gl::DeleteVertexArrays = reinterpret_cast(glfwGetProcAddress("glDeleteVertexArraysAPPLE")); gl::GenVertexArrays = reinterpret_cast(glfwGetProcAddress("glGenVertexArraysAPPLE")); gl::IsVertexArray = reinterpret_cast(glfwGetProcAddress("glIsVertexArrayAPPLE")); assert(gl::BindVertexArray != nullptr); assert(gl::DeleteVertexArrays != nullptr); assert(gl::GenVertexArrays != nullptr); assert(gl::IsVertexArray != nullptr); } // Require packed depth stencil gl::isPackedDepthStencilSupported = true; gl::isDepth24Supported = true; } glfwMakeContextCurrent(nullptr); } void GLFWView::key(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->toggleDebug(); break; case GLFW_KEY_X: if (!mods) view->map->resetPosition(); break; case GLFW_KEY_R: if (!mods) { view->map->setDefaultTransitionDuration(std::chrono::milliseconds(300)); if (view->map->hasClass("night")) { view->map->removeClass("night"); } else { view->map->addClass("night"); } } break; case GLFW_KEY_N: if (!mods) view->map->resetNorth(); break; } } } void GLFWView::scroll(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->startScaling(); view->map->scaleBy(scale, view->lastX, view->lastY); } void GLFWView::resize(GLFWwindow *window, int width, int height ) { GLFWView *view = reinterpret_cast(glfwGetWindowUserPointer(window)); int fbWidth, fbHeight; glfwGetFramebufferSize(window, &fbWidth, &fbHeight); view->map->resize(width, height, static_cast(fbWidth) / static_cast(width), fbWidth, fbHeight); } void GLFWView::mouseClick(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; if (!view->rotating) { view->map->stopRotating(); } } else if (button == GLFW_MOUSE_BUTTON_LEFT) { view->tracking = action == GLFW_PRESS; if (action == GLFW_RELEASE) { view->map->stopPanning(); double now = glfwGetTime(); if (now - view->lastClick < 0.4 /* ms */) { if (modifiers & GLFW_MOD_SHIFT) { view->map->scaleBy(0.5, view->lastX, view->lastY, std::chrono::milliseconds(500)); } else { view->map->scaleBy(2.0, view->lastX, view->lastY, std::chrono::milliseconds(500)); } } view->lastClick = now; } } } void GLFWView::mouseMove(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->startPanning(); view->map->moveBy(dx, dy); } } else if (view->rotating) { view->map->startRotating(); view->map->rotateBy(view->lastX, view->lastY, x, y); } view->lastX = x; view->lastY = y; } int GLFWView::run() { map->start(); while (!glfwWindowShouldClose(window)) { glfwWaitEvents(); } map->stop([]() { glfwWaitEvents(); }); // Terminate here to save binary shaders map->terminate(); return 0; } void GLFWView::activate() { glfwMakeContextCurrent(window); } void GLFWView::deactivate() { glfwMakeContextCurrent(nullptr); } void GLFWView::notify() { glfwPostEmptyEvent(); } void GLFWView::swap() { glfwSwapBuffers(window); map->swapped(); fps(); } void GLFWView::notifyMapChange(mbgl::MapChange /*change*/, std::chrono::steady_clock::duration /*delay*/) { // no-op } void GLFWView::fps() { static int frames = 0; static double timeElapsed = 0; frames++; double currentTime = glfwGetTime(); if (currentTime - timeElapsed >= 1) { fprintf(stderr, "FPS: %4.2f\n", frames / (currentTime - timeElapsed)); timeElapsed = currentTime; frames = 0; } } namespace mbgl { namespace platform { double elapsed() { return glfwGetTime(); } #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); 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); 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 } }