2014/06/28

GLFW3 Getting Started 日本語訳

GLFW3 Getting Started 日本語訳

GLFW: Getting Startedの勝手な日本語翻訳です.GLFWを使い始める方は目を通しておくとよいでしょう.これを読めば,GLFWの大まかな使い方はわかるかと思います.
あ,オリジナル文書に用意されているリンクは機能してません><


目次

  • GLFWヘッダのインクルード
  • GLFWの初期化と終了
  • エラーコールバックの設定
  • ウィンドウとコンテキストの作成
  • OpenGLコンテキストをカレントにする
  • ウィンドウの閉じるフラグのチェック
  • 入力イベントの受信
  • OpenGLによるレンダリング
  • タイマーの読み取り
  • バッファのスワップ
  • イベント処理
  • 書いてみよう: 小さなGLFWアプリケーション


このガイドは、GLFW3を用いたシンプルなOpenGLアプリケーションを作る方法を解説します。 ここでは、最も頻繁に利用される幾つかの機能を紹介しますが、それら以外にも多くの機能が存在します。 GLFW関数の詳細なドキュメントを見る場合は、関数名をクリックしてください(訳注:リンクしてません:-().
このガイドは、以前のバージョンのGLFWを使った経験がない方を対象としています。 もしGLFW2を使ったことのある方は、移行ガイド日本語訳)もご覧ください。

GLFWヘッダのインクルード

プログラムのOpenGLやGLFWを使うファイルでは、GLFW3ヘッダファイルをインクルードする必要があります。

#include <GLFW/glfw3.h>

これはGLFWのAPIの全ての定数、型、関数プロトタイプを定義します。 また、OpenGLヘッダもインクルードされ、プラットフォームで動作させるのに必要な全ての定数と型が定義されます。
例えば、Windowsでは通常GL/gl.hをインクルードする前に、windows.hをインクルードする必要があります。これは、ソースファイルがWindowsに紐付けられて、コードの名前空間がWin32APIに汚染されます。
その代わりに、GLFWヘッダがそれを行いますが、windows.hをインクルードするのではなく、その必要部分だけを複製することで処理します。 これは必要な場合にだけ実施されるので、もしwindows.hをインクルード済みであればGLFWヘッダはそれらのシンボルの再定義は行いません。

つまり:
  • 自分でOpenGLヘッダをインクルードしないこと。GLFWが行います。
  • windows.hあるいはプラットフォーム固有のヘッダは、それらのAPIを直接利用するまでインクルードしないこと。
  • それらのヘッダが必要になった場合は、GLFWヘッダをインクルードする前にインクルードすること。GLFWはこれを検出する。
バージョン3.0からは、GLUヘッダglu.hはデフォルトでインクルードされなくなりました。 もしインクルードしたい場合は、GLFW_INCLUDE_GLUをGLFWヘッダのインクルードの前に定義してください。


#define GLFW_INCLUDE_GLU
#include <GLFW/glfw3.h>

GLFWの初期化と終了

GLFWの機能を使う前に、ライブラリを初期化しなければなりません。 これは、glfwInitで実行され、成功したなら非ゼロ、エラーが発生した場合はゼロを返します。

if (!glfwInit())
    exit(EXIT_FAILURE);

GLFWを使用しているときは、通常、プログラムの最後にglfwTerminateを呼び出す必要があります。

glfwTerminate();

これは、すべての残っているウィンドウを破棄して、すべての他のリソースを解放します。 これの呼出した後は、GLFW機能を利用する前に、再度glfwInitを呼び出す必要があります。

エラーコールバックの設定

ほとんどのイベント(キーが押されたとか、GLFWウィンドウが移動したとか、エラーが発生しているとか)は、コールバックを介して報告されます。 コー​​ルバックは単なるCの関数(またはC++の静的メソッド)で、イベントに関する引数を持ってGLFWによって呼び出されます。
glfwInitまたはその他GLFW関数が失敗した場合、GLFWエラーコールバックにエラーがレポートされます。 エラーコールバックを設定することで、これらのレポートを受け取ることができます。 コー​​ルバック関数自体はGLFWerrorfunのシグネチャと一致する必要があります。 ここに挙げるのは、単にstderrにエラーの説明を出力する単純なエラーコールバックです。

void error_callback(int error, const char* description)
{
    fputs(description, stderr);
}

コールバックを設定することで、GLFWはそれを呼び出せることを知らせるには、glfwSetErrorCallbackを使います。 これは、glfwInitより前に呼び出すことのできるGLFW関数のひとつで、初期化中にエラーが発生を通知を受け取るために、他のGLFWを使う前に設定するべきです。

glfwSetErrorCallback(error_callback);

ウィンドウとコンテキストの作成

ウィンドウ (とそのコンテキスト)glfwCreateWindowで作成され、作成されたウィンドウハンドルを返します。 例えば、640x480のウィンドウモードのウィンドウを作成するには次のようにします:

GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL);

ウィンドウ作成に失敗した場合は、NULLが返されるので、それを確認する必要があります。

if (!window)
{
    glfwTerminate();
    exit(EXIT_FAILURE);
}

このハンドルは、すべてのウィンドウ関連関数に渡され、入力イベントと共に提供されるので、どのウィンドウがその入力を受け取ったかを知ることができます。
フルスクリーンウィンドウを作成するには、どのモニタにそのウィンドウを表示するかを指定する必要があります。 ほとんどの場合、ユーザのプライマリモニタを選ぶのが良いです。 glfwGetPrimaryMonitorを使うとプライマリモニタを取得できます。 上述のウィンドウをフルスクリーンにするには、単にモニタハンドルを渡すだけです:

GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonitor(), NULL);

フルスクリーンウィンドウは、モニタの表示エリア全体をカバーし、境界や装飾を持たず、そして、モニタの解像度を要求したウィンドウサイズに最も近いものに変更します。
そのウィンドウを使い終えた時は、glfwDestroyWindow関数でウィンドウを破棄します。

glfwDestroyWindow(window);

この関数が一度呼び出されたら、そのウィンドウにはそれ以上イベントが届けられなくなり、そのハンドルは無効になります。

OpenGLコンテキストをカレントにする

OpenGLのAPIを使う前に、OpenGLコンテキストを取得しなければなりません。 ウィンドウのコンテキストをglfwMakeContextCurrentを用いてカレントにします。 他のコンテキストをカレントにするまで、あるいはコンテキストを所有するウィンドウが破棄されるまで、カレントコンテキストのままになります。

glfwMakeContextCurrent(window);


ウィンドウ閉じるフラグのチェック

各ウィンドウは、そのウィンドウが閉じられるべきであるかを示すフラグを持っています。 このフラグは、glfwWindowShouldCloseでチェックすることができます。
ユーザが、タイトルバーの閉じるボタンを押す、あるいはAlt+F4のようなショートカットで、ウィンドウを閉じようとした時、このフラグは1にセットされます。 その際、実際にはウィンドウはまだ閉じられていないことに注意してください。このフラグをモニタリングすることで、ウィンドウを破棄するか、ユーザに何らかのフィードバックを与えることができます。

while (!glfwWindowShouldClose(window))
{
    // Keep running
}

glfwSetWindowCloseCallbackでクローズコールバックを設定することで、ユーザがウィンドウを閉じようとした時に通知を受け取ることができます。 そのコールバックはクローズフラグがセットされた直後に呼び出されます。
glfwSetWindowShouldCloseを用いて、自分自身でそれをセットすることも可能です。 これは他の入力をウィンドウを閉じるに変換したいとき、例えば、エスケープキーの押下で閉じるようにしたいときに便利です。

入力イベントの受信

各ウィンドウは、すべての様々な種類のイベントを受け取るために設定できるコールバックを数多く持っています。 キー押下、押下解除イベントを受け取るには、glfwSetKeyCallbackでキーコールバックを設定します。

static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}

イベント発生時に実際に呼び出されるイベントコールバックに、上述したようなイベント処理が必要です。

OpenGLによるレンダリング

カレントOpenGLコンテキストを取得したあとは、OpenGLを普通に使えます。 このチュートリアルでは、多色の回転する三角形をレンダリングしてみます。 この例ではglViewportglOrthoで必要とされるフレームバッファのサイズは、glfwGetFramebufferSizeで受け取ることができます。

int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);

しかし、コールバックglfwSetFramebufferSizeCallbackを用いて、そこでglViewportを呼ぶことで、フレームバッファサイズを設定することも可能です。

void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}

タイマーの読み取り

三角形を適切に回転させるには、時間の情報源が必要です。 GLFWは、glfwInitからの経過秒数をdouble型で返すglfwGetTimeを提供しています。 時間の情報源は各プラットフォームにおける最も精確なものが利用され、一般にはマイクロ秒あるいはナノ秒の分解能を持っています。

double time = glfwGetTime();

バッファのスワップ

GLFWウィンドウは常にダブルバッファリングを使います。 2つのレンダリングバッファを持つことを意味しています; フロントバッファとバックバッファ。 フロントバッファは画面に表示されているもので、バックバッファはレンダリングの対象のものです。
フレーム全体のレンダリングが完了した時、レンダリングしたフレームを表示し、そして、新しいフレームのレンダリングを開始するために、バックとフロントを入れ替えます。 これはglfwSwapBuffersで行えます。

glfwSwapBuffers(window);

イベント処理

GLFWは、イベントの受け取りのため、および、ロックされていないことを示すための両方の目的のために、ウィンドウシステムと定期的に通信する必要があります。 イベント処理は定期的に行う必要があり、通常、各フレームのレンダリングの前にとバッファスワップの後に行われます。
保留中のイベントを処理する方法は2つあります。 glfwPollEventsはそれらの受信済みイベントだけを処理して、すぐにリターンします。 これは、ほとんどのゲームが行うように継続的にレンダリングする場合に最良のチョイスです。

glfwPollEvents();

新しい入力を受け取ったときにだけレンダリングの更新が必要な場合は、代わりに、glfwWaitEventsを使うのがベターです。 それは、少なくとも1つのイベントが受信されるまで待ち、その間はスレッドをスリープしておき、それから、glfwPollEventsが行うようにすべての受信イベントを処理します。 この方法は、CPUサイクルをかなり抑えることができ、例えば、いろんなエディットツールにおいて有用です。

glfwWaitEvents();


書いてみよう: 小さなGLFWアプリケーション

いま、GLFWを初期化し、ウィンドウを作成し、キーボード入力を取得する方法がわかったので、シンプルなプログラムを作成できるようになりました。

#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
static void error_callback(int error, const char* description)
{
    fputs(description, stderr);
}
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
        glfwSetWindowShouldClose(window, GL_TRUE);
}
int main(void)
{
    GLFWwindow* window;
    glfwSetErrorCallback(error_callback);
    if (!glfwInit())
        exit(EXIT_FAILURE);
    window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
    glfwMakeContextCurrent(window);
    glfwSetKeyCallback(window, key_callback);
    while (!glfwWindowShouldClose(window))
    {
        float ratio;
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        ratio = width / (float) height;
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glOrtho(-ratio, ratio, -1.f, 1.f, 1.f, -1.f);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glRotatef((float) glfwGetTime() * 50.f, 0.f, 0.f, 1.f);
        glBegin(GL_TRIANGLES);
        glColor3f(1.f, 0.f, 0.f);
        glVertex3f(-0.6f, -0.4f, 0.f);
        glColor3f(0.f, 1.f, 0.f);
        glVertex3f(0.6f, -0.4f, 0.f);
        glColor3f(0.f, 0.f, 1.f);
        glVertex3f(0.f, 0.6f, 0.f);
        glEnd();
        glfwSwapBuffers(window);
        glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
    exit(EXIT_SUCCESS);
}


このプログラムは、640x480のウィンドウモードの画面を作成してから、スクリーンの消去、三角形のレンダリング、イベント処理のループを、ウィンドウがユーザに閉じるまで行います。 これはソースコード配布のexamples/simple.cにあり、GLFWをビルドする時に、デフォルトで他のサンプルと一緒にコンパイルされます。
コンパイル GLFWを使うプログラムをコンパイル・リンクする方法について知りたい場合は、Building programs that use GLFWを参照してください。