忍者ブログ
[106]  [105]  [104]  [103]  [102]  [101]  [100
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

いよいよoFプロジェクトにWiiYourself!をインクルードしてみる。

自分の備忘録以外の、誰かの何らかの役には立ちそうな事を書いている気もしてきた。


まずは、今後(願わくば)様々なAppクラスのベースとなるようなofBaseAppサブクラスを作ってみようと思う。名前はwiiAppクラスとでもしておこう。
前回使ったプロジェクトフォルダをコピーして、その中にWiiYourself!のソースをコピーしてしまう。
で、プロジェクトのプロパティから、WDKのHIDライブラリにインクルードパスとライブラリパスを通して、更に、インクルードパスの冒頭に
$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;
と追記しておく。
あとコンパイルエラーが出て気づいたんだけど、wiimote_common.hにはインクルードガードが無い。ややこしい事を考えなくて済むように、適当にでっち上げて追記。
wiiApp.cpp
#ifndef _WIIMOTE_COMMON_H_
#define _WIIMOTE_COMMON_H_
/* ソース本文 */
#endif
こんな感じ。
あとはwiiAppクラスの設計を考えるだけ。かな。

WiiRemoteに何か変化があったら特定のメンバ関数が呼び出されるようにしたいのだけれど、そうするとスレッドが必要になるのかな。でもwiimoteクラス内で既にスレッドが走ってるよなあ・・・、と思ったら、標準でコールバック関数が指定出来るみたい。
その名が示す通りに、wiimote::CallbackTriggerFlags フィールドにコールバック条件となるフラグ(wiimote_common.hで定義)を指定すると、 wiimote::ChangedCallback フィールドにセットした関数ポインタが呼ばれるって寸法だ。
じゃあ、このChangedCallbackにwiiAppのメンバ関数を指定してやればいいんじゃね?と思ったんだけど、グローバル関数ポインタとメンバ関数ポインタは、他のシグネチャ(戻り値型、引数型)が一致していても違う型として見なされるようだ。ううむ。

WiiYourself!のコールバック機能を使うなら、wiiAppインスタンス内で呼び出されたグローバル関数から、再びwiiAppインスタンスにどうにかして戻って来なくちゃならない。あと、できれば既存のライブラリには手を加えたくない(インクルードガードは追加しちゃったけどね)。さて、どうするか。
とりあえずwiiAppインスタンスはmain関数から1回だけ生成されるものとして考えよう。つまり暗黙的なシングルトンなので、グローバル領域にwiiAppインスタンスへの参照があれば、コールバック関数からインスタンスに戻って来れるね。(あまり美しくないかな・・・)

どうせだったらコールバック関数もインスタンスへのポインタ変数も、wiiAppクラスに纏めてしまいたいから、staticメンバにしてしまおう。static関数はグローバル関数と見なされるようだ。(ちょっと嵌ったんだけども、staticメンバ変数はclassブロック内で宣言しただけではメモリが確保されないので定義を忘れずに行うこと。)
あと、なんかWiiRemote接続時には、コールバック関数内で色々行うべき儀式があるようなので、そこはWiiYourself!のデモを丸写しし。
で、こんな感じになったー。ちょっと長くなります。

wiiApp.h
#ifndef _WIIAPP_H_
#define _WIIAPP_H_

#include "ofMain.h"
#include "wiimote.h"
#include "wiimote_state.h"
#include "wiimote_common.h"

// 表示しなきゃいけないらしいライセンス文
#define WII_YOURSELF_LICENSE_WSTRING L"contains WiiYourself! wiimote code by gl.tter\nhttp://gl.tter.org\n"

class wiiApp : public ofBaseApp
{
public:
	wiiApp();
	~wiiApp();
	// WiiRemoteに変化があると以下の仮想関数が呼び出される。
	// もっと大雑把にまとめたりあるいは細分化してもよかったんだけど
	// とりあえずこんな感じで。
	virtual void wiiButtons(wiimote_state::buttons &btns){};
	virtual void wiiAccel(wiimote_state::acceleration &accel){};
	virtual void wiiOrientation(wiimote_state::acceleration &accel){};
	virtual void wiiIR(wiimote_state::ir &ir){};
	virtual void wiiExtension(){};
protected:
	// サブクラスからならwiimoteを操作出来る
	wiimote _wiimote;
private:
	static wiiApp *_ptrApp;
	static void _wiimoteCallback (wiimote &remote,
				state_change_flags changed,
				const wiimote_state &new_state);
};

#endif
wiiApp.cpp
#include "wiiApp.h"

// 暗黙のシングルトン
wiiApp *wiiApp::_ptrApp = 0;

// コンストラクタ
wiiApp::wiiApp()
{
	// コールバック関数からインスタンスを参照できるよう
	// クラスのstatic変数にポインタを代入。
	// 暗黙的にインスタンスは1つしかない事になってる。
	_ptrApp = this; 

	// コールバック関数を設定
	_wiimote.ChangedCallback = _wiimoteCallback;
	// コールバック条件を全フラグに設定
	_wiimote.CallbackTriggerFlags = (state_change_flags) (CONNECTED | CHANGED_ALL);

	// 超適当
	int tryConnect = 10;
	// 接続
	while(!_wiimote.Connect(wiimote::FIRST_AVAILABLE) || !tryConnect--)
	{
		Sleep(500);
	}
}

// デストラクタ
wiiApp::~wiiApp()
{
	if(_wiimote.IsConnected()) _wiimote.Disconnect();
}

// WiiYourself!のコールバック関数
void wiiApp::_wiimoteCallback (wiimote &remote,
			state_change_flags  changed,
			const wiimote_state &new_state)
{
	// WiiYourself!のDemo.cpp から
	// WiiRemote本体や拡張コントローラの接続に関連する処理
	// 	
	// the wiimote just connected
	if(changed & CONNECTED)
	{
		if(new_state.ExtensionType != wiimote::BALANCE_BOARD)
		{
			if(new_state.bExtension)
				remote.SetReportType(wiimote::IN_BUTTONS_ACCEL_IR_EXT); // no IR dots
			else
				remote.SetReportType(wiimote::IN_BUTTONS_ACCEL_IR);		//    IR dots
		}
	}
	// a MotionPlus was detected
	if(changed & MOTIONPLUS_DETECTED)
	{
		if(remote.ExtensionType == wiimote_state::NONE) 
		{
			bool res = remote.EnableMotionPlus();
			_ASSERT(res);
		}
	}
	// an extension is connected to the MotionPlus
	else if(changed & MOTIONPLUS_EXTENSION_CONNECTED)
	{
		// We can't read it if the MotionPlus is currently enabled, so disable it:
		if(remote.MotionPlusEnabled())
			remote.DisableMotionPlus();
	}
	// an extension disconnected from the MotionPlus
	else if(changed & MOTIONPLUS_EXTENSION_DISCONNECTED)
	{
		// enable the MotionPlus data again:
		if(remote.MotionPlusConnected())
			remote.EnableMotionPlus();
	}
	// another extension was just connected:
	else if(changed & EXTENSION_CONNECTED)
	{
		// switch to a report mode that includes the extension data (we will loose the IR dot sizes)
		if(!remote.IsBalanceBoard())
			remote.SetReportType(wiimote::IN_BUTTONS_ACCEL_IR_EXT);
	}
	// extension was just disconnected:
	else if(changed & EXTENSION_DISCONNECTED)
	{
		// use a non-extension report mode (this gives us back the IR dot sizes)
		remote.SetReportType(wiimote::IN_BUTTONS_ACCEL_IR);
	}
	
	// wiiAppインスタンスのメンバ仮想関数を呼び出す処理
	if (changed & CHANGED_ALL)
	{
		remote.RefreshState();

		if(changed & BUTTONS_CHANGED)
		{
			_ptrApp->wiiButtons(remote.Button);
		}
		if(changed & ACCEL_CHANGED)
		{
			_ptrApp->wiiAccel(remote.Acceleration);
		}
		if(changed & ORIENTATION_CHANGED)
		{
			_ptrApp->wiiOrientation(remote.Acceleration);
		}
		if(changed & IR_CHANGED)
		{
			_ptrApp->wiiIR(remote.IR);
		}
		if(changed & EXTENSION_CHANGED)
		{
			_ptrApp->wiiExtension();
		}
	}
}
wiiAppで定義した仮想関数をサブクラスでオーバーライドすることで、openFrameworks上でも手軽にWiiRemoteが使えるようになる。多分。

と、いうわけで、何か作ってみよう。
PR
この記事にコメントする
お名前
タイトル
文字色
メールアドレス
URL
コメント
パスワード   Vodafone絵文字 i-mode絵文字 Ezweb絵文字
belize pharmacy
wellington pharmacy http://onlinemedistore.com/products/digoxin.htm mubFaunny 807690 pet pharmacy 18008504419
Tepexaxyonelo URL 2011/11/18(Fri)08:31:55 編集
この記事へのトラックバック
この記事にトラックバックする:
26歳のハローワールド
カレンダー
03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
最新コメント
[11/27 gyzwviyehl]
[11/18 Tepexaxyonelo]
[09/12 gomFolley]
[08/16 CypeBachCoece]
[06/02 gb]
[03/06 kishima]
[01/18 KNDY]
[01/16 kage]
[12/23 KNDY]
[12/23 kage]
最新トラックバック
ブログ内検索
アクセス解析
プロフィール
HN:
knd
HP:
自己紹介:
絶賛迷走中。
UNIQLO CALENDAR
忍者ブログ [PR]