Home | Lesson | Game | Tool | Link

C01.SDL組み込み

SDLを組みこんだIrrLichtの開発を紹介します。
SDLを組み込むことで、細かいキー操作も可能になります。
(Irrlichtのキー操作で取得できないキーも取得可能になります。)
ジョイスパッド(ジョイスティック)をより簡単に操作可能になります。
(LinuxやMacの環境でもジョイパッドが使用可能になります。)

SDLはPS3Linuxでも使用可能です。

SDL(Simple DirectMedia Layer) 1.2.13はこちらからダウンロードして下さい。
SDLHELP日本語版はこちらからダウンロードして下さい。


SDLを使用する準備
ライブラリをリンクします。必要なライブラリはSDL.libと、SDLmain.libです。
インクルードファイルを記述します。 SDL用デバイスを作成する際に、システム情報を取得するのでSDL_syswm.hもインクルードしておきます。
SDLのプログラムは、スレッドを使用する場合があるので、マルチスレッドDLLで作成することをお奨めします。VisualC++では、コード生成でランタイムライブラリを「マルチスレッドDLL」に変更して下さい。
また、必要であれば無視するライブラリに「msvcrt.lib」を設定してください。


ここでは、Windowsでの記述方法を紹介します。
#ifdef WIN32
	#include <windows.h>
	#pragma comment(lib, "Irrlicht.lib")

	//SDL用設定
	#pragma comment(lib, "SDL.lib")
	#pragma comment(lib, "SDLmain.lib")
	//C/C++→コード生成→ランタイムライブラリ→マルチスレッドDLLに変更
	//必要であれば、無視するライブラリに「msvcrt.lib」を設定
#endif

#include <SDL/SDL.h> 
#include <SDL/SDL_syswm.h>//SysWMinfo使用

SDLデバイス作成関数
SDL用のデバイスを作成します。
SDL用の設定で初期化を行い、createDeviceExを呼び出します。
関数の引数はcreateDeviceと同じようになっています。
createDeviceExを使用する際のパラメータでwindowIDが必要になります。
WindowsでいうHWNDですが、これにはSDLのシステム情報で取得するwindowを渡します。

2008/05/11 現在の設定だと、画面サイズがタイトルバーなども含めたサイズになってしまい、 座標を指定した描画だと位置がずれてしまいます。 そこで、SDL_SetVideoMode()とparam.WindowIdを削除することで、 表示サイズや位置の問題は解決可能です(太字の箇所が該当箇所です)。
//SDL用デバイス作成
IrrlichtDevice* createDeviceSDL
(
	video::E_DRIVER_TYPE deviceType,
	const core::dimension2d<s32> & windowSize,
	u32 bits,
	bool fullscreen,
	bool stencilbuffer,
	bool vsync,
	IEventReceiver* receiver,
	const c8* sdk_version_do_not_use)
{
	//SDLフラグ(環境によって書き換えてください)
	u32 flags = SDL_HWSURFACE|SDL_DOUBLEBUF;
	if(fullscreen)
		flags |= SDL_FULLSCREEN;

	//SDLの初期化(SDL関連を全て初期化します)
	if(SDL_Init(SDL_INIT_EVERYTHING) < 0)
		return 0;

	//プログラム終了時の呼び出し関数指定
	atexit(SDL_Quit);

	//SDLビデオ表示の初期化
	//if(SDL_SetVideoMode(windowSize.Width, windowSize.Height, bits, flags) == 0)
		//return 0;

	//キーリピート有効(50ms)
	SDL_EnableKeyRepeat(50,50);

	//キーのUnicode変換有効
	SDL_EnableUNICODE(1);

	//SDLシステム情報取得(WindoID用)
	SDL_SysWMinfo wmInfo;		//システム情報取得用構造体
	SDL_VERSION(&wmInfo.version);	//システムver取得
	SDL_GetWMInfo(&wmInfo);		//verからウインドウ情報取得

	//パラメータ作成
	SIrrlichtCreationParameters param;
	param.AntiAlias     = false;
	param.Bits          = bits;
	param.DriverType    = deviceType;
	param.Fullscreen    = fullscreen;
	param.Stencilbuffer = stencilbuffer;
	param.Vsync         = vsync;
	param.WindowSize    = windowSize;
	param.WindowId      = NULL;//wmInfo.window;//SDLのウインドウハンドル指定

	IrrlichtDevice *device = createDeviceEx(param);

	//レシーバ設定
	device->setEventReceiver(receiver);

	return device;
}

main関数
今まではcreateDeviceで作成していた所をcreateDeviceSDLに置き換えます。
他は変更なしで、SDLでの描画が可能になります。
※処理がSDLに移っているので、Alt+F4での終了ができないので注意して下さい。

「SDL_mainが見つからない」という時のために、main関数をSDL_mainに置き換えておきましょう。

//#ifdef WIN32
//	int WINAPI WinMain(
//		HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR strCmdLine, int nShowCmd)
//#else
//	int main()
//#endif
int SDL_main(int argc, char* argv[])
{
	IrrlichtDevice *device = createDeviceSDL(
		EDT_OPENGL,dimension2d<s32>(320,240),16,false,false,false,0,0);

	device->setWindowCaption(L"Irrlicht");//ウインドウタイトル設定

	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr  = device->getSceneManager();

	while(device->run())
	{
		driver->beginScene(true, true, 0xFF6060FF);

		//シーンの描画
		smgr->drawAll();

		driver->endScene();
	}

	device->drop();

	return 0;
}

キーイベント処理の追加
ESCで終了できるように、キーイベント処理を追加します。
イベント処理には以下の2つがありますが、スレッドを使用しない場合は
SDL_PollEventを使用したほうがよいでしょう。
・SDL_WaitEvent:何かイベントがあるまで待機します。
・SDL_PollEvent:イベントがなければ処理しません。
※スレッドを使用していない場合、何かイベントがあるまで待機してしまうと、
 キーやマウスでのイベントが起きない限り処理がそこで停止してしまいます。
 (描画処理や音声処理などもそこで停止してしまいます。)
//キーイベント処理
int keyFunc(IrrlichtDevice *device) 
{ 
	SDL_Event event;
	//if(SDL_WaitEvent(&event))//処理待ち
	while(SDL_PollEvent(&event))///処理チェック
	{
		switch(event.type)
		{
			case SDL_QUIT:
				device->closeDevice();
				break;
			//キーボード
			case SDL_KEYDOWN:
			{
				switch(event.key.keysym.sym)
				{
					case SDLK_ESCAPE:
						device->closeDevice();
						break;
				}
				break;
			}
			break;
		}
	}

	return 0;
}

メインループの処理
メインループの中にキー処理を追加します。
ウインドウを閉じたりESCを押した際に、デバイスを閉じるようにしたので、
メインループを抜けるようになっています。
	while(device->run())
	{
		driver->beginScene(true, true, 0xFF6060FF);

		//キー処理
		keyFunc(device);

		//シーンの描画
		smgr->drawAll();

		driver->endScene();
	}


メモ
現在の設定では、タイトルバーやウインドウ枠の分だけ画面が小さくなっています。
FULLSCREEN設定にすると問題ないですが、ウインドウで起動する場合は注意して下さい。

ダウンロード
今回作成したファイル一式です。

宿題
AltとF4キーを押したら終了できるようにしてみましょう。