8

I have an an OSX OpenGL app I'm trying to modify. When I create the app a whole bunch of initialisation functions are called -- including methods where I can specify my own mouse and keyboard handlers etc. For example:

glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(700, 700);
glutCreateWindow("Map Abstraction");
glutReshapeFunc(resizeWindow);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
glutMouseFunc(mousePressedButton);
glutMotionFunc(mouseMovedButton);
glutKeyboardFunc(keyPressed);

At some point I pass control to glutMainLoop and my application runs. In the process of running I create a whole bunch of objects. I'd like to clean these up. Is there any way I can tell GLUT to call a cleanup method before it quits?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Daniel
  • 23,365
  • 10
  • 36
  • 34

5 Answers5

10

In freeglut if you call this:

glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION)

Prior to entering the main loop, then when the window closes the main loop function will return and you can do your cleanup.

It's worth noting that at that stage the GL context has already been destroyed so you can't perform any GL operations.

Gordon Wrigley
  • 11,015
  • 10
  • 48
  • 62
  • 2
    It is in fact worth noting that the context is destroyed! That's what led me here, 18 months after you wrote that. Another good option is the glutCloseFunc() callback, which runs right after you close the window of your program. The context still exists in that function, so you can properly destroy things there too. – Philip Apr 03 '13 at 22:55
4

I fell for this once in a while, trying to play with GLUT. I tried everything I could thing of, including IIRC exiting glutMainLoop through an exception catched in the main function but...

When using glutMainLoop

My solution was the following : Create a global Context object, who will be owner of all your resources, and free those resources in the destructor.

This global Context object destructor will be called immediately after exiting the main.

It is important Context is a global variable, and not a variable declared in the main function, because for a reason that still escapes me (I still fail to see the interest of this implementation choice), glutMainLoop won't return.

In my Linux box (Ubuntu), the destructor is called correctly. I guess it should work the same way on Windows and MacOS, too.

Note that this is the C++ version of Francisco Soto's atexit() solution, without the possible limitations.

Using glutMainLoopEvent

Apparently, some implementations have a glutMainLoopEvent which can be used instead of calling glutMainLoop.

http://openglut.sourceforge.net/group__mainloop.html#ga1

glutMainLoopEvent will only resolve the pending events, and then return. Thus, you must provide the event loop (the for(;;) construct) around the call to glutMainLoopEvent, but this way, you can work with a GLUT and still have control on the event loop, and free your resources when needed.

paercebal
  • 81,378
  • 38
  • 130
  • 159
3

If you are using C/C++ maybe you can use an atexit() call?

Francisco Soto
  • 10,277
  • 2
  • 37
  • 46
  • Yes, I should have mentioned I'm using C++. I'm looking at a solution based on atexit but it's not so nice as specifying a cleanup callback. Anyway, it's a good suggestions. Thanks! – Daniel Apr 22 '10 at 04:39
0

I ended up using paercebal's answer above, along with his previous attempt at using a try/catch block around glutMainLoop() as well. Why? Because I wanted to cleanup properly no matter how it was shutdown. The global Context object will get destroyed properly if the app exits cleanly, which is what happens if you close out the app by closing the window (or quitting the app on OS X). But if you hit ctrl-C in the terminal where it was launched (or send it a SIGINT), the cleanup does not happen. To handle this, I added the following to my code:

static bool exitFlag = false;

static void sighandler(int sig) {
  exitFlag = true;
}

static void idleFunc() {
  if(exitFlag) {
    throw NULL;
  }
}

And then in main():

signal(SIGINT, sighandler);
glutIdleFunc(idleFunc);

try {
  glutMainLoop();
} catch(...) {}

This isn't the prettiest bit of code, but it does handle both cases of exiting the program correctly.

One catch (no pun intended) -- any code you place after the catch() block will not be called if you close the window/quit the app normally. You have to place your cleanup code in the global Context object as shown in paercebal's answer. All this code is doing is allow the SIGINT signal to be used to get out of the glutMainLoop().

I think the real lesson here is that for anything really complex, GLUT is just not going to cut it.

Dennis Munsie
  • 1,211
  • 12
  • 24
0

Typically you don't need to do this; just exiting the application will tear down any resources you've allocated. Even if you've captured the screen, it should go back to normal.

Nicholas Riley
  • 43,532
  • 6
  • 101
  • 124
  • I don't understand; how would the GLUT know what I've malloc'd? – Daniel Apr 22 '10 at 04:32
  • 1
    It is not GLUT who does that, its the operating system. Your application closes and the OS cleans up after yourself. – Francisco Soto Apr 22 '10 at 04:46
  • 5
    -1. This is REALLY bad practice. It encourages sloppy programming practices such as not properly tracking your memory. If you have written your application correctly you should be able to unwind memory allocations easily without relying on the OS to clear up after you. – Goz Apr 22 '10 at 07:09
  • 3
    +1 to balance. It doesn't matter if its bad practice. Its HOW GLUT WORKS. The glutModalLoop function does not return, so NSApplication::Run does not return. In conditions where the framework is already promising to not do any cleanup, trying to force application objects to cleanup is a wasted effort. – Chris Becke Apr 22 '10 at 09:45
  • @Goz - aiee. If this kind of cleanup were actually necessary, it would be a bug in the OS. In fact, in OS X 10.6, Apple now explicitly encourages applications to let themselves be killed rather than gracefully shut down when possible, in order to speed up logging out: it's called sudden termination (http://developer.apple.com/mac/library/documentation/cocoa/reference/foundation/Classes/NSProcessInfo_Class/Reference/Reference.html#//apple_ref/doc/uid/20000316-SW3). – Nicholas Riley Apr 23 '10 at 03:30
  • @Nicholas: Alas it is this kind of approach that leads to a game like Battlefield needing to CreateProcess a new process and terminating the old at each level change. This is bad practice. I admit from looking into it that this is what GLUT encourages you to do but this is bad going. Especially with all the OpenGL driver bugs about I have doubts that the GL clean up will proceed completely ... – Goz Apr 23 '10 at 07:10
  • The questioner is asking what to do when *exiting*; if you're leaking within your app, that's your problem. Resource leaks in OpenGL drivers are bugs in the drivers; sure, you may need to work around them, but there's no need to always write as if they exist. – Nicholas Riley Apr 23 '10 at 15:30
  • Hey, if you're downvoting this answer, please explain yourself. I think I've defended my answer pretty well in the comments, but I'd love to hear why people disagree. (Seriously.) – Nicholas Riley Jan 15 '13 at 01:01
  • 1
    @NicholasRiley - I haven't upvoted or downvoted your answer. No downvote - all modern operating systems I know of(can't say for every) are doing resource cleanup for you - if you're running in *user space*. And there's nothing wrong in letting os do this for you especially if os vendor encourages you in doing so(your Apple example). Problem arise when that code supposed to work on such system in *user space* is, say, ported so some other system, or made to run in kernel space, or just re-used by some other coder who expects object to release its resources on termination. Or something else.. – kerim Feb 25 '13 at 06:45