今月号(2002年2月号)のC Magazineでは、SDLの特集が組まれています。SDLは、グラフィックやサウンドなどを扱うライブラリで同じソースをLinuxやWindowsなど複数のプラットフォームで利用できるのですが、特にLinuxでは最近SDLで開発されたゲームが目立つようになって来ましたね。今回は、C Magazineに収録されているSDLをLinuxにインストールして、ウインドウ上にフレームバッファを表示してみました。
インストールは、ソースのパッケージをコピーし、makeしてインストール、その後パスの設定などを行うだけです(バイナリのパッケージもあります)。Linuxならgccなどの開発環境も一通りそろっているでしょうから、環境整備はそれほど難しくないでしょう。
SDLでは、画像をサーフェスという単位で扱います。これは、DirectXのサーフェスとよく似た感じのフレームバッファで、システムのメモリの他、ビデオカード内のメモリにも取れるようです。また、画面に表示するウインドウのクライアント領域もサーフェスになり、メインウインドウは以下のように画面表示用サーフェスの形式を指定してSetVideoMode()すると自動的に作成されるみたいですね。
screen=SDL_SetVideoMode(256,256,32,SDL_SWSURFACE);
このようにして画面の設定を行うと、ウインドウが出てきて以降screenを通してその表示領域に描画を行うことが出来ます。
では、次に表示領域以外にメモリ上にサーフェス(フレームバッファ)を作成し、それを表示用サーフェスscreenに描画してみましょう。サーフェスは、色形式と大きさを指定するだけで自動的にフレームバッファの情報とピクセル列用のメモリ領域が確保され使えるようになるのですが、今回はピクセル列を自分で用意し、そのピクセル列を元にサーフェスを作ってみます。こちらの方が、自分で確保した領域にデータを読み込んでそのデータを直接サーフェス化する、という使い方が可能なので便利なことが多いでしょう。
ピクセル列のバッファからサーフェスを作成するにはSDL_CreateRGBSurfaceFrom()を使います。この関数に、ピクセル列のポインタ、サーフェスの大きさ(今回は256×256)、1ピクセルの色深度(今回は32ビット)、横一ラインのバッファの幅(今回は256*4=1024バイト)、RGB、それにアルファのマスクを指定するとサーフェスのポインタが返ってきます。マスクは、RGBアルファが格納されている位置を示すもので、この部分をいじるとRGBやアルファの配置を変更できるようです。フォーマットの異なる画像データを読み込んでそのままサーフェス化する時に役立ちそうですね。今回は、32ビットのうち下位24ビットに上位からRGBの順に配置して、アルファは無効(マスク値0)にしました。これで、32ビットDIBと同じ感覚で扱うことが出来ます。ピクセル列pixelsは、32ビット型256×256要素の配列として確保し、すべて0xff(青)で埋めるようにしました。
Uint32 pixels[256*256]; for (i=0;i<256*256;i++) /* ピクセル列設定 */ pixels[i]=0xff; bitmap=SDL_CreateRGBSurfaceFrom((void *)pixels,256,256,32,256*4, 0x00ff0000,0x0000ff00,0x000000ff,0);
オフスクリーンのサーフェスが出来たら、後はそれをscreenに描画してscreenを更新すれば、サーフェスbitmapが描かれたscreenが表示されます。
/* screenにbitmapを描画 */ SDL_BlitSurface(bitmap,NULL,screen,NULL); /* screenの全領域を更新 */ SDL_UpdateRect(screen,0,0,0,0);
以上で、独自に確保したサーフェスが描かれたウインドウが出来ました。ウインドウシステムでは、通常ウインドウ作成の後メッセージループに入り、メッセージループから抜けるとプログラムも終了、という形が一般的ですが、SDLにもメッセージを捉えその内容を調べる仕組みが用意されています。ですので、SDLアプリは一般的なウインドウアプリ同様に
という構造で書くことが出来ます。今回は、メッセージループ内のイベント取得にSDL_WaitEvent()を使ってみましょう。これは「イベントが来るまで待つ」関数で、Win32で言えばGetMessage()ですね。他に、PeekMessage()に相当する「現在イベントがあるか調べる」SDL_PeepEvents()もあります。
今回のメッセージループ(プログラムのメインループ)は、以下のようにしてみました。
while (quite==0) { /* メッセージループ */ SDL_WaitEvent(&e); switch (e.type) { case SDL_QUIT: /* 終了要求 */ quite=1; break; } }
SDL_WaitEvent()でメッセージを取得すると、引数で渡した構造体のtypeメンバにイベントの種類が入っているので、そのイベントに応じて処理を振り分けます。今回は、ユーザーがウインドウを閉じようとするなどして終了処理の要求があった時に送られてくるSDL_QUITが来たら、ループを抜けるようにしました。
プログラムを実行すると、青く塗りつぶされたウインドウが出てきます。それだけです。しばらく眺めたら、ウインドウを閉じて終了してください。
それにしても、SDLを使うとフレームバッファを非常に簡単に扱えますね。他にもイベント処理やスレッド・タイマ関連の機能まで一通りあるようなので、手軽にゲームを創るには適しているかもしれません。資料に関しても、日本語の情報こそ少ないものの充実した英語のリファレンスがあるので、機能の概要や関数の使い方を調べながらとにかくいろいろ創ってみるのも手でしょう。特に、リファレンスのビデオやイベント周りの部分は、「こんな機能があれば楽だな」と思いながら見てみるとまさに思っていた通りの機能が用意されていたりして、ざっと眺めながら何が出来そうか考えるだけでも楽しいものです。