I'm writing a GLFW app, in which I've wrapped the function calls into a simple class. I'm having trouble setting the key callback. My class is defined as:
class GAME
{
private:
bool running;
public:
GAME();
int execute();
void events(int, int);
int loop();
int render();
};
The execute function is:
int GAME::execute()
{
glfwOpenWindow(640, 320, 8, 8, 8, 8, 0, 0, GLFW_WINDOW);
glfwSetWindowTitle("Viraj");
glfwSetKeyCallback(events);
running = true;
while(glfwGetWindowParam(GLFW_OPENED))
{
glfwPollEvents();
loop();
render();
}
return 0;
}
Compiling the following code on Visual Studio 2010 gives the error:
error C3867: 'GAME::events': function call missing argument list; use '&GAME::events' to create a pointer to member
Using &GAME::events
gives:
error C2664: 'glfwSetKeyCallback' : cannot convert parameter 1 from 'void (__thiscall GAME::* )(int,int)' to 'GLFWkeyfun' 1> There is no context in which this conversion is possible
The code examples provided in the other answers don't describe how to redirect your callback to a per-object member function, with possibly any number of objects. Making your class a singleton will constrain your design and will not scale to multiple glfw windows.
The scalable solution is to set the glfw window user pointer to your object and then fetch it in the callback, and call the member function :
class MyGlWindow
{
public:
void mouseButtonPressed();
};
void makeWindow()
{
GLFWwindow* glfwWindow;
MyGlWindow* myWindow;
/* ... Initialize everything here ... */
glfwSetWindowUserPointer(glfwWindow, myWindow);
auto func = [](GLFWwindow* w, int, int, int)
{
static_cast<MyGlWindow*>(glfwGetWindowUserPointer(w))->mouseButtonPressed( /* ... */ );
}
glfwSetMouseButtonCallback(glfwWindow, func);
}
This solution is shorter and will work for any number of windows.
I also ran into this problem with another glfw callback function, but I didn't want to declare my class method as static
, because I needed to access the member variables within. So I tried std::function
and std::bind
for giving me the ability to bind an instance method as the callback function, but unfortunately it's not an option when working with C callbacks.
The answer to this problem is also stated in the GLFW FAQ "How do I use C++ methods as callbacks":
You cannot use regular methods as callbacks, as GLFW is a C library and doesn’t know about objects and this pointers. If you wish to receive callbacks to a C++ object, use static methods or regular functions as callbacks, store the pointer to the object you wish to call in some location reachable from the callbacks and use it to call methods on your object.
However, this encouraged me to apply the Singleton pattern for my callback class and integrate it as following:
This is what it looks like:
// Input.h (the actual callback class for glfwSetMouseButtonCallback)
class Input
{
public:
static Input& getInstance() // Singleton is accessed via getInstance()
{
static Input instance; // lazy singleton, instantiated on first use
return instance;
}
static void mouseButtonCallback(int key, int action) // this method is specified as glfw callback
{
//here we access the instance via the singleton pattern and forward the callback to the instance method
getInstance().mouseButtonCallbackImpl(key, action);
}
void mouseButtonCallbackImpl(int key, int action) //this is the actual implementation of the callback method
{
//the callback is handled in this instance method
//... [CODE here]
}
private:
Input(void) // private constructor necessary to allow only 1 instance
{
}
Input(Input const&); // prevent copies
void operator=(Input const&); // prevent assignments
};
and in my main.cpp:
Input &hexmap = Input::getInstance(); // initialize the singleton
//The glfw callback is set up as follows:
glfwSetMouseButtonCallback( &Input::mouseButtonCallback); // specifying the static callback method, which internally forwards it to the instance method
There is a C++ syntax for pointing to class member methods but you cannot pass them to a C style API. C understands function calls and every non-static object method, taking your events
as an example, looks like this thinking in C terms: void events(void* this, int, int);
meaning that every method apart from the standard arguments also gets a this
pointer silently passed.
To make your events
C compatible make it static void events(int, int);
. This way it will follow the C calling semantics - it will not require a this
pointer getting passed. You have to also somehow pass your object to this callback in some other manner (if you need this object's data in the callback).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With