0
\$\begingroup\$

I see a lot of talk about glfwGetWindowUserPointer() and glfwSetWindowUserPointer() but I can't for the life of me understand what these functions actually do.

From http://discourse.glfw.org/t/what-is-a-possible-use-of-glfwgetwindowuserpointer/1294:

"If you are trying to use glfw in a program that follows object-oriented design, for example, you can use this pointer to store the address of the instance that is handling a particular window, and forward the callbacks (which have to be static functions, because of the way the API works) to the appropriate member functions."

The author of that comment then posts the following example:

/* Constructor for the MyWindowHandler class */

MyWindowHandler (GLFWwindow * window) 
{
....
    glfwSetWindowUserPointer(window, reinterpret_cast<void *>(this));
}


/* Key event callback wrapper function */

static void key_callback (GLFWwindow * window, int key, int scancode, int 
                                                        action, int mods) 
{
    MyWindowHandler * handler = 
    reinterpret_cast<MyWindowHandler *>(glfwGetWindowUserPointer(window));

    if (handler)
        handler->keyEvent(key, scancode, action, mods);
}

What confuses me is that (at least as far as I can tell) I was able to achieve the exact same outcome in my program without using glfwSetWindowUserPointer() or glfwGetWindowUserPointer() at all.

/* Class constructor (just provided for reference) */

GLFW::GLFW(int right, int top)
    : m_Window(0)
{
    if (!glfwInit())
    {
        std::cout << "GLFW initialisation failed!\n";
        __debugbreak();
    }

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    m_Window = glfwCreateWindow(right, top, "OpenGL Window", NULL, NULL);

    if (!m_Window)
    {
        glfwTerminate();
        std::cout << "Could not create window!\n";
        __debugbreak();
    }

    glfwMakeContextCurrent(m_Window);
    glfwSwapInterval(2);

    if (glewInit() != GLEW_OK)
    {
        std::cout << "GLEW initialisation failed!\n";
        __debugbreak();
    }

    std::cout << glGetString(GL_VERSION) << std::endl;
}

/* My callback member function */

void GLFW::MouseMovement(int x, int y)
{
    std::cout << "Mouse moved\n";
    // do other stuff...
}

/* Main.cpp */

static void MouseMovementCallback(GLFWwindow* window, double x, double y)
{
    GLFW* glfw = nullptr;
    glfw->MouseMovement(x , y);
}

int main()
{
    GLFW glfw(1200, 600);
    glfwSetCursorPosCallback(glfw.GetWindowID(), MouseMovementCallback);

    // ......
    // ......
}

In the above code my 'MouseMovement' callback function was called... so I'm rather stumped as to what the purpose of the glfwGetWindowUserPointer() and glfwSetWindowUserPointer() functions actually is.

I'm sure there is something rather obvious that I am missing here, hopefully someone can enlighten me.

Thanks in advance.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$
static void MouseMovementCallback(GLFWwindow* window, double x, double y)
{
    GLFW* glfw = nullptr;
    glfw->MouseMovement(x , y);
}

This is undefined behavior. And it only happens to work because MouseMovement doesn't access any of it's fields.

Skipping using the userpointer only works when there is just 1 GLFW sitting in a global somewhere. (Which is fine in most games.)

However if you ever want to open a second window you need a way to differentiate them and get access to the object that manages it. The easiest way is setting the userpointer. Or you need to have fully separate callbacks for each window.

Most callback APIs have a way to pass a user-defined pointer through to the callback. One of the main reasons is because globals are discouraged and the only way to get back to your data without the userpointer is to use a global.

\$\endgroup\$
6
  • \$\begingroup\$ Could you possibly elaborate on what is meant by " just 1 GLFW sitting in a global somewhere"? What is a 'global' in this case...? I'm familar with global variables but I am not using any here? Maybe you are referring to the 'MouseMovementCallback' function? Also can I infer that if there is only one GLFW window, I don't need to bother with glfwSetWindowUserPointer() / glfwGetWindowUserPointer() ? \$\endgroup\$ Commented May 21, 2019 at 11:41
  • \$\begingroup\$ @RyanWalter your code will break as soon as the callback needs to access the fields of GLFW. If you make GLFW* glfw a global that you use inside MouseMovementCallback to forward to your class, then it will work. \$\endgroup\$ Commented May 21, 2019 at 11:47
  • \$\begingroup\$ Sorry for all the questions, but what do you mean by 'fields'? \$\endgroup\$ Commented May 21, 2019 at 11:49
  • \$\begingroup\$ @RyanWalter like m_Window \$\endgroup\$ Commented May 21, 2019 at 11:50
  • \$\begingroup\$ Fields=member variables. \$\endgroup\$
    – user35344
    Commented May 21, 2019 at 11:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .