OpenGLのとっかかり GLFW Ubuntu16.04

## 目次
- [目次](#目次)
- [目的](#目的)
- [OpenGLとは](#openglとは)
    - [OpenGL](#opengl)
    - [GLUT](#glut)
    - [freeGLUT](#freeglut)
    - [GLFW](#glfw)
    - [GLEW](#glew)
- [環境](#環境)
    - [環境構築](#環境構築)
- [背景色のみ表示するコードを書いてみる](#背景色のみ表示するコードを書いてみる)


## 目的
　OpenGLをやってみたいけどOpenGL, GLFW, GLUT, GLEWなどいろいろ種類があってわけがわからずどっから手を付ければいいかわからない人のための記事です。
　この記事は以下の文書の序盤の大いに参考にしました。WindowsやmacOSでの例なども詳細にそしてわかりやすく書いてありますし、ちゃんと勉強したい人は最初からこちらを読むといいと思います。

- [◯◯くんのために一所懸命書いたものの結局◯◯くんの卒業に間に合わなかった GLFW による OpenGL 入門 (draft 版) - 和歌山大学システム工学部 床井浩平](http://marina.sys.wakayama-u.ac.jp/~tokoi/GLFWdraft.pdf) [^1]

　ただ、Ubuntuで実装する際に`apt`経由でインストールしたときはgccのオプション指定が少し異なるので、そこらへんを参考にしていただければと思います。


## OpenGLとは

### OpenGL
　まずOpenGLとはコンピュータグラフィックスなどに必要なグラフィックス表示機能を抽象化し、整理したグラフィックスライブラリです。ただ、ここで注意が必要なのはOpenGLはあくまでグラフィックスの演算部分を担当するだけであり、実際に画面に表示するのはOSにもっと近い部分が担当します。OpenGLはそれに描画する内容を渡す役割を持ちます。


### GLUT
　OpenGLはプラットフォーム非依存ではありますが、多少プラットフォームごとに異なる実装が必要となるためその部分を吸収したツールキットがいくつか存在します。
　そのなかにGLUT (OpenGL Utility Toolkit) があり、マルチプラットフォーム対応であるため、UNIX/Linux、Windows、macOS 間で共通なコードを書くことができます。
　しかしながら、オリジナルのサイトでじゃメンテナンスがあまりされていないようです。

[GLUT - The OpenGL Utility Toolkit](https://www.opengl.org/resources/libraries/glut/)


### freeGLUT
　GLUTの代わりに、GLUTと互換性を持った[freeGLUT](http://freeglut.sourceforge.net/)が開発されています。


### GLFW
　GLUT以外のオープンソースマルチプラットフォーム対応ライブラリとして[GLFW](https://www.glfw.org/)があります。他のツールキットに比べて小さめのキットで学習用にはちょうどいいようです。


### GLEW
　OpenGLの拡張機能を手軽に使うことができるようにするためのマルチプラットフォーム対応ライブラリが[GLEW (The OpenGL Extension Wrangler Library)](http://glew.sourceforge.net/)です。

　GLFWの特徴として以下のようなことが挙げられていました。[^1]

> - コンパクト
> - マルチプラットフォーム
> - OpenGLのバージョンやプロファイルが指定可能
> - 最初からでダブルバッファリング
> - イベントループを自分で書く
> - ポーリング方式とコールバック方式のどちらにも対応
> - マルチウィンドウやマルチモニタに対応
> - ユーザ定義のポインタを保存できる
> - 入力デバイスの取り扱い方法が異なる
> - GLUTにあってGLFWにない機能
>   - CubeやSphere、Teapotのような図形を表示する機能は省かれている
>   - ビットマップフォントをレンダリングする機能がない
>   - ポップアップメニュー表示機能がない


## 環境

| | Version |
|---|---|
| OS | Ubuntu16.04 |
| OpenGL | |
| GLFW | |
| GLEW | |

※Ubuntu以外でやりたい方は元の文書からどうぞ [^1]

### 環境構築

```
$ sudo apt-get install -y libx11-dev xorg-dev \
                          libglu1-mesa libglu1-mesa-dev \
                          libgl1-mesa-glx libgl1-mesa-dev
$ sudo apt install -y libglfw3 libglfw3-dev
$ sudo apt install -y libglew-dev
```


## 背景色のみ表示するコードを書いてみる

### コード
　同一ディレクトリ内に以下の`Makefile`と`main.cpp`ファイルを作成します。

```:Makefile
CXXFLAGS = -g -Wall -std=c++11
LDLIBS = -lGL \
		 -lglfw
OBJECTS = $(patsubst %.cpp,%.o,$(wildcard *.cpp))
TARGET = sample


${TARGET} : ${OBJECTS}
	${LINK.cc} $^ ${LOADLIBES} ${LDLIBS} -o $@

.PHONY : clean
clean :
	-${RM} ${TARGET} ${OBJECTS} *~ .*~ core
```


```cpp:main.cpp
#include <cstdlib>
#include <iostream>
#include <GLFW/glfw3.h>


int main()
{
  ////////////////////////////////////////////////////////////////////////////////
  // GLFW の初期化 (GLFW)
  if (glfwInit() == GL_FALSE){
    // 初期化に失敗した処理
    std::cerr << "Can't initialize GLFW" << std::endl;
    return 1;
  }


  ////////////////////////////////////////////////////////////////////////////////
  // 終了時の処理登録 (GLFW)
  atexit(glfwTerminate);


  ////////////////////////////////////////////////////////////////////////////////
  // ウィンドウを作成 (GLFW)
  GLFWwindow * const window(glfwCreateWindow(/* int           width   = */ 640,
                                             /* int           height  = */ 480,
                                             /* const char  * title   = */ "Hello!",
                                             /* GLFWmonitor * monitor = */ NULL,
                                             /* GLFWwindow  * share   = */ NULL));
  if (window == NULL){
    // ウィンドウ作成に失敗した処理
    std::cerr << "Can't create GLFW window." << std::endl;
    return 1;
  }

  // 作成したウィンドウを処理対象とする (GLFW)
  glfwMakeContextCurrent(/* GLFWwindow *  window = */ window);

  // 背景色 (OpenGL)
  glClearColor(/* GLfloat red   = */ 0.2f,
               /* GLfloat green = */ 0.2f,
               /* GLfloat blue  = */ 0.2f,
               /* GLfloat alpha = */ 0.0f);


  ////////////////////////////////////////////////////////////////////////////////
  // ループ処理

  // ウィンドウが開いている間繰り返す
  while (glfwWindowShouldClose(/* GLFWwindow * window = */ window) == GL_FALSE){
    // ウィンドウを消去 (GLFW)
    glClear(/* GLbitfield mask = */ GL_COLOR_BUFFER_BIT);

    // 描画処理

    // カラーバッファ入れ替え <= ダブルバッファリング (GLFW)
    glfwSwapBuffers(window);

    // イベント待ち (GLFW)
    glfwWaitEvents();
  }

  return 0;
}
```


### 解説

1. GLFW の初期化
  1. [glfwInit()](https://www.glfw.org/docs/latest/group__init.html#ga317aac130a235ab08c6db0834907d85e)
1. ウィンドウ作成
    1. [GLFW: Window reference](https://www.glfw.org/docs/latest/group__window.html)
    1. [glfwCreateWindow()](https://www.glfw.org/docs/latest/group__window.html#ga5c336fddf2cbb5b92f65f10fb6043344)
        1. ウィンドウを作成したとしてもそのウィンドウが描画の対象にしていされていないので次の`glfwMakecontextCurrent()`で処理対象にします。
    1. [glfwMakeContextCurrent()](https://www.glfw.org/docs/latest/group__context.html#ga1c04dc242268f827290fe40aa1c91157)
        1. ウィンドウを処理対象に指定
    1. [glClearColor()](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClearColor.xhtml)
        1. 最初のカラーバッファ設定
1. ループ処理
    1. [glfwWindowShouldClose()](https://www.glfw.org/docs/latest/group__window.html#ga24e02fbfefbb81fc45320989f8140ab50)
        1. ウィンドウを閉じるかどうかの判断
    1. [glClear()](https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glClear.xhtml)
        1. maskに指定したバッファを塗りつぶす
    1. [glfwWailEvents()](https://www.glfw.org/docs/latest/group__window.html#ga554e37d781f0a997656c26b2c56c835e)
        1. マウスの操作などのイベント待ち
        2. イベント発生後に処理再開
1. ダブルバッファリングのバッファ入れ替え
    1. [glfwSwapBuffers()](https://www.glfw.org/docs/3.0/group__context.html#ga15a5a1ee5b3c2ca6b15ca209a12efd14)
        1. ダブルバッファリングにおけるカラーバッファの入れ替え
1. ウィンドウを閉じ、終了処理
    1. [glfwTerminate()](https://www.glfw.org/docs/latest/group__init.html#gaaae48c0a18607ea4a4ba951d939f0901)
        1. GLFWの終了処理
        1. 初期化成功したときにプログラム終了前にこの関数の実行が必要


### 実行

```
$ ./sample
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/195174/2660c960-5099-440e-821b-b6188c58f99e.png)


## 図形を描画してみる

結構、長くなりそうなので近いうちに別記事で ( _ _ )


## 参照
- [OpenGL Wiki](https://www.khronos.org/opengl/wiki/)
- [OpenGL SDK](https://www.opengl.org/sdk/)
- [How to Install OpenGL on Ubuntu Linux](http://www.codebind.com/linux-tutorials/install-opengl-ubuntu-linux/)
- [GLEW: The OpenGL Extension Wrangler Library](http://glew.sourceforge.net/)
- [GLEWについて - PukiWiki for PBCG Lab](http://www.slis.tsukuba.ac.jp/~fujisawa.makoto.fu/cgi-bin/wiki/index.php?GLEW%A4%CB%A4%C4%A4%A4%A4%C6)
- [linux - How to print the ld(linker) search path - Stack Overflow](https://stackoverflow.com/questions/9922949/how-to-print-the-ldlinker-search-path)


[^1]: [◯◯くんのために一所懸命書いたものの結局◯◯くんの卒業に間に合わなかった GLFW による OpenGL 入門 (draft 版) - 和歌山大学システム工学部 床井浩平](http://marina.sys.wakayama-u.ac.jp/~tokoi/GLFWdraft.pdf)