WindowsでOpenGLES --- imgui導入
OpenGL上でGUIを実装するライブラリの一つに、ImGuiがあります。
GitHub - ocornut/imgui: Bloat-free Immediate Mode Graphical User interface for C++ with minimal dependencies
数ファイル取り込むだけでGUIを実装できるため、簡単なソフトの作成には便利です。
今回はGLFW上でImGuiを動作させてみたいと思います。
GLFWに関しましては下記記事を参照してください。
WindowsでOpenGLES --- GLFW導入 - 何でもプログラミング
Immediate Mode GUI
このライブラリは "Immediate Mode GUI" という方式を採用しており、一般的な、ボタンオブジェクトを作ってテキストを変更して…といった "Retained Mode GUI" とは異なります。
Immediate Modeでは毎回GUIを描き直すため、既にあるGUIツリーを更新していくRetained Modeに比べて、わかりやすいコードになる傾向があります。
ただしライブラリ側でstatic変数に状態を持っていたりするため、Immediate Modeが完全優位というわけでもありません。
個人的には毎回GUIの作り直し(一部のみの更新をしない)が重要だと思いますので、Retained ModeであってもwebのReactのようなフレームワークがあれば変わらないと思います。
ファイル取り込み
GitHubからダウンロードし、下記ファイルをプロジェクトに追加します。
imgui_impl_glfw_gl3はexamples/opengl3_example/以下に入っています。
imgui_impl_glfw_gl3.cppの修正
元のままではOpenGL3を利用するようになっていますので、OpenGLES3に対応するよう修正します。
// GLES3/gl3.hをincludeするように -#include <GL/gl3w.h> +#define GLFW_INCLUDE_ES3 +#define GL_GLEXT_PROTOTYPES // GL_BLEND_SRCは存在しないのでGL_BLEND_SRC_ALPHAに -GLint last_blend_src; glGetIntegerv(GL_BLEND_SRC, &last_blend_src); -GLint last_blend_dst; glGetIntegerv(GL_BLEND_DST, &last_blend_dst); +GLint last_blend_src; glGetIntegerv(GL_BLEND_SRC_ALPHA, &last_blend_src); +GLint last_blend_dst; glGetIntegerv(GL_BLEND_DST_ALPHA, &last_blend_dst); // Vertexシェーダのversion変更 -"#version 330\n" +"#version 300 es\n" // Fragmentシェーダのversion変更、precisionの設定 -"#version 330\n" +"#version 300 es\n" +"precision mediump float;\n"
アプリケーションコード
ImGui_ImplGlfwGL3_Initで初期化し、描画ごとにImGui_ImplGlfwGL3_NewFrameとImGui::Render()を呼び出します。
今回はImGui::ShowTestWindowを用いてサンプルを描画しています。
毎フレーム描画する必要がない場合はglfwPollEventsの代わりにglfwWaitEventsを利用してください。
フレームレートはglfwSwapInterval(1)でディスプレイと同期するようになるのですが、Windowsでは呼ばなくてもディスプレイと同期しているようです。
#define GLFW_INCLUDE_ES3 #define GL_GLEXT_PROTOTYPES #include <GLFW\glfw3.h> #include "imgui.h" #include "imgui_impl_glfw_gl3.h" #pragma comment(lib, "glfw3.lib") #pragma comment(lib, "libGLESv2.lib") int main() { assert(glfwInit()); glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); GLFWwindow* window = glfwCreateWindow(650, 350, "ImGui", NULL, NULL); assert(window); glfwMakeContextCurrent(window); assert(ImGui_ImplGlfwGL3_Init(window, true)); glfwSetWindowSizeCallback(window, [](GLFWwindow*, int w, int h) { glViewport(0, 0, w, h); }); while (glfwWindowShouldClose(window) == GL_FALSE) { glfwPollEvents(); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplGlfwGL3_NewFrame(); ImGui::ShowTestWindow(); ImGui::Render(); glfwSwapBuffers(window); } ImGui_ImplGlfwGL3_Shutdown(); glfwTerminate(); return 0; }