Sign in to follow this  
Togakangaroo

question about passing functions in glut

Recommended Posts

Ok, I hope I'm not being an asshole by skipping over the FAQ and just posting my question, but I figure its pretty specific and just merits a quick answer. I am also pretty new to graphis programming so bear with me etc. etc. Now then. I am making a terrain map generator/display. In order to avoid having to declare a bunch of global variables and just keep overall neatness at a maximum I tried putting as much as I can in an general GLInterface class (that I wrote). So very basically my program looks like this. class myclass { ///stuff }; class GLInterface { myclass c1; //otherstuff void RenderScene() { //stuff } void setupinterface() { //change window size and other stuff glutDisplayFunc(GLInterface::RenderScene); } startLoop(){ glutMainLoop(); } }; int main() { GLInterface GLI; GLI.setupinterface(); GLI.startLoop(); } However the line glutDisplayFunc(RenderScene); will not complile. It will not compile if I do not scope it with GLInterface:: and it will not compile if I put it in the main glutDispalyFunc(GLI.RenderScene); Please tell me that there is some way short of making RenderScene a global function to get this to work! Thanks a lot. George

Share this post


Link to post
Share on other sites
The glut callbacks are suppose to be plain non-method, functions. Methods(class-functions) and plain functions do not have the same signature so therefore you can't pass a class method as a function pointer. Try it out without glut. You'll get the same errors.

Share this post


Link to post
Share on other sites
Quote:
Original post by Khaosifix
The glut callbacks are suppose to be plain non-method, functions. Methods(class-functions) and plain functions do not have the same signature so therefore you can't pass a class method as a function pointer. Try it out without glut. You'll get the same errors.

True and not true[smile].
It would work perfectly if the member functions are static. Since they aren't one can use std::mem_fn together with std::bind1st to achieve this (or boost.bind).

Regards,
Pat.

[edit]
Oh, you already noticed - just ignore the first part [smile]
[/edit]

Share this post


Link to post
Share on other sites
Since IMHO the STL is a bit clumsy on the bind1st and mem_fn part, I decided to just post an example:


class GLInterface {
myclass c1;
//otherstuff
void RenderScene() {
//stuff
}
void setupinterface() {
//change window size and other stuff
glutDisplayFunc(std::bind1st(std::mem_fun(&GLInterface::RenderScene), this));
}

void startLoop() {
glutMainLoop();
}
};



Hope this helps,
Pat.

Share this post


Link to post
Share on other sites
thanks a lot, I'll try it right now and see what happens.
I'm afraid I don't know what it would mean to have a static method (I mean I know I could put the word static there but I don't know waht it would do) could someone explain that to me so I could see if that method would be applicable?

Share this post


Link to post
Share on other sites
Hope this helps :


class CClass
{

public :

static GLvoid RenderScene( ) ; // declare it as static in the class

} ;

GLvoid CClass::RenderScene( )
{ // Important step : define the function outside of the class. Can't be inside.
// Draw stuff.
}

void main( )
{
// Function calls are a little odd. But this is how you call a static method.
CClass::RenderScene( ) ;
}



Share this post


Link to post
Share on other sites
Quote:
Original post by Togakangaroo
thanks a lot, I'll try it right now and see what happens.
I'm afraid I don't know what it would mean to have a static method (I mean I know I could put the word static there but I don't know waht it would do) could someone explain that to me so I could see if that method would be applicable?

You could use the PIMPL idiom to achieve that:


class ActualImplementation {
private:
// declare data
public:
// methods
void doSomething();
};

class PublicInterface {
private:
static ActualImplementation *pimpl;
public:
PublicInterface() {
if (0 == pimpl) {
pimpl = new ActualImplementation;
}
}
~PublicInterface() {
delete pimpl;
pimpl = 0;
}

static void doSomething() {
// dispatch to actual implementation
assert (pimpl);
pimpl->doSomething();
}
};




You can use PublicInterface::doSomething like a free function now and pass it as a callback to GLUT for example.

Regards,
Pat.

Share this post


Link to post
Share on other sites
Another idea to bypass the static-problem:


class GLInterface {

myclass c1;
static GLInterface * instance;
//otherstuff
void RenderScene() {
//stuff
}
static void InternalRender() {
assert(instance);
instance->RenderScene();
}

public:

GLInterface() {
instance = this;
}

void setupinterface() {
//change window size and other stuff
glutDisplayFunc(InternalRender);
}

void startLoop() {
glutMainLoop();
}
};




A little less confusing, I hope [smile]

Share this post


Link to post
Share on other sites
damn, that's clever darookie,I tried using the second one. Still something's up though. It compiles but then complains while linking
TerrainGen error LNK2020: unresolved token (0A000027) ?instance@GLInterface@@1PAV1@A

any ideas?

Share this post


Link to post
Share on other sites
Quote:
Original post by Togakangaroo
darookie, what you recomended std::bind1st(std::mem_fun(&GLInterface::RenderScene), this)
didn't work problem with second argument type as best as I can decipher from the compiler error

Mea culpa! This is not possible because of the different calling conventions...
All GLUT callback types are declared as 'extern "C"' meaning __cdecl has to be used, which is not possible for __thiscall types (all non-static member functions are silently declared this way). I don#t know of any way to trick mem_fun into using a __cdecl member function, though.

Maybe the other two solutions are for you?

Good luck,
Pat.

Share this post


Link to post
Share on other sites
Quote:
Original post by Togakangaroo
damn, that's clever darookie,I tried using the second one. Still something's up though. It compiles but then complains while linking
TerrainGen error LNK2020: unresolved token (0A000027) ?instance@GLInterface@@1PAV1@A

any ideas?

Yeah.

// add this line somewhere
GLInterface * GLInterface::instance = 0;


You need to define static member variables somewhere. They are rarely used so I understand you didn't know that.

Regards,
Pat.

Share this post


Link to post
Share on other sites
Quote:
Original post by Khaosifix
Why use GLUT in the first place?

Now that's not very helpful comment[wink]
The same issue occurs with every C library that takes callbacks as parameter. So this isn't a problem specific to GLUT.
<irony>
Blame C++ for that whole name-mangling insanity and messed up interop system.
</irony>

In the end this we all learned a valuable lesson again: C++ is hard and has its caveats [smile].

Best regards,
Pat.

Share this post


Link to post
Share on other sites
Is that right? GLInterface * GLInterface::instance = NULL;

did you mean GLInterface::instance I = NULL;

either way, I tried both, maybe I'm not putting them in the right place.

Oh well, I suppose I could make all the functions global. Its just a pain in the ass. Thanks anyways guys.

Share this post


Link to post
Share on other sites

class GLInterface {

myclass c1;
static GLInterface * instance;
//otherstuff
void RenderScene() {
//stuff
}
static void InternalRender() {
assert(instance);
instance->RenderScene();
}

public:

GLInterface() {
instance = this;
}

void setupinterface() {
//change window size and other stuff
glutDisplayFunc(InternalRender);
}

void startLoop() {
glutMainLoop();
}
};
static GLInterface * GLInterface::instance = NULL;



Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this