Avoiding use of Globals with Callback Funcs

Nov 19, 2013 at 11:18am
I have been developing a game recently using GLFW, and have done quite a bit. My current problem is that I have a class for processing battles, which needs to be accessed in the display loop in the "main()" function as well as in the callback functions required by GLFW for things such as keypresses and mouse events. I can't think of any way to avoid using the object as a global pointer so that the data will still be kept by the object, i.e. pointers stay valid, STL objects keep their data, everything else is normal, etc. Is there any way to avoid using the object as a global variable, or will I just have to settle with a necessary evil? The solution also has to be highly efficient, as this could otherwise become a bottleneck in the processing of this game.

As an idea, here is just a quick layout of the problem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <GLFW/glfw3.h>
// other includes

// function prototypes, class declarations, etc.

static enemy::BattleSystem *mainBattleSystem; // I would like to get rid of this

static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
    switch (key) {
        case GLFW_KEY_SPACE: {
            mainBattleSystem->startProcessingJump();
            // ...
            mainBattleSystem->clean();
        } break;

        // other keys, etc.
    }
}

// other funcs

int main(int argc, char *argv[]) {
    // initialize GLFW, objects, etc.

    while (!glfwWindowShouldClose(window)) {
        // process OpenGL setup commands, draw background, etc.
        mainBattleSystem->drawAll();

        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    // clean up

    return 0;
}
Last edited on Nov 19, 2013 at 11:20am
Nov 19, 2013 at 12:17pm
you can place that pointer in another file and create accessors methods to it.

1
2
3
4
5
6
7
8
9
10
global.h

class globals
{
private:
enemy::BattleSystem *mainBattleSystem;
public:
enemy::BattleSystem * getBattleSystem(); //check if valid, etc;
void setBattleSystem(...);
};


it is also good place to implement critical sections if you are using threads
Last edited on Nov 19, 2013 at 12:18pm
Nov 19, 2013 at 12:28pm
Have you looked at glfwSetWindowUserPointer and glfwGetWindowUserPointer?

http://www.glfw.org/docs/latest/group__window.html#ga3d2fc6026e690ab31a13f78bc9fd3651
http://www.glfw.org/docs/latest/group__window.html#ga17807ce0f45ac3f8bb50d6dcc59a4e06

You could store your own data in the window itself, which you are passed in the callback parameter. So you could create your battle processing object in scope, set it as the Window's user data using glfwSetWindowUserPointer (casting it to void*) and retrieve it from the window parameter passed to you in your callback using glfwGetWindowUserPointer.

Just ensure that your battle system object is not destroyed before the window is destroyed.
Nov 19, 2013 at 12:32pm
Thanks, @Lodger, that is exactly what I was looking for! I was already halfway through modifying the source code to get the callbacks to accept a void* as an optional extra argument, but it turns out there already is one!
Nov 19, 2013 at 9:28pm
Welcome! You'll find that a lot of API's use a similar method for passing around user defined data. As long as you have a handle to a window, you have access to your data.
Topic archived. No new replies allowed.