Windows環境でOpenGL ES 2.0の開発

この記事では、Visual Studio 2013(C/C++)を使ってOpenGL ES 2.0を使ったアプリケーション開発を行うための環境構築および各方法のメリット・デメリットについて記載します。なお、以下、本記事ではOpenGL ES 2.0のことを単にOpenGL ESを表記する場合があります。また、OpenGL ES等のグラフィックAPIに関する基礎知識の解説は省略します。

技術的な内容をできるだけ前方に記載しており、筆者の抱えている問題点などは後方に記載するようにしています。ただし、筆者本人のメモ書き的な側面が多いため、内容のわかりやすさについてはご了承下さい。また、記事中では利用するライブラリのライセンスも記載していますが、筆者の調査に誤りがある可能性もあるため、実際に利用する際には必ず各ライブラリのライセンス条項を確認するようにして下さい。

#Windows上でOpenGL ES 2.0を動作させる方法

WindowsのアプリケーションでOpenGL ESを動作させるためには、主に以下の2つの方法があります。

1. OpenGL 4.1以上を用いて、OpenGL ES 2.0 プロファイルを使う
2. ANGLEを利用する

それぞれについて、筆者自身が調べたことを記載していきます。

#OpenGL ES 2.0 プロファイルを使う

OpenGL 4.1から、OpenGL ES 2.0 のプロファイルに対応しました。つまり、WindowsでもOpenGL ES 2.0 をネイティブで動作させることができます。こちらの方法については、[小笠原さんの記事](http://wlog.flatlib.jp/item/1468)が詳しいので、そちらを参照下さい。私はこれらを試したことがないのですが、ドライバによって初期化処理などが異なり、使い方が難しいようです。

面倒な初期化処理を回避するために、OpenGL用のフレームワークを使う方法を考えてみます。OpenGL用のフレームワーク（ウィンドウを作ってくれて、入出力を管理してくれる）としては、以下が考えられます。

- [GLUT](https://www.opengl.org/resources/libraries/glut/) ( [freeGlut](http://freeglut.sourceforge.net/) )
- [GLFW](http://www.glfw.org/)

このうち、GLFWはウィンドウの作成前にプロファイル設定ができます。そのため、GLFWを使ってOpenGL ES 2.0の開発を行うことにします。

##GLFW3を使ったOpenGL ES 2.0の開発
GLFWは、WindowsやOS Xなど、様々なデスクトップ環境で動作するフレームワークです。ライセンスもzlib/libpngのため、取り入れやすいメリットがあります。さらに、emscripten（筆者は1.35.0で試しました）もサポートしているため、Web上への移植も容易になります。iOSやAndroidには対応していないため、こちらでも共有のソースコードを利用するためには、初期化処理は切り離しておく必要がありそうです。
GLFWのバージョンは3.1が現行のようですので、こちらのバージョンをベースに記載します。

##GLFW3の導入
[GLFWのサイト](http://www.glfw.org/)から、ライブラリをダウンロードします。サイト右上の[Download]からWindows用のコンパイル済みバイナリもダウンロードできるため、こちらを利用するのが便利でしょう。Visual Studio 2010～2015までのバイナリが含まれているため、Visual Studioを使った開発にはとても便利です。
Visual Studioのプロジェクト（ソースコード）の方でglfw3.hヘッダをインクルードし、適切なライブラリをリンクして下さい。

##OpenGL ES 2.0 プロファイルを用いて初期化
GLFW3では、ウィンドウの作成前にglfwWindowHint関数を用いてプロファイルの設定が行えます。OpenGL ES 2.0 用に設定するためには以下のようにします。

```
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
```
この設定を行った後、ウィンドウを作成することで、OpenGL ES 2.0プロファイルを用いて初期化されたOpenGLのコンテキストが作成されます。
このように設定することで、GLSL ES 1.0 のシェーダーを使用することができます。

ちなみに、ウィンドウ生成前に

```
glfwWindowHint(GLFW_SAMPLES, 4);
```

のようにアンチエイリアス（マルチサンプリング）の設定をすることができます。便利ですね。

##OpenGL ES 2.0 用の関数がない > GLEWの導入

以上のように、GLFWを用いることでプロファイルの初期化を行うことはできますが、glfw3.hをインクルードしただけでは、glUseProgramのようなOpenGL 1.0に含まれていない関数が未定義になってしまいます。そこで、OpenGLエクステンション用のライブラリ[GLEW](http://glew.sourceforge.net/)を導入します。
[GLEWのサイト](http://glew.sourceforge.net/)からWindows用バイナリをダウンロードし、Visual Studioのプロジェクト（ソースコード）の方でglew.hヘッダをインクルードし、適切なライブラリをリンクして下さい（dllを使う版と静的リンク版があるようです。Release MX?は何かよくわかりませんが、筆者はReleaseの方で動作しました）。

GLEWは、使用前に初期化が必要です。必ず、glfwMakeContextCurrent後に呼び出して下さい。

```
	glewExperimental = GL_TRUE;
	GLenum  err = glewInit();
	if (err != GLEW_OK)
	{
		printf("Error: %s\n", glewGetErrorString(err));
	}
```

ちなみに、筆者の環境では`glewExperimental = GL_TRUE;`を呼び出さないと、glBindBufferでエラーが起きたことがあったため、念のためつけています。

##GLFW3を使った開発による、メリット・デメリット

さて、GLFW3を利用したOpenGL ESを用いた開発による、メリット・デメリットについてまとめておきます。

###**メリット**
先にも述べたとおり、GLFW3は様々なデスクトップ環境で動作するフレームワークです。そのため、ウィンドウの生成から入力処理までクロスプラットフォームな開発が行えます。
また、[emscripten](http://kripken.github.io/emscripten-site/)もこのフレームワークをサポートしているため、デスクトップ環境ではなく、Web環境でも動作するアプリケーションの開発が行えます。

###**デメリット**
GLFWを内部でOpenGLのプロファイル選択を呼び出していると考えられます。つまり、グラフィックカード（ドライバ？）がOpenGL 4.1以上に対応した環境でなければ動作しません。最近では、[Intel HD Graphics](https://ja.wikipedia.org/wiki/Intel_HD_Graphics)でも動作するため問題ないと思いますが、環境を選ぶことは否めません。
また、一般的な話ではないかもしれませんが、筆者のRadeon + Windows 8.1 環境ではOpenGL ESプロファイルでのウィンドウ生成に失敗しました。カードとドライバのバージョンは以下のとおりです。

![img00.png](https://qiita-image-store.s3.amazonaws.com/0/103854/504d7c0f-69da-4b78-6d1d-a7994dba419d.png)

OpenGLは4.4に対応しているため問題ないと思うのですが、やはりWindows環境でOpenGLを直接触るのはいくらか不安が残ります。


#ANGLEを利用する

WindowsでのOpenGL利用には不安が…そんな思いは、Googleさんも抱えていたようで、OpenGL ES APIのDirectX実装を行ったオープンソースプロジェクトが存在します。それが、[ANGLE](https://github.com/google/angle)です。以前はGoogle Codeにあったのですが、現在はgithubに移っています。
ANGLEは、ChromeのWebGL実行部分にも利用されているもののようです。ライセンスはBSDとのことです。

ANGLEにはEGL（OpenGL ESのコンテキストを初期化するためのAPI）も含まれています。

##ANGLEのビルド

以前はVisual Studioのソリューションファイルが含まれていたのですが、現在は[depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools)が必要です。詳細は、[こちら](http://qiita.com/takao_mofumofu/items/110c3274846faf6f428c)の記事を御覧ください。

##ANGLEを使った開発による、メリット・デメリット

さて、ANGLEを利用する、メリット・デメリットについてまとめておきます。

###**メリット**
ANGLEを使うことで、OpenGL ES API は DirectX を用いて実行されます。XP環境（サポートは終了していますが）でも、安定して動作するようです。
また、ANGLEのブランチとして[Windows Store App 用のプロジェクト](https://github.com/MSOpenTech/angle)もあるようです。

###**デメリット**
アプリケーションを開発するにあたり、EGLを使ってコンテキストの初期化を行う必要があります。ウィンドウ生成なども当然OSに依存します。そのため、クロスプラットフォームにするためには、ウィンドウ作成や入出力などを自前で抽象化しておく必要があります。
また、現在のANGLE実装ではアンチエイリアス（マルチサンプリング）に対応していないようです。

***

#筆者のモチベーション

OpenGL ES 2.0 を使った開発を行うことで、様々な環境、特にモバイル環境で動作するアプリケーションの開発が行えます。
例えば、以下の環境で動作するアプリケーションの開発が可能です。

- iOS
- Android
- Webブラウザ

OpenGL ESを使う最大の理由は、おそらくiOSやAndroidで動作させるためでしょう。最近では、[emscripten](http://kripken.github.io/emscripten-site/)を使うことで、Webブラウザ上で動作できるようにコンパイルすることも出来ます。OpenGL ES 2.0部分コードは、[WebGL](https://www.khronos.org/webgl/)へコンパイルされます。WebGLはOpenGL ES 2.0のWeb移植のAPIのため、完全に互換性があります（あると思います）。

さて、モバイル環境やWeb環境では現在どこでも動作すると言って良いOpenGL ESですが、デスクトップ環境、特にWindowsでは動作させることが面倒になります。WindowsでもOpenGL ESを動作させることができれば、デスクトップ、モバイル、Webとグラフィック部分を（ほぼ）共有して開発することができます。さらに、Visual Studioの強力なコード補完やデバッグ機能を使ってクロスプラットフォームなアプリケーション開発も行えます。そのため、本記事では、OpenGL ES 2.0 を使ったWindowsのネイティブアプリケーション開発を行う方法を紹介しました。


#ところで、なんでわざわざ OpenGL ES 2.0 で開発しなきゃダメなの？

詳しい方はご存知かもしれませんが、OpenGL ESはOpenGLとある程度の互換性があります。そのため、いくらか注意しておけば、デスクトップではESではないOpenGLで動作させておき、モバイル環境ではOpenGL ESで動させるということも不可能ではありません。しかしながら、これはあくまでもOpenGLのAPIの話です。シェーダー言語であるGLSLでは少し異なります。（以下、GLSLとGLSL ESと出てきますが、これらは別物ですので注意して下さい。）

例えば、GLSLでは「attribute, varying」などのキーワードが削除になっていますが、GLSL ES 1.0ではこれらは現役です。これらのキーワードをGLSLで使用するためには、GLSL 1.3でコンパイルする必要がありますが、そのためにはシェーダの先頭に`#version 130`とバージョン宣言をする必要があります。しかし、この宣言があるとGLSL ESではコンパイルに失敗してしまいます。また、テクスチャ描画も上手く動かなかったため、その他にも細かな違いが存在するようです。

うまい方法があるのかもしれませんが、このシェーダー言語の互換性問題に頭を悩ませた結果、筆者はOpenGL ESを動かす方法を模索した次第です。

#筆者はどうしているのか？

筆者は、以下の環境で動作するようなグラフィックライブラリを構築しています。

- Windows
- Android
- iOS
- ブラウザ

各環境でそれなりに動作するように、以下のようにしています。なお、ウィンドウや入力の実装は、一段階抽象化しています。

| 環境 | ウィンドウ等の実装 | OpenGL ES |
|:---|:---|:---|
|Windows | WIN32API (ネイテイブ) | ANGLE |
|Android | Android API (Java) | ネイテイブ |
|iOS | ネイテイブ | ネイテイブ |
|ブラウザ(emscripten) | GLFW3 | WebGL |

ブラウザ用の構成は、開発用にWindowsでも動くようにしています。この構成は、Mac OS XやLinuxでも動くと思うのですが、試していません。改めて見ると、各環境用にそれぞれ実装していますが、それでもシェーダー部分や描画ロジックを共有できるため、便利に感じています。