OpenGL ES 2.0 その01

大往生、2月か。侍道3とHaloWarsもあるというのに…。

とはいえ、大往生はすでにAmazonで予約済み。デススマイルズの限定版はすでに品切れ(泣。

さて、スティックをどうするか考えないと。

と言うわけでGLES2.0を使ってみようのコーナー、第1回。

前回はイントロダクション、って感じで。本格的に今回から。

本格的に、とか言っても今回は初期化のみ。別のサンプル作ってて時間がなくなったので。

GLESの初期化にはEGLライブラリを使用します。

EGLライブラリはネイティブ・プラットフォーム・グラフィクス・インターフェイス。つまり、OSやらハードウェアやらとの間を取り持ってくれるライブラリです。

基本的に、ウィンドウに関する処理はほぼこいつがやってくれます。実際、今回はこれだけです。

WindowsエミュレータでGLESを使用する場合、まずはウィンドウを作成します。これはDirectXを使う場合と変わりません。

ただ、DirectXはウィンドウハンドル(HWND)があれば良かったのですが、GLESではデバイスコンテキストが必要になります。なので、これを取得します。

HDC    hDC = GetDC( hWnd );

次にこのデバイスコンテキストからGL用ディスプレイを作成します。

EGLDisplay    eglDisplay = eglGetDisplay( hDC );

if( eglDisplay == EGL_NO_DISPLAY )

{

    // 失敗した時用

    eglDisplay = eglGetDisplay( (EGLNativeDisplayType)EGL_DEFAULT_DISPLAY );

}

EGLDisplay は void* の typedef です。他にも void* の typedef がいくつかありますが、void* を使用するのは避けましょう。当たり前ですが。

ではOpenGLを初期化しましょう。

// GLを初期化する

if( !eglInitialize( eglDisplay, &majorVersion, &minorVersion ) )

{

    return false;

}

初期化の際にバージョンを取得できます。いらないのであれば NULL を指定してもかまいません。

// コンフィグ

const EGLint pi32ConfigAttribs =

{

    EGL_LEVEL,    0,

    EGL_SURFACE_TYPE,  EGL_WINDOW_BIT,

    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,

    EGL_NATIVE_RENDERABLE, EGL_FALSE,

    EGL_DEPTH_SIZE,   EGL_DONT_CARE,

    EGL_NONE

};

// コンフィグ選択

EGLConfig eglConfig;

int  nConfigs;

if( !eglChooseConfig( eglDisplay, pi32ConfigAttribs, &eglConfig, 1, &nConfigs ) || (nConfigs != 1) )

{

    return false;

}

この命令は指定のコンフィグに見合ったフレームバッファ構成を取得します。

コンフィグは1次元配列ですが、実際には2つで1つです。つまり、偶数番目が項目、奇数番目がその値という形で、終端の偶数番目にEGL_NONEを置きます。

指定の構成が見つかれば nConfigs に見つかった構成の数が入ってきます。今回は1つだけならOKという形を取っています。

// サーフェイスを作成する

EGLSurface eglSurface = eglCreateWindowSurface( eglDisplay, eglConfig, eglWindow, NULL );

if( eglSurface == EGL_NO_SURFACE )

{

    return false;

}

EGLSurface も void* の typedef です。eglWindow は中身は HWND です。ネイティブ環境のウィンドウハンドルを入れておく必要があります。

// APIをバインドする

eglBindAPI( EGL_OPENGL_ES_API );

// コンテキストを作成する

EGLint ai32ContextAttribs = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };

EGLContext eglContext = eglCreateContext( eglDisplay, eglConfig, NULL, ai32ContextAttribs );

if( !TestEGLError( hWnd, "eglCreateContext" ) )

{

    return false;

}

レンダリングコンテキストを作成します。

コンテキスト作成前にAPIにOpenGLESを指定します。OpenVG(だっけ?)とかも選択できますが、今回必要なのはGLESです。

eglCreateContext() の第4引数はコンフィグの時と同じようなものを指定します。

第3引数は別のコンテキストを指定します。すると、そのコンテキストとテクスチャを共有することができます。

DirectXで言えば異なる2つのIDirect3DDeviceでテクスチャを共有できるようになるものと考えてください。

// ディスプレイ、サーフェイス、コンテキストを関連づける

eglMakeCurrent( eglDisplay, eglSurface, eglSurface, eglContext );

if( !TestEGLError( hWnd, "eglMakeCurrent" ) )

{

    return false;

}

ディスプレイ、サーフェイス、コンテキストを関連づけます。これで初期化は終了。

eglMakeCurrent() の第2,3引数は draw と read のサーフェイスを指定します。同じものを指定してもかまわないようです。

draw は描画されるサーフェイスなんですが、read は読み出し可能なサーフェイスってことかな?この辺がよくわかりません。

終了処理はデバイスコンテキストとウィンドウハンドルを解放すればOK。

// クリアカラーの設定

glClearColor( 0.6f, 0.8f, 1.0f, 1.0f );

// 画面クリア

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

// スワップ

eglSwapBuffers( eglDisplay, eglSurface );

画面に表示する処理はこんな感じ。当然、クリアからスワップまでの間で描画を行います。

DirectXと違って、画面クリアする前にクリア設定を行う必要があります。

一度設定すれば変更するまで設定を変える必要はありません。

楽と言えば楽かもしれませんが…実際にはあんまり意味ないですよね。

深度やステンシルの初期値もあらかじめ設定しておきます。

とまあ、適当すぎる解説で恐縮ですが、私も細部はよくわかってないもので。

少なくとも、こうすればたいていの環境では動くはずです。たぶん。