はじめに
OpenGLというと、3DCG用のライブラリ、といったイメージがあるかもしれません。しかし、実際には画像データをフレームバッファとして保持し、表示する機能もあるので、2D画像処理ソフトの開発にも使うことができます。さらに、OpenGLと組み合わせて使うためのマウスやウインドウを制御する補助ライブラリも用意されており、そうしたライブラリで独自のGUIを作成すれば、ちょっとした汎用アプリケーションを作成できるマルチプラットフォーム開発環境としての側面も持っています。
本稿では、OpenGLのフレームバッファ描画機能と、各プラットフォームのマウス・ウインドウの基本的な機能を抽象化したAUXを使用し、簡単な画像処理ソフトを作ってみます。「ウインドウに自分で作成したメモリ上の画像データを描く」機能、「マウスクリック時にクリックされた座標に応じた処理を行う」機能を実装してみたので、OpenGLとAUXによる簡単な画像処理ソフト開発の基本的な流れを確認してみてください。
対象読者
Visual C++で簡単なプログラムを作ったことがある方。
必要な環境
- Windows 98以降のWindowsマシン
- Visual C++ 5以降、またはOpenGL関連ライブラリがインストールされているC++開発環境
OpenGL AUXによるウインドウとマウス処理
AUXベースのアプリケーション開発では、まずウインドウを作成します。そして、そのウインドウに描画を行う描画関数とマウスクリックなどのイベントを処理するイベント関数を定義し、その関数をAUXに登録します。これらの関数は、描画が必要になった時やマウスがクリックされた時など、必要に応じてAUXから呼び出され(コールバックされ)ますが、独自の処理を行う必要のない関数については、AUXのデフォルトの処理に任せればよいので、特に用意する必要はありません。
GLAUXによるウインドウの作成処理では、まずアプリケーションで使用する画面形式(今回はフルカラー)をauxInitDisplayMode()
で指定します。そして、auxInitPosition()
でアプリケーションのウインドウの位置と大きさを設定し、auxInitWindow()
でウインドウの初期化と表示を行う、という流れになります。ウインドウを出すだけなら、これだけの処理で可能です。
といっても、これだけではウインドウが一瞬出るだけでプログラムが終了してしまい、何もできません。ウインドウに描画したり、マウスクリックなどに応答するイベント処理を行うためには、描画用の関数やイベント処理用の関数を定義してAUXに登録し、auxMainLoop()
を呼び出してAUXのメインループに処理を委ねます。メインループに入ると、後はAUXの方で必要に応じて登録されている関数を呼び出し、アプリケーションが駆動されます。
auxMainLoop()
には、関数のポインタを一つ指定しますが、この関数がウインドウの描画を行う関数になります。この関数は、最初ウインドウが表示される時のほか、ウインドウの大きさが変わったり移動したりして、ウインドウの再描画が必要になったときに呼び出されるので、ウインドウ(画面上)に描画する処理をまとめておくようにしましょう。
int main(int argc, char*argv[]) { auxInitDisplayMode(AUX_SINGLE | AUX_RGBA | AUX_DEPTH); auxInitWindow(NULL); /* マウスボタンクリック時のイベント処理関数設定 */ auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, left); auxMouseFunc(AUX_RIGHTBUTTON, AUX_MOUSEDOWN, right); /* AUXのメインループへ */ auxMainLoop(draw); return 0; }
フレームバッファの描画
OpenGLには、glDrawPixels()
という、メモリ上のデータを特定形式の画像データとしてフレームバッファに転送する(画面上に表示する)関数が用意されています。この関数を、引数に画像の大きさと画像(ピクセル)形式、データの形式、画像データのポインタを指定して呼び出すと、メモリ上に作成した画像データを表示することができます。
指定できる画像の形式は、インデックス(カラーテーブル)やフルカラー、グレイスケール、R・G・Bの各単色スケールです。アルファチャネルも用意されています。通常はフルカラーやグレースケールを使う機会が多いでしょうが、RGBの単色スケールがあるのは面白いです。
各ピクセルは、画像形式で指定した形式で格納しますが、そのデータの形式(精度)も設定することができます。一般的な符号なし1バイト(0-255)のほか、符号付整数や実数も選択可能です。実際の画像データは、RGBA各要素やグレースケールの明るさなどを、指定した形式で格納していきます。
フルカラーデータを使用する場合は、RGBA各8ビットで1ピクセル32ビットの形式(色形式GL_RGBA
、データ精度GL_UNSIGNED_BYTE
)にすると、1ピクセルを32ビット符号なし整数に格納できるので便利でしょう。その場合、width
×height
ピクセルの32ビットフルカラー画像データpixels
を表示するには、以下のようにします。
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
画像データpixels
の各ピクセルは、下位から順にR、G、Bを各8ビット格納し、最上位のAは0にしておきます。
なお、glDrawPixels()
では「描画する位置」を指定しませんでしたが、これはOpenGLの現在のラスター位置に描かれるからです。現在のラスター位置を設定するにはglRasterPos2i()
を使います。つまり、任意の場所に画像を表示する場合は、最初にglRasterPos2i()
で位置を設定してからglDrawPixels()
で表示、という流れになります。
また、フルカラー以外のデータを利用する場合は、単色スケールを使うと「色違いで同じ形の画像」を簡単に表示できるので、面白い使い方もできるかもしれません。例えば、GL_UNSIGNED_BYTE
(符号なし8ビット)形式で適当なパターンデータを用意しておいて、それをglDrawPixels()
で表示する際、画像形式をGL_LUMINANCE
とすると白黒画像として、GL_RED
とすると赤の単色スケール画像として表示することができます。
マウスイベント処理
AUXに右クリックや左クリックといったマウスイベント処理用の関数を登録しておくと、右クリックや左クリックが発生したときに、その関数を自動的に呼び出してくれます。この関数は引数としてイベント情報構造体AUX_EVENTREC
を取るので、イベントが発生したマウスのカーソル座標もそこから取得できます。
/* マウス左ボタンクリック処理関数 */ GLvoid CALLBACK left(AUX_EVENTREC *event) { /* マウス座標取得 */ int x = event->data[AUX_MOUSEX]; int y = event->data[AUX_MOUSEY]; ・・・マウスイベントの処理 }
マウスクリックが発生すると自動的に再描画されますので、マウスクリックを処理する関数の中で表示する画像を生成するためのデータを更新すると良いでしょう。
アプリケーション
今回のアプリケーションは、画像ファイル(24ビットフルカラーBMPファイル)を読み込んで、その画像の色成分をマウスで増減する簡易画像処理ソフトです。画像ファイルのパスを引数に起動すると、その画像と、いくつかのボタンが並んだウインドウが表示されますので、ボタンをマウスでクリックしてみてください(このボタン群は、同じパターンデータを「色違い」で表示しています)。
白いボタンをクリックするとRGBすべて(明るさ)が、赤ならRが、緑ならGが、青ならBが左クリックで加算、右クリックで減算されます。
まとめ
AUXを使うと、ウインドウシステムをほとんど意識することなく(デフォルトの座標系など若干の注意は必要)、ウインドウベースのアプリケーションを開発することができます。この種のライブラリでは、GLUTの方が一般的ですが、今回のようなちょっとしたアプリケーションならAUXでも十分でしょう。特にVC++の場合、AUXなら標準で入っているので追加でライブラリをインストールする手間もなく、すぐにプログラムを作り始めることができます。
OpenGLに興味を持っている方は、まずはAUXで、気軽に手持ちの画像をいじって遊ぶ「画像処理ソフト」を作ってみてはいかがでしょうか。