GLFWでウィンドウを表示する

連載一覧 "re:ゼロから始めるOpenGL 2.1"

タイトルにもありますが、GLFWを使って進めていきます。
GLUT(またはFreeGLUT)でも別にいいのですが、GLUTは若干直感的でないですし、コンテキスト関連の理解がしにくいですし、メンテナンスされていないのはそれなりの理由があるということでGLFWを使っていきます。

ここまでディスっといてなんですが、作者はいつもGLUTを使っています(笑)
まぁ、どちらを選んでもそこまで大きな差があるというわけでもないので、「俺はGLUTを使うんだ」って人を止める気はありません。
その都度、読み替えてください。

始める前に大事な話を1つしておかなければなりません。
これをやるかどうかで大きくあなたの成長速度が変わってくるようなことです。

それは「コードをコピペしないこと」です。
自分の手でキーボードをたたいてプログラムを書いてください。

僕の書いたプログラムをそのままコピペしても賢くなるのは僕だけです(笑)
写す行為は原始的に見えますが、馬鹿にできないほど効果がありますのでお勧めです。
(コメントは説明のために書いているので別に写さなくてもいいですよ)

それでは始めていきましょう。

GLFWのサンプルと解説

まずはプログラム全体です。

#include "stdafx.h"
#include <iostream>
#include <gl/glew.h>
#include <GLFW/glfw3.h>


int main()
{
	// GLFW初期化
	if (glfwInit() == GL_FALSE) 
	{
		return -1;
	}

	// ウィンドウ生成
	GLFWwindow* window = glfwCreateWindow(640, 480, "OpenGL Simple", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}

	// バージョン2.1指定
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

	// コンテキストの作成
	glfwMakeContextCurrent(window);
	glfwSwapInterval(1);

	// GLEW初期化
	if (glewInit() != GLEW_OK) 
	{
		return -1;
	}

	// フレームループ
	while (glfwWindowShouldClose(window) == GL_FALSE) 
	{
		// バッファのクリア
		glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// ダブルバッファのスワップ
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	// GLFWの終了処理
	glfwTerminate();

    return 0;
}

解説していきます。

#include "stdafx.h"
#include <iostream>
#include <gl/glew.h>
#include <GLFW/glfw3.h>

stdafx.hはVisual C++に必要なものだと思ってください。
C++は仕様に従っていろんなところがコンパイラを作っています。
そのコンパイラによって微妙に仕様が違ったりします。

iostreamはC++の標準関数の1つです。

glew.hは「#include <gl/GL.h>」よりも先にインクルードしなければエラーになります。
ここで気づいた人もいるかもしれませんが、このプログラムではgl/GL.hなんてインクルードしていません。

これはglfw3.hに含まれているからだと考えられます。
GLFWはOpenGLを使うためのライブラリなので非常に合理的ですね。
なのでGLUTなどを使った場合は「#include <gl/GL.h>」を記述してください。

	// GLFW初期化
	if (glfwInit() == GL_FALSE) 
	{
		return -1;
	}

GLFWを初期化しています。

	// ウィンドウ生成
	GLFWwindow* window = glfwCreateWindow(640, 480, "OpenGL Simple", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		return -1;
	}

glfwCreateWindow()によってウィンドウを生成しています。
第1引数はwidth、第2引数はheight、第3引数はウィンドウタイトルです。

その後、きちんとウィンドウが正常に生成できなかった場合、glfwTerminate()によってウィンドウの終了処理をしています。

	// バージョン2.1指定
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);

OpenGLバージョンの指定はglfwWindowHint()によって行います。

ちなみにこれはGLFW3の書き方です。
GLFW2ではglfwOpenWindowHint()だったので、古いサンプルはこっちの関数を使っているかもしれません。

変更点はこちらにまとめられています。

	// コンテキストの作成
	glfwMakeContextCurrent(window);

	glfwSwapInterval(1);

	// GLEW初期化
	if (glewInit() != GLEW_OK) 
	{
		return -1;
	}

glfwMakeContextCurrent()によってコンテキストを作成しています。
glfwSwapInterval()はのちに出てくるglfwSwapBuffers()に関連した設定で、ダブルバッファリングのバッファの入れ替えのタイミングを指定します。
1以外を設定することはほぼないと思います。

GLEWを初期化していますが、これはコンテキスト作成後にしなければならない点が注意です。

	while (glfwWindowShouldClose(window) == GL_FALSE) 
	{
		// バッファのクリア
		glClearColor(0.2f, 0.2f, 0.2f, 0.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		// ダブルバッファのスワップ
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

glClearColor(Red, Green, Blue, Alpha値)はのちに実行されるglClear()がカラーバッファをクリアして設定する色を指定します。それぞれが範囲[0,1]を取ります。

画面の更新をする際、glFlush()やSwapBuffers()系の関数を使用します。

glFlush()は描画を直ちに行いことを意味します。
ただ、これでアニメーションさせると更新する際にちらつきが出てしまします。

なので今回の様に頻繁に画面を更新するのであればglfwSwapBuffers()を用います。

わからなければglfwSwapBuffers()を使っておけばいいです。

glfwPollEvents()はマウスやキーボード、ウィンドウサイズの変更などのイベントの取得を行います。
glfwSwapBuffers()に含まれているのでいらないって書いてるサイトもありましたが、これがないとうまく動きませんでした。
まぁ、必要なのでしょう(思考放棄)

連載一覧 "re:ゼロから始めるOpenGL 2.1"

あわせて読みたい