Pointing to a function that is a class member - glfw setKeycallback

viraj picture viraj · Oct 6, 2011 · Viewed 22.9k times · Source

I'm writing a glfw app, in which I've wrapped the function callse into a simple class. Im 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

Answer

N0vember picture N0vember · Feb 22, 2015

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.