GLFW Callbacks From Inside Class/Struct

Started by
10 comments, last by Lord Fers 4 years, 11 months ago

This question has been asked before multiple times, but as a beginner I have found the various answers rather hard to interpret. 

I want to call my member function SetFrameBufferSize() from the glfwSetFramebufferSizeCallback() function (from inside my other member function SetFramebufferSizeCallBack()). The problem, as has been detailed before, is that the glfwSetFramebufferSizeCallback() function will not take a member function as a parameter. I can solve this problem by abstracting the SetFrameBufferSize() function outside the GLFW class, and I have done this with the SetTheFrameBufferSize() function which works fine. But I would much prefer to have this function inside the class. Is there anyway that this can be done, and if so, would the respondent be so kind as to talk me through the steps required to achieve this. 


void GLFW::SetFrameBufferSize(GLFWwindow* window, int h, int w)
{
	// Resize window
}

void SetTheFrameBufferSize(GLFWwindow* window, int h, int w)
{
	// Resize window
}

void GLFW::SetFrameBufferSizeCallBack()
{
	glfwSetFramebufferSizeCallback(m_Window, SetTheFrameBufferSize); // works fine
	glfwSetFramebufferSizeCallback(m_Window, GLFW::SetFrameBufferSize);
  	/* argument of type "void (GLFW::*)(GLFWwindow* window, int h, int w)" is incompatible
       with parameter of type "GLFWframebuffersizefun" */
}

 

Advertisement

This problem (which isn't unique to GLFW and comes up in other contexts as well) is discussed here:

https://stackoverflow.com/questions/7676971/pointing-to-a-function-that-is-a-class-member-glfw-setkeycallback

There's quite a bit of discussion in that thread, but it links to this GLFW FAQ entry that addresses the question directly:

https://www.glfw.org/faq.html#216---how-do-i-use-c-methods-as-callbacks

That answer pretty much sums it up. For the callback, you'll need to use a compatible function (e.g. free or static). Within that function, you can then call a corresponding member function on an instance of your class. You can store a pointer to the instance of your choice using the GLFW 'user pointer' feature (as the FAQ suggests) or through other means.

Now, you did say in your post that you've already read some material on this, so maybe you've already seen those references or similar references and aren't clear on the details. In that case, maybe you could clarify what you're uncertain about, and someone should be able to help :)

I seem to be having some pretty serious problems with GLFW now. Functions aren't being called when they should be and even when they are being called they are doing the wrong thing. For example glfwSetCursorPosCallback() is only working when the mouse is inside the window and other callback functions just aren't calling the function at all. Have read that this can be due to not calling glfwPollEvents() but this is certainly not the case in my program. Thanks for your help anyway!

try it:

Quote

    auto mousepos_callback = [](GLFWwindow *window, double x, double y) {
        Display* display = static_cast<Display *>(glfwGetWindowUserPointer(window));
        display->mListener.onMouseMove(x, y);
    };
    glfwSetCursorPosCallback(pWindow, mousepos_callback);

But, before you need set this:

glfwMakeContextCurrent(pWindow);

This is what I do in my tests apps.

Computer Graphics programmer.

My GLFW is totally messed up. I will try that if I am able to restore it back to its previous state.

So no-one has mentioned this before, there is also the option to wrap your class member function into a delegate so that this will provide a static function pointer arround your class member function. However, this will assume that you have a static wrapper that is keeping a pointer to the class you want to call and knows (maybe via interface or a map) the function it needs to call.

I don't think this very helpfull at all because the problems you'll have with such a solution, if it is GL or not dosent matter, that you need to do some extra house-keeping you could also do by providing a static function and do whatever you want inside it.

The other way round is simpler to achieve when you expect a member function pointer and instead want to pass a static one

13 hours ago, Lord Fers said:

try it:

But, before you need set this:

glfwMakeContextCurrent(pWindow);

This is what I do in my tests apps.

 

@calioranged: You should really try this first. C++11 lamda functions are really nice if you have to squeeze arbitrary functions through strict interfaces.

 

However, it does not work always. I can remember having issues with some GLUT callbacks where my function was not accepted if it depended on a runtime state.

2 hours ago, Shaarigan said:

So no-one has mentioned this before, there is also the option to wrap your class member function into a delegate so that this will provide a static function pointer arround your class member function. However, this will assume that you have a static wrapper that is keeping a pointer to the class you want to call and knows (maybe via interface or a map) the function it needs to call.

Or, having a wrapper wrap the window's static callbacks and have objects register their handling wishes with the wrapper. Thus they can communicate for example that they wish to be the only ones to receive and handle a certain callback, or establish a sequence and pass some info along to other objects that come after them.

40 minutes ago, DerTroll said:

  You should really try this first. C++11 lamda functions are really nice if you have to squeeze arbitrary functions through strict interfaces.

What is the 'Display' class you are using?

23 minutes ago, calioranged said:

What is the 'Display' class you are using?

Don't know, since it is not my code, just quoted it.

 

But it is also not really relevant. The point here is, that you create a lambda function which fulfills the interface requirements. In this function, you call your member function. In your case it could look like this (might contain coding errors ;p):


void GLFW::SetFrameBufferSize(GLFWwindow* window, int h, int w)
{
	// Resize window
}


void GLFW::SetFrameBufferSizeCallBack()
{
  	auto myCallbackFunction = [this](GLFWwindow* window, int h, int w)
    {
     	this-> SetTheFrameBufferSize(window, h, w); 
    };
  
	glfwSetFramebufferSizeCallback(m_Window, myCallbackFunction); // works fine
	glfwSetFramebufferSizeCallback(m_Window, GLFW::SetFrameBufferSize);
  	/* argument of type "void (GLFW::*)(GLFWwindow* window, int h, int w)" is incompatible
       with parameter of type "GLFWframebuffersizefun" */
}

Not sure if the this pointer is captured correctly here. I remember that whenever I captured it, I did something wrong and needed to fix that ;).

As I said in my previous post, it might also happen, that the approach does not work, since your Lambda function has a state (pointer to your GLFW class). Especially GLUT didn't like that. Can't remember if GLFW was more tolerant in this case. If not, you need an external function which gets you the pointer to the corresponding instance of your class. Since my Window class is a singleton I can just call the instance function to get the pointer.

 

Greetings

This topic is closed to new replies.

Advertisement