前々からWindows上でOpenGLESを使ってツールを作れればAndroidとのマルチプラットフォーム開発が楽だなと思っていました。

昨今NVIDIAがOpenGLES2.0のWindows版プロファイラを提供してくれたりとかなり開発環境もそろってきているという話を聞いたのでそろそろ本腰を入れてチャレンジしてみようかなと考えました。

# ■angleとは

angle
Almost Native Graphics Layer Engineの略。(ほぼネイティブのグラフィックスレイヤーエンジン)

ANGLEの目標は、OpenGL ES API呼び出しをそのプラットフォームで利用可能なハードウェアでサポートされたAPIの1つに変換することにより、複数のオペレーティングシステムのユーザーがWebGLおよびその他のOpenGL ESコンテンツをシームレスに実行できるようにすることです。ANGLEは現在、OpenGL ES 2.0、3.0、および3.1からVulkan、デスクトップOpenGL、OpenGL ES、Direct3D 9、およびDirect3D 11への翻訳を提供しています。将来の計画には、ES 3.2、MetalおよびMacOSへの翻訳、Chrome OS、およびFuchsiaサポートが含まれます。

Googleが提供しているBSDライセンスのオープンソースプロジェクトです。

OpenGLESのドライバが入っていない環境下でもOpenGLESを動かすことができるOpenGLESライブラリです。
Windowsでは、中身はDirectXなのでDirectXが動作する環境が必要になります。

# ■環境

  • Windows 10 (バージョン1904)
  • Visual Studio 2017 Professional
  • Git for Windows 2.25.1

# ■OpenGLES2.0用のライブラリを作成

# ▼depot_toolsのセットアップ

  1. こちら から depot_tools の zip をダウンロードしフォルダに展開します。(例 C:\Tools\depot_tools)
    angle saite

  2. 環境変数pathにdepot_toolsの展開パスを登録しPCを再起動します。
    ここで注意なのはWindowsAppよりdepot_toolsを上に登録しないとpythonのパスが奪われるので環境構築が終わるまでは上に配置してきましょう。
    environments

  3. gclient を使えるようにコマンドプロンプトで下記コマンドを打ち込み環境構築し念のためPCを再起動します。

> cd C:\Tools\depot_tools
> call gclient.bat
  1. Windows 10 Standalone SDK をインストール。
    こちら からSDKをダウンロードしインストールします。
    VisualStudio経由でインストールした物ですとwindbg等が入らないためこの先の作業が失敗します。
    忘れずに入れ替えましょう。
    WindowsSDK

# ▼angleプロジェクトのセットアップ

  1. フォルダを作成しソースコードをチェックアウトします。(例 C:\projects\angle)
> cd C:\projects\angle
> git clone https://chromium.googlesource.com/angle/angle
> cd angle
> python scripts\bootstrap.py
> set DEPOT_TOOLS_WIN_TOOLCHAIN=0
> gclient sync
  1. ここまでの環境構築ができているか確認
    コマンド実行後にout\Debugフォルダができていれば成功です。
> gn gen out\Debug
  1. VisualStudio2017用のslnファイルを作成
    デフォルト設定のslnファイルが生成されます。
  • Visual Studio 2017
  • Debugシンボル有
  • ターゲットCPUはx64
    ※out\Debug\args.gnにパラメーターを設定すれば変更可能です。
     詳しくは こちら のページをご確認ください。
> gn gen out\Debug --sln=angle-debug --ide=vs2017
  1. sln のビルド
  • angle-debug.sln を開き、
  • 「ソリューションエクスプローラー > angle-debug/angle/angle.vcxprojを右クリック > ビルド(U)」
  • ビルドが終了しout\Debugフォルダ以下にライブラリが出来ていれば準備完了です。
    • libEGL.dll
    • libEGL.dll.lib
    • libGLESv2.dll
    • libGLESv2.dll.lib

これでライブラリの準備完了です。

# ■テストプロジェクトで動作確認

# ▼VisualStudio2017のプロジェクトを準備

  1. VisualStudioを立ち上げる。

  2. 「ファイル(F) > 新規作成(N) > プロジェクト(P )」を選択。

  3. 「新しいプロジェクト」にて「VisualC++ > Windowsデスクトップ > Windowsデスクトップウィザード」を選択しOK。
    VSCreate

  4. 「Windowsデスクトッププロジェクト」にて設定を行いOK。
    VSCreate2

  5. slnファイルと同一階層にlibフォルダを作成しangleプロジェクトからファイルをコピーしてくる。

  • コピー先:(project_root)\lib\GLES2\include
    • (angle_root)\angle\include\EGL
    • (angle_root)\angle\include\GLES2
    • (angle_root)\angle\include\KHR
  • コピー先:(project_root)\lib\GLES2\lib\x64
    • (angle_root)\angle\out\Debug\libEGL.dll.lib
    • (angle_root)\angle\out\Debug\libGLESv2.dll.lib
  • コピー先:(project_root)\x64\Debug
    • (angle_root)\angle\out\Debug\libEGL.dll
    • (angle_root)\angle\out\Debug\libGLESv2.dll
  1. 5で追加したファイルを使えるようにvcxprojの設定を変更します。
    「ソリューションエクスプローラー > OpenGLES2Test.vcxprojを右クリック > プロパティ(R )」を開き下記のように変更します。
    Property

  2. NuGetを使いGLFWをプロジェクトに追加
    glfw

# ▼ソースコードを構築

  1. プロジェクトに下記内容でMain.cppを追加しビルドします。
#include <Windows.h>
#include <iostream>
#define GLFW_INCLUDE_ES2
#define GL_GLEXT_PROTOTYPES
#include <GLFW/glfw3.h>
#if defined(GLFW_INCLUDE_ES2)
#   pragma comment(lib, "libEGL.dll.lib")
#   pragma comment(lib, "libGLESv2.dll.lib")
#else
#   pragma comment(lib, "opengl32.lib")
#endif
namespace
{
    constexpr int WindowWidth = 800;
    constexpr int WindowHeight = 600;
    const char* AppTitle = "OpenGLES2";
}
int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    if (glfwInit() == GL_FALSE)
    {
        return -1;
    }
    // エラーコールバック
    glfwSetErrorCallback([](int error, const char* description){
        std::cout << "glfw err[" << error << "] " << description << std::endl;
        fprintf(stderr, "err[%d] %s\n", error, description);
    });
    glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    // ウィンドウの生成
    auto window = glfwCreateWindow(WindowWidth, WindowHeight, AppTitle, nullptr, nullptr);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }
    // キー入力コールバック
    glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
        if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
            glfwSetWindowShouldClose(window, GL_TRUE);
        }
    });
    // OpenGLの処理対象にする
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);
    while (glfwWindowShouldClose(window) == GLFW_FALSE)
    {
        glfwPostEmptyEvent();
        // 更新
        glViewport(0, 0, WindowWidth, WindowHeight);
        glClear(GL_COLOR_BUFFER_BIT);
        glClearColor(0.f, 0.5f, 0.f, 1.f);
        glfwSwapBuffers(window);
        glfwWaitEvents();
    }
    glfwDestroyWindow(window);
    glfwTerminate();
    return -1;
}
  1. 表示結果を確認します。
    Window

長くなりましたが無事にOpenGLES2.0のビルドができました。

# ■参考URL

# 余談

参考URLはGLFWの書き方などを参考にさせていただきました。
環境構築に多数のサイト・ブログを拝見しましたがどうもうまくいかず、最終的には公式に書いてある手順通りにやったところ成功しました。
常に最新の情報に更新していくのは難しいのでしょうがないですね。