GLUTの初期設定と意外な点について

## はじめに
もともとゲーム制作体験記を書こうとしていたのですが、冗長になって飽きてしまいました.
体験記はクリスマスに友達と過ごしたいねという願いとともに焼却処分しておきます。

さて、4JでGLUTを履修するのですが、意外と呪文のような場所が多くありましたよね。その中で今回はGLUTの初期設定に的を絞ってお話ししていこうと思います。

## GLUTの初期設定を復習する
GLUTでは```main```関数内の最初で初期設定としてこんな感じのコードを書きます。
4J・5Jの方々は何となく覚えているでしょうか。

```C
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize (WINDOW_INIT_WIDTH, WINDOW_INIT_HEIGHT);
glutCreateWindow ("Simple Multi-Functional Clock");
glutInitDisplayMode (GLUT_ALPHA | GLUT_RGBA);
glClearColor (0.45, 0.72, 0.89, 1.0);
glEnable (GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// この先にコールバック関数の宣言やglutMainLoop()が続く
}
```

各関数でやっていることは大体こんな感じになります(筆者のアナログ時計レポート参考)。
- **```glutInit```関数** GLUTライブラリの初期化, ウインドウシステムに対しセッションの掛け合わせを行う.
- **```glutInitWindowSize```関数** GUIのウインドウの起動時のサイズを設定. ここではウインドウサイズの幅と高さに, 定数として事前に定義した値を指定している.

- **```glutCleate関数```** ウインドウの生成が行われる. 引数としてアプリケーションの名前を渡す. 

- **```glutInitDisplayMode```関数** GLUTの表示モードの初期設定を行う. この関数は, 引数に表示モードを指定する. 複数の表示モードを指定する際には論理和を使用する.

- **```glutEnable```関数** OpenGLの各種機能の有効化. <-> **```glutDisable```関数**
    + ex1. ```GL_BLEND``` カラーバッファに色情報を書き込む際の混合処理を行う(半透明な物体を描画する時用)
    + ex2. ```GL_TEXTURE2D``` テクスチャリング(図形にテクスチャを貼り付けて描画)するときに利用

- **```glutBlendFunc```関数** 混合処理の計算方法を指定. 計算方法の種類は様々. (ここでは省略)

- **```glTexEnvf```関数** テクスチャ環境の変数を指定する。

下3つは確か画像貼り付けに用いた記憶があります。

## 本題：```glutInitDisplayMode```の意外な事実
さて、```glutInitDisplayMode```関数ですが、「透明モードを用いないときは```GLUT_RGB```, 透明モードを用いるときは```GLUT_RGBA | GLUT_ALPHA```とする」とよく言われます。 こんな感じですね。

```C
glutInitDisplayMode(GLUT_RGB); //RGB
glutInitDisplayMode(GLUT_ALPHA | GLUT_RGBA); //RGBA
```

これですが、実は```GLUT_RGBA```も```GLUT_RGB```も**必要ありません**。

実際に筆者自身で値を表示させてみた結果ですが、このようになりました。[^1]
ちなみに説明は公式のリファレンスページをみて簡単に書いたものになります。
ちゃんとした説明を見たい場合にはサイトを見てください。

https://www.opengl.org/resources/libraries/glut/spec3/node12.html

|  モード名 | 説明 | 値 |
| ---- | ---- | ---- |
|  ```GLUT_RGBA```  | RGBAモード  | 0 |
|  ```GLUT_RGB```  | RGBAのエイリアス | 0 |
| ```GLUT_SINGLE``` | 単一バッファウインドウ | 0 |
| ```GLUT_INDEX``` | カラーインデックスモード | 1 |
|```GLUT_DOUBLE``` | ダブルバッファウインドウ | 2 |
|```GLUT_ACCUM``` | 蓄積バッファウインドウ | 4 |
|```GLUT_ALPHA``` | アルファ値を含むウインドウ | 8 |
|```GLUT_DEPTH``` | デプスバッファ付きのウインドウ | 16 |
|```GLUT_STENCIL``` | ステンシルバッファ付きのウインドウ | 32 |
|```GLUT_MULTISAMPLE``` | マルチサンプリングのサポート | 128 |
|```GLUT_STEREO``` | ステレオウインドウ | 256 |
|```GLUT_LUMINANCE``` | 輝度カラーモデルのウインドウ | 512 |

さて、先ほどこの関数については次のように説明をしました。

> **```glutInitDisplayMode```関数** GLUTの表示モードの初期設定を行う. この関数は, 引数に表示モードを指定する. 複数の表示モードを指定する際には**論理和**を使用する.

はい。複数指定の場合は「論理和」を使用するという点です。

ここでもう一度モードの表を見てみましょう。指定するモードに対応する値はすべて2の累乗で表される値になっています。つまり、「どこか1つのビットだけが1」になるように設定されています。論理和を行うことで、 複数のモードを指定すると「各モードに対応したビット」が複数1になる、それによってモードの判別をしていると推測できます。

[^1]: あの、64ってないんですか？え、64って使われてないんですか？かわいそうじゃないんですか？(うるさい)

話をもとに戻しますが、今回```GLUT_RGBA```も```GLUT_RGB```も値が0になっているため、どちらを指定してもよい。なんなら指定しなくてもよい。ということになります。

## 透過モードの正体
さっきの話を踏まえると、このような引数の渡し方も大丈夫だよ～ということになります。
```C
glutInitDisplayMode(0); //RGB
glutInitDisplayMode(GLUT_RGB); //RGB
glutInitDisplayMode(GLUT_ALPHA); //RGBA
```
つまり、実際の透過モードの判定は```GLUT_RGBA```が指定されているかではなく, ```GLUT_ALPHA```が指定されているかどうか、つまり下から4ビット目($2^{4-1}=8$)に1が立っているかどうかにあるということになります。

ダブルバッファリング (片方のバッファを画面表示としてもう一方を描画用として交互に切り替える方法、画面のちらつきを軽減する) の設定を行うときには ```GLUT_DOUBLE```を指定しているのにその反対、```GLUT_SINGLE```は指定しなくてよいというのも(多分)同じ理屈です。

### まとめ
今回は```GLUT_RGBA```も```GLUT_RGB```も値は0だよ！複数モード指定の時は論理和を取るとどうせなくなっちゃうからそもそもいらないよ！ということを記事にしていきました。ただし、ここで私の言いたいことは別にあります。
じゃあ、このコードをぱっと見で理解できますか？ということです。

```C
glutInitDisplayMode(0);
```

逆に、最初の例の場合は、コメントのような意味としてとらえることができます.
どちらが良いかはあなた次第になります。

```C
// 「RGBモード有効」
glutInitDisplayMode(GLUT_RGB);
// 「RGBAモード有効」そのため、「ALPHAチャネルも有効」
glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA); 
// 「ALPHAチャネル有効」だけでも伝わるかもしれない
glutInitDisplayMode(GLUT_ALPHA);
```

## おわりに
皆さんは「これは書く必要がないから消した」、「こう書いたらかっこいい」でプログラミングをしていませんか？
プログラムにつけるコメントもそうです。「自分が分かっているし面倒だからこれは書かなくてもいい。」「自分が分かっているから相手もすぐ理解できるはずだ。」と思うのは命取りになります。共同開発は言わずもがな、個人開発でももしかしたら忘れたころに手直しするかもしれないです。そういったときに例えばこの記事の内容、覚えているでしょうか？あ、そうだ。ねえ、ねこみみ君、これ書いてるけど君もだからね？結局コメントも書かずに脳筋コーディングしてC-CRAFT手直しできなかったでしょ^*。今、学生のうちにプログラムにコメントを付ける、丁寧なコーディングをすることを心掛けることは大切だよ。というお話でした。

以上になります。良いクリスマスライフを！(うっ何かが刺さったような)。
アドベントカレンダー書くのは難しいね。