Avoiding global variables when using GLUT

GLUT is a great API and it is very easy to use, but I have some difficulties with how it handles the scope. When defining callbacks, it is not possible to pass parameters, so it seems to me that the programmer is forced to rely on global variables that are difficult for me to accept. Right now I have all the GLUT code in its own module, running its own thread on it and defining a static pointer that I assign at the module entry point, for example:

The main module

int main( int argc, char** argv ) { int foo; boost::thread graphicsThread(glutMain, argc, argv, &foo); //... graphicsThread.join(); return 0; } 

GLUT module

 static int* FOO_REF; int glutMain( int argc, char** argv, int* foo ) { FOO_REF = foo; glutInit(&argc, argv); //etc... 

Is there a better solution than this?

+4
source share
2 answers

If you use freeglut or a derivative and want to limit yourself to freeglut derivatives, it has a custom extension to solve this very problem. You can associate void* with each window. If you create a structure containing all the data needed for each window, you can completely exclude global variables.

Description:

 #include <GL/glut.h> #include <GL/freeglut_ext.h> void * glutGetWindowData(); glutSetWindowData(void *data); 
+1
source

What I did was declared global.h for all of my global variables. And initialize them basically. For my "main / general" variables (eg camera, position, iteration numbers, ...) they were all declared separately. Mostly:

 include "global.h" Vector position_g = ... Vector angles_g = ... int time_g = 0; int main () { ... } 

But for variables that were "section specific", i.e. in only one game mode / level, I did the union and listing.

 enum mainGame{skipLevel, ...}; enum mainMenu {viewingSettings, ...}; typedef union generic_union { int i; char c; bool b; char s[100]; // or char * s; float f; } generic; 

And the globalData variable is declared.

 extern generic * globalData; // in global.h generic * globalData = NULL; // in main 

What can be used now:

 int main () { ... globalData = malloc (sizeof (generic)*numGlobals); globalData[skipLevel].b = false; ... } 

Now that in your keystroke function, you can assign a key to switch globalData [skipLevel]. And in any other file, all you have to do is enable global.h.

 include "global.h" void onKeyPress (... ) { If (inMainGame) { If (key == SPACE) { globalData [skipLevel] = true; } } 

And finally, use:

 include "global.h" void levelManager () { ... if (globalData[skipLevel]) level++; ... } 

Pros You only need to bind variable 1 and turn it on.

You can free variables that you no longer want or use in this case. (very useful for reducing "pollution"). If only one variable is required for one game mode, then all you need to save, if you need 48, is just as easy!

It can easily handle any type of variable by adding it to the union.

Fully portable

vs It is necessary to remember the type of variable in order to dereference a common union (not so difficult)

And tracking the use of enums (you can use a style for enums like mainMenu_e to solve this problem)

It adds complexity, but as the number of variables increases, such a system, because it's worth it.

Personally, I think this is very neat, despite a few extra moving parts. If this is unclear, let me know and I will try to fix it :)

0
source

Source: https://habr.com/ru/post/1393593/


All Articles