ページ 11

openGLUTのコールバック関数について

Posted: 2013年5月20日(月) 16:29
by kyz
いつもお世話になっております。
openGLUTのコールバック関数である glutDisplayFunc(void (*callback))の引数にクラスのメンバ関数を指定したいのですが、どういう方法を取ればいいでしょうか?

コード:

class Room{

public:

	Room(){
init_OpenGL();
        }

	void display(){

        /* 内容省略 */

	}

	void init_OpenGL(){
		glutDisplayFunc(display);//ここでコールバック関数を登録したい
		glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
		glClearColor(1.0, 1.0, 1.0, 1.0);
		glEnable(GL_DEPTH_TEST);
	}

};
これをコンパイルしてみると、

error C3867: 'Room::display': 関数呼び出しには引数リストがありません。メンバーへのポインターを作成するために '&Room::display' を使用してください

このようなエラーが出て来ました。
また&Room::displayと書きなおしてみても、

error C2664: 'glutDisplayFunc' : 1 番目の引数を 'void (__thiscall Room::* )(void)' から 'void (__cdecl *)(void)' に変換できません。(新しい機能 ; ヘルプを参照)

と出て来てコンパイルできませんでした。

環境は、OS:windows 7(64bit) 開発環境:Visual Studio2012 for Desktop(C/C++) を使って開発しています。

Re: openGLUTのコールバック関数について

Posted: 2013年5月20日(月) 16:40
by usao
指定すべきコールバック関数は,普通の(クラスメンバではない)関数なので,
Room::display() では 求められている関数とは型が違うわけで,当然エラーとなります.

staticなメンバ関数であれば渡せるでしょうが,結局,Room型インスタンスを知ることはできないので
何かしらの妥協(別途インスタンスを知る方法を用意して,コールバック内から使う方法を用意する)をする必要があると思います.

仮に,プログラム内にRoom型インスタンスが一つしか存在しないことを保証できるのであれば,そこらへんのことも
わりと自然な形で解決できるように思います.

Re: openGLUTのコールバック関数について

Posted: 2013年5月20日(月) 21:50
by kyz
usao さんが書きました:指定すべきコールバック関数は,普通の(クラスメンバではない)関数なので,
Room::display() では 求められている関数とは型が違うわけで,当然エラーとなります.

staticなメンバ関数であれば渡せるでしょうが,結局,Room型インスタンスを知ることはできないので
何かしらの妥協(別途インスタンスを知る方法を用意して,コールバック内から使う方法を用意する)をする必要があると思います.

仮に,プログラム内にRoom型インスタンスが一つしか存在しないことを保証できるのであれば,そこらへんのことも
わりと自然な形で解決できるように思います.
分かりました。構造的に難しいという訳ですね。
これじゃ不便なので自らC++風にコールバック関数を定義してみたいと思います。
お早いご回答ありがとうございました。

Re: openGLUTのコールバック関数について

Posted: 2013年5月20日(月) 21:52
by h2so5
Roomのポインタをグローバルに持っておくのも方法の一つだと思います。

コード:

namespace DisplayCallback {
namespace {
std::list<Room*> listeners;
}

void callback()
{
    for (std::vector<Room*>::iterator it = listeners.begin(); it != listeners.end(); ++it)
        it->display();
}

void addListener(Room *ptr)
{
    listeners.push_back(ptr);
}
}

// プログラム初期化時に呼ぶ
glutDisplayFunc(DisplayCallback::callback);

// コールバック登録
void Room::init_OpenGL()
{
    DisplayCallback::addListener(this);
}