summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago Marcos P. Santos <tmpsantos@gmail.com>2020-02-08 17:30:57 +0200
committerThiago Marcos P. Santos <tmpsantos@gmail.com>2020-02-16 21:13:02 +0200
commit9f682ec3a43e7263f6c265f91a9dba070b71a0b6 (patch)
treee4e2f9712d779ef3d0277d1b692dfd176b07e78e
parent59294aaef333bdd455bd13d6bab6fca730379b52 (diff)
downloadqtlocation-mapboxgl-9f682ec3a43e7263f6c265f91a9dba070b71a0b6.tar.gz
glfw
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt1
-rw-r--r--tools/CMakeLists.txt1
-rw-r--r--tools/shell/CMakeLists.txt27
-rw-r--r--tools/shell/demo_widget.cpp17
-rw-r--r--tools/shell/demo_widget.hpp20
-rw-r--r--tools/shell/fps_widget.cpp21
-rw-r--r--tools/shell/fps_widget.hpp17
-rw-r--r--tools/shell/imgui_backend.cpp21
-rw-r--r--tools/shell/imgui_backend.hpp29
-rw-r--r--tools/shell/imgui_backend_impl.hpp27
-rw-r--r--tools/shell/imgui_backend_impl_glfw.cpp50
-rw-r--r--tools/shell/impl_glfw.cmake28
-rw-r--r--tools/shell/main_glfw.cpp15
-rw-r--r--tools/shell/map_widget.cpp17
-rw-r--r--tools/shell/map_widget.hpp17
-rw-r--r--tools/shell/util.hpp9
-rw-r--r--tools/shell/widget.cpp15
-rw-r--r--tools/shell/widget.hpp46
-rw-r--r--tools/shell/window.cpp81
-rw-r--r--tools/shell/window.hpp41
-rw-r--r--tools/shell/window_impl.hpp34
-rw-r--r--tools/shell/window_impl_glfw.cpp51
-rw-r--r--tools/shell/window_impl_glfw.hpp25
m---------vendor/imgui0
-rw-r--r--vendor/imgui-glfw.cmake30
26 files changed, 643 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
index cd6db33ae3..61abc79ca5 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -79,3 +79,6 @@
[submodule "vendor/curl-android-ios"]
path = vendor/curl-android-ios
url = https://github.com/gcesarmza/curl-android-ios.git
+[submodule "vendor/imgui"]
+ path = vendor/imgui
+ url = https://github.com/ocornut/imgui.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 485ced04aa..6f8f8e58cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1023,3 +1023,4 @@ endif()
add_subdirectory(${PROJECT_SOURCE_DIR}/test)
add_subdirectory(${PROJECT_SOURCE_DIR}/benchmark)
add_subdirectory(${PROJECT_SOURCE_DIR}/render-test)
+add_subdirectory(${PROJECT_SOURCE_DIR}/tools)
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
new file mode 100644
index 0000000000..4b0e2131e3
--- /dev/null
+++ b/tools/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/shell)
diff --git a/tools/shell/CMakeLists.txt b/tools/shell/CMakeLists.txt
new file mode 100644
index 0000000000..a6f0269a43
--- /dev/null
+++ b/tools/shell/CMakeLists.txt
@@ -0,0 +1,27 @@
+set(
+ MBGL_SHELL_SOURCES
+ ${CMAKE_CURRENT_LIST_DIR}/demo_widget.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/fps_widget.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/imgui_backend.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/map_widget.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/widget.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/window.cpp
+)
+
+if(CMAKE_SYSTEM_NAME STREQUAL Linux)
+ include(${CMAKE_CURRENT_LIST_DIR}/impl_glfw.cmake)
+elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ include(${CMAKE_CURRENT_LIST_DIR}/impl_glfw.cmake)
+else()
+ message(FATAL_ERROR "Unsupported target platform: " ${CMAKE_SYSTEM_NAME})
+endif()
+
+target_include_directories(
+ mbgl-shell
+ PRIVATE ${CMAKE_CURRENT_LIST_DIR}
+)
+
+target_link_libraries(
+ mbgl-shell
+ PRIVATE Mapbox::Map Mapbox::Base::Extras::expected-lite mbgl-compiler-options
+)
diff --git a/tools/shell/demo_widget.cpp b/tools/shell/demo_widget.cpp
new file mode 100644
index 0000000000..142230626a
--- /dev/null
+++ b/tools/shell/demo_widget.cpp
@@ -0,0 +1,17 @@
+#include "demo_widget.hpp"
+
+#include <imgui.h>
+
+namespace mbgl {
+namespace shell {
+
+DemoWidget::DemoWidget(Window& parent_) : Widget(parent_) {}
+
+void DemoWidget::render() {
+ if (visible) {
+ ImGui::ShowDemoWindow(&visible);
+ }
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/demo_widget.hpp b/tools/shell/demo_widget.hpp
new file mode 100644
index 0000000000..07a8a4ea94
--- /dev/null
+++ b/tools/shell/demo_widget.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "widget.hpp"
+
+namespace mbgl {
+namespace shell {
+
+class DemoWidget final : public Widget {
+public:
+ DemoWidget(Window &window);
+
+ bool isVisible() const override { return visible; }
+ void render() override;
+
+private:
+ bool visible = true;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/fps_widget.cpp b/tools/shell/fps_widget.cpp
new file mode 100644
index 0000000000..071514b636
--- /dev/null
+++ b/tools/shell/fps_widget.cpp
@@ -0,0 +1,21 @@
+#include "fps_widget.hpp"
+
+#include <imgui.h>
+
+namespace mbgl {
+namespace shell {
+
+FPSWidget::FPSWidget(Window& parent_) : Widget(parent_) {}
+
+void FPSWidget::render() {
+ constexpr auto overlay = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize |
+ ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav;
+
+ ImGui::SetNextWindowPos(ImVec2(0, 0));
+ ImGui::Begin("overlay", nullptr, overlay);
+ ImGui::Text("FPS %.1f", ImGui::GetIO().Framerate);
+ ImGui::End();
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/fps_widget.hpp b/tools/shell/fps_widget.hpp
new file mode 100644
index 0000000000..88fc494a1f
--- /dev/null
+++ b/tools/shell/fps_widget.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "widget.hpp"
+
+namespace mbgl {
+namespace shell {
+
+class FPSWidget final : public Widget {
+public:
+ FPSWidget(Window &window);
+
+protected:
+ void render() override;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/imgui_backend.cpp b/tools/shell/imgui_backend.cpp
new file mode 100644
index 0000000000..b167cb9535
--- /dev/null
+++ b/tools/shell/imgui_backend.cpp
@@ -0,0 +1,21 @@
+#include "imgui_backend.hpp"
+
+#include "imgui_backend_impl.hpp"
+
+namespace mbgl {
+namespace shell {
+
+ImGuiBackend::ImGuiBackend(Window::Impl &windowImpl) : impl(Impl::Create(windowImpl)) {}
+
+ImGuiBackend::~ImGuiBackend() = default;
+
+void ImGuiBackend::newFrame() {
+ impl->newFrame();
+}
+
+void ImGuiBackend::renderDrawData() {
+ impl->renderDrawData();
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/imgui_backend.hpp b/tools/shell/imgui_backend.hpp
new file mode 100644
index 0000000000..de3e1aa93d
--- /dev/null
+++ b/tools/shell/imgui_backend.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "window_impl.hpp"
+
+#include <memory>
+
+namespace mbgl {
+namespace shell {
+
+class ImGuiBackend final {
+public:
+ ImGuiBackend(Window::Impl &);
+ ~ImGuiBackend();
+
+ // Starts a new ImGui frame.
+ void newFrame();
+
+ // Create the draw calls and render
+ // the frame using the graphics backend.
+ void renderDrawData();
+
+ class Impl;
+
+private:
+ std::unique_ptr<Impl> impl;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/imgui_backend_impl.hpp b/tools/shell/imgui_backend_impl.hpp
new file mode 100644
index 0000000000..cc50dafdf7
--- /dev/null
+++ b/tools/shell/imgui_backend_impl.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "imgui_backend.hpp"
+
+#include <string>
+
+namespace mbgl {
+namespace shell {
+
+class ImGuiBackend::Impl {
+public:
+ virtual ~Impl() = default;
+
+ virtual void newFrame() = 0;
+ virtual void renderDrawData() = 0;
+
+ // Factory for creating the ImGuiBackend, to abstract
+ // integration with the window system and graphics
+ // backend such as OpenGL and Metal.
+ static std::unique_ptr<Impl> Create(Window::Impl &windowImpl);
+
+protected:
+ Impl() = default;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/imgui_backend_impl_glfw.cpp b/tools/shell/imgui_backend_impl_glfw.cpp
new file mode 100644
index 0000000000..454ea09f25
--- /dev/null
+++ b/tools/shell/imgui_backend_impl_glfw.cpp
@@ -0,0 +1,50 @@
+#include "imgui_backend_impl.hpp"
+
+#include "window_impl_glfw.hpp"
+
+#include <imgui.h>
+#include <imgui_impl_glfw.h>
+#include <imgui_impl_opengl3.h>
+
+namespace mbgl {
+namespace shell {
+
+class ImGuiBackendImplGLFW final : public ImGuiBackend::Impl {
+public:
+ ImGuiBackendImplGLFW(Window::Impl &windowImpl);
+ ~ImGuiBackendImplGLFW();
+
+ void newFrame() override;
+ void renderDrawData() override;
+};
+
+ImGuiBackendImplGLFW::ImGuiBackendImplGLFW(Window::Impl &windowImpl) {
+ ImGui::CreateContext();
+ ImGui_ImplGlfw_InitForOpenGL(static_cast<WindowImplGLFW &>(windowImpl).getGLFWwindow(), true);
+ ImGui_ImplOpenGL3_Init();
+}
+
+ImGuiBackendImplGLFW::~ImGuiBackendImplGLFW() {
+ ImGui_ImplOpenGL3_Shutdown();
+ ImGui_ImplGlfw_Shutdown();
+ ImGui::DestroyContext();
+}
+
+void ImGuiBackendImplGLFW::newFrame() {
+ ImGui_ImplOpenGL3_NewFrame();
+ ImGui_ImplGlfw_NewFrame();
+ ImGui::NewFrame();
+}
+
+void ImGuiBackendImplGLFW::renderDrawData() {
+ ImGui::Render();
+ ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
+}
+
+// static
+std::unique_ptr<ImGuiBackend::Impl> ImGuiBackend::Impl::Create(Window::Impl &windowImpl) {
+ return std::make_unique<ImGuiBackendImplGLFW>(windowImpl);
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/impl_glfw.cmake b/tools/shell/impl_glfw.cmake
new file mode 100644
index 0000000000..0ae4532576
--- /dev/null
+++ b/tools/shell/impl_glfw.cmake
@@ -0,0 +1,28 @@
+find_package(OpenGL REQUIRED)
+find_package(PkgConfig REQUIRED)
+
+pkg_search_module(GLFW glfw3 REQUIRED)
+
+add_executable(
+ mbgl-shell
+ ${MBGL_SHELL_SOURCES}
+ ${CMAKE_CURRENT_LIST_DIR}/imgui_backend_impl_glfw.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/window_impl_glfw.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/main_glfw.cpp
+)
+
+target_include_directories(
+ mbgl-shell
+ PRIVATE ${GLFW_INCLUDE_DIRS}
+)
+
+target_link_directories(mbgl-shell PRIVATE $<$<BOOL:${GLFW_LIBRARY_DIRS}>:${GLFW_LIBRARY_DIRS}>)
+
+include(${PROJECT_SOURCE_DIR}/vendor/imgui-glfw.cmake)
+
+target_link_libraries(
+ mbgl-shell
+ PRIVATE ${GLFW_LIBRARIES} OpenGL::GL mbgl-vendor-imgui-glfw
+)
+
+install(TARGETS mbgl-shell RUNTIME DESTINATION bin)
diff --git a/tools/shell/main_glfw.cpp b/tools/shell/main_glfw.cpp
new file mode 100644
index 0000000000..86ea63a2ba
--- /dev/null
+++ b/tools/shell/main_glfw.cpp
@@ -0,0 +1,15 @@
+#include "demo_widget.hpp"
+#include "fps_widget.hpp"
+#include "map_widget.hpp"
+#include "window.hpp"
+
+int main(int, char **) {
+ mbgl::shell::Window window;
+ mbgl::shell::MapWidget map(window);
+ mbgl::shell::FPSWidget fps(window);
+ mbgl::shell::DemoWidget demo(window);
+
+ window.show();
+
+ return 0;
+}
diff --git a/tools/shell/map_widget.cpp b/tools/shell/map_widget.cpp
new file mode 100644
index 0000000000..dea30dcaae
--- /dev/null
+++ b/tools/shell/map_widget.cpp
@@ -0,0 +1,17 @@
+#include "map_widget.hpp"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace mbgl {
+namespace shell {
+
+MapWidget::MapWidget(Window &parent_) : Widget(parent_) {}
+
+void MapWidget::render() {
+ glClearColor(0.4f, 0.0f, 0.6f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/map_widget.hpp b/tools/shell/map_widget.hpp
new file mode 100644
index 0000000000..afda89e907
--- /dev/null
+++ b/tools/shell/map_widget.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "widget.hpp"
+
+namespace mbgl {
+namespace shell {
+
+class MapWidget final : public Widget {
+public:
+ MapWidget(Window &window);
+
+protected:
+ void render() override;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/util.hpp b/tools/shell/util.hpp
new file mode 100644
index 0000000000..3401605575
--- /dev/null
+++ b/tools/shell/util.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <nonstd/expected.hpp>
+
+template <class T, class E>
+using expected = nonstd::expected<T, E>;
+
+template <class E>
+using unexpected = nonstd::unexpected_type<E>;
diff --git a/tools/shell/widget.cpp b/tools/shell/widget.cpp
new file mode 100644
index 0000000000..088a5cd841
--- /dev/null
+++ b/tools/shell/widget.cpp
@@ -0,0 +1,15 @@
+#include "widget.hpp"
+
+namespace mbgl {
+namespace shell {
+
+Widget::Widget(Window &parent_) : parent(parent_) {
+ parent.addWidget(*this);
+}
+
+Widget::~Widget() {
+ parent.removeWidget(*this);
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/widget.hpp b/tools/shell/widget.hpp
new file mode 100644
index 0000000000..caeb6fa84f
--- /dev/null
+++ b/tools/shell/widget.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "window.hpp"
+
+#include <utility>
+
+namespace mbgl {
+namespace shell {
+
+class Widget {
+public:
+ Widget(Window &parent);
+ virtual ~Widget();
+
+ // Function called when the widget is about
+ // to be visible. It will be called with a
+ // valid graphics context.
+ virtual void show() {}
+
+ // Hide the widget, effectively it will make
+ // it not render and resize anymore.
+ virtual void hide() {}
+
+ // Function called every time the widget needs
+ // to render a frame. It will provide a valid
+ // context for drawing and it will swap buffers
+ // after this function returns. Other widgets
+ // might render after or before this call, so
+ // it should not assume any graphics context state.
+ virtual void render() {}
+
+ // Resize the widget taking into consideration
+ // the framebuffer scale.
+ virtual void resize(unsigned /* width */, unsigned /* height */) {}
+
+ // Returns true if the widget is visible,
+ // false otherwise. Invisible widgets will
+ // not have render() and resize() called.
+ virtual bool isVisible() const { return true; }
+
+private:
+ Window &parent;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/window.cpp b/tools/shell/window.cpp
new file mode 100644
index 0000000000..c7f3f24843
--- /dev/null
+++ b/tools/shell/window.cpp
@@ -0,0 +1,81 @@
+#include "window.hpp"
+
+#include "imgui_backend.hpp"
+#include "widget.hpp"
+#include "window_impl.hpp"
+
+#include <imgui.h>
+
+#include <iostream>
+#include <memory>
+
+namespace mbgl {
+namespace shell {
+
+Window::Window() : impl(Impl::Create(*this)) {
+ auto expected = impl->init(800, 600, "Mapbox GL Shell");
+ if (!expected) {
+ std::cerr << expected.error() << std::endl;
+ errored = true;
+ return;
+ }
+
+ IMGUI_CHECKVERSION();
+
+ imgui = std::make_unique<ImGuiBackend>(*impl);
+
+ ImGui::StyleColorsDark();
+ ImGui::GetIO().IniFilename = nullptr;
+}
+
+Window::~Window() {
+ if (errored) {
+ return;
+ }
+}
+
+void Window::addWidget(Widget &widget) {
+ children.push_back(&widget);
+}
+
+void Window::removeWidget(Widget &widget) {
+ children.remove(&widget);
+}
+
+void Window::show() {
+ if (errored) {
+ return;
+ }
+
+ for (auto widget : children) {
+ widget->show();
+ }
+
+ impl->show();
+}
+
+void Window::render() {
+ imgui->newFrame();
+
+ for (auto widget : children) {
+ if (widget->isVisible()) {
+ widget->render();
+ }
+ }
+
+ imgui->renderDrawData();
+}
+
+void Window::resize(unsigned width, unsigned height) {
+ ImGuiIO &io = ImGui::GetIO();
+
+ io.DisplaySize = ImVec2(width, height);
+ io.DisplayFramebufferScale = ImVec2(1, 1);
+
+ for (auto widget : children) {
+ widget->resize(width, height);
+ }
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/window.hpp b/tools/shell/window.hpp
new file mode 100644
index 0000000000..dcca205963
--- /dev/null
+++ b/tools/shell/window.hpp
@@ -0,0 +1,41 @@
+#pragma once
+
+#include <list>
+#include <memory>
+
+namespace mbgl {
+namespace shell {
+
+class ImGuiBackend;
+class Widget;
+
+class Window final {
+public:
+ Window();
+ ~Window();
+
+ void addWidget(Widget &widget);
+ void removeWidget(Widget &widget);
+
+ // Show the window and pools for events, it will
+ // block on GLFW, and on GLFM it will be no-op.
+ void show();
+
+ // Render the window and all its visible widgets.
+ void render();
+
+ // Resize the window and the contents inside it.
+ void resize(unsigned width, unsigned height);
+
+ class Impl;
+
+private:
+ std::unique_ptr<Impl> impl;
+ std::unique_ptr<ImGuiBackend> imgui;
+
+ bool errored = false;
+ std::list<Widget *> children;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/window_impl.hpp b/tools/shell/window_impl.hpp
new file mode 100644
index 0000000000..862b907d1c
--- /dev/null
+++ b/tools/shell/window_impl.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "util.hpp"
+#include "window.hpp"
+
+#include <string>
+
+namespace mbgl {
+namespace shell {
+
+class Window::Impl {
+public:
+ virtual ~Impl() {}
+
+ // Initializes the window with the dimensions
+ // and the tile when supported.
+ virtual expected<bool, std::string> init(unsigned width, unsigned height, const char *title) = 0;
+
+ // Show the window and all its children
+ // widgets.
+ virtual void show() = 0;
+
+ // Factory for creating the Window, implemented
+ // by backends such as GLFW and GLFM.
+ static std::unique_ptr<Impl> Create(Window &parent);
+
+protected:
+ Impl(Window &parent_) : parent(parent_) {}
+
+ Window &parent;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/window_impl_glfw.cpp b/tools/shell/window_impl_glfw.cpp
new file mode 100644
index 0000000000..cf68098532
--- /dev/null
+++ b/tools/shell/window_impl_glfw.cpp
@@ -0,0 +1,51 @@
+#include "window_impl_glfw.hpp"
+
+namespace mbgl {
+namespace shell {
+
+WindowImplGLFW::WindowImplGLFW(Window &parent_) : Window::Impl(parent_) {}
+
+WindowImplGLFW::~WindowImplGLFW() {
+ glfwDestroyWindow(glfwWindow);
+ glfwTerminate();
+}
+
+expected<bool, std::string> WindowImplGLFW::init(unsigned width, unsigned height, const char *title) {
+ if (!glfwInit()) {
+ return unexpected<std::string>("GLFW not initialized.");
+ }
+
+ glfwWindow = glfwCreateWindow(width, height, title, NULL, NULL);
+ if (!glfwWindow) {
+ return unexpected<std::string>("Could not create GLFW window.");
+ }
+
+ glfwMakeContextCurrent(glfwWindow);
+ glfwSwapInterval(1);
+
+ return true;
+}
+
+void WindowImplGLFW::show() {
+ while (!glfwWindowShouldClose(glfwWindow)) {
+ glfwPollEvents();
+
+ int w, h;
+ glfwGetFramebufferSize(glfwWindow, &w, &h);
+ glViewport(0, 0, w, h);
+
+ // TODO: Only resize when needed.
+ parent.resize(w, h);
+ parent.render();
+
+ glfwSwapBuffers(glfwWindow);
+ }
+}
+
+// static
+std::unique_ptr<Window::Impl> Window::Impl::Create(Window &parent) {
+ return std::make_unique<WindowImplGLFW>(parent);
+}
+
+} // namespace shell
+} // namespace mbgl
diff --git a/tools/shell/window_impl_glfw.hpp b/tools/shell/window_impl_glfw.hpp
new file mode 100644
index 0000000000..4e0a5d0600
--- /dev/null
+++ b/tools/shell/window_impl_glfw.hpp
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "window_impl.hpp"
+
+#include <GLFW/glfw3.h>
+
+namespace mbgl {
+namespace shell {
+
+class WindowImplGLFW final : public Window::Impl {
+public:
+ WindowImplGLFW(Window &parent);
+ ~WindowImplGLFW();
+
+ expected<bool, std::string> init(unsigned width, unsigned height, const char *title) override;
+ void show() override;
+
+ GLFWwindow *getGLFWwindow() { return glfwWindow; }
+
+private:
+ GLFWwindow *glfwWindow = nullptr;
+};
+
+} // namespace shell
+} // namespace mbgl
diff --git a/vendor/imgui b/vendor/imgui
new file mode 160000
+Subproject f694244dec94ca67666d767fd5be59faf74686b
diff --git a/vendor/imgui-glfw.cmake b/vendor/imgui-glfw.cmake
new file mode 100644
index 0000000000..0ca945b09d
--- /dev/null
+++ b/vendor/imgui-glfw.cmake
@@ -0,0 +1,30 @@
+if(TARGET mbgl-vendor-imgui-glfw)
+ return()
+endif()
+
+add_library(
+ mbgl-vendor-imgui-glfw STATIC
+ ${CMAKE_CURRENT_LIST_DIR}/imgui/examples/imgui_impl_opengl3.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/imgui/examples/imgui_impl_glfw.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/imgui/imgui.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/imgui/imgui_demo.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/imgui/imgui_draw.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/imgui/imgui_widgets.cpp
+)
+
+target_link_libraries(
+ mbgl-shell
+ PRIVATE mbgl-compiler-options
+)
+
+target_compile_definitions(
+ mbgl-vendor-imgui-glfw
+ PUBLIC IMGUI_IMPL_OPENGL_ES3 IMGUI_IMPL_OPENGL_LOADER_CUSTOM
+)
+
+target_include_directories(
+ mbgl-vendor-imgui-glfw SYSTEM
+ PUBLIC ${CMAKE_CURRENT_LIST_DIR}/imgui ${CMAKE_CURRENT_LIST_DIR}/imgui/examples
+)
+
+set_property(TARGET mbgl-vendor-imgui-glfw PROPERTY FOLDER Core)