Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I use SDL2 iOS Application Events?

Tags:

c

ios

sdl-2

I am currently using the SDL2 Library and C to write an iPhone application, and things have been going well for the most part. Unfortunately, the documentation seems to be fairly thin in some areas, especially iOS-specific functions. I'm new to using SDL2, and this makes things very difficult. Thus far, everything has worked, but I am stumped on one problem. SDL2 defines six event-types to be used specifically for mobile applications. The README-ios.txt file describes them and using them as such:

int HandleAppEvents(void *userdata, SDL_Event *event)
{
    switch (event->type)
    {
    case SDL_APP_TERMINATING:
        /* Terminate the app.
           Shut everything down before returning from this function.
        */
        return 0;
    case SDL_APP_LOWMEMORY:
        /* You will get this when your app is paused and iOS wants more memory.
           Release as much memory as possible.
        */
        return 0;
    case SDL_APP_WILLENTERBACKGROUND:
        /* Prepare your app to go into the background.  Stop loops, etc.
           This gets called when the user hits the home button, or gets a call.
        */
        return 0;
    case SDL_APP_DIDENTERBACKGROUND:
        /* This will get called if the user accepted whatever sent your app to the background.
           If the user got a phone call and canceled it, you'll instead get an    SDL_APP_DIDENTERFOREGROUND event and restart your loops.
           When you get this, you have 5 seconds to save all your state or the app will be terminated.
           Your app is NOT active at this point.
        */
        return 0;
    case SDL_APP_WILLENTERFOREGROUND:
       /* This call happens when your app is coming back to the foreground.
           Restore all your state here.
       */
        return 0;
    case SDL_APP_DIDENTERFOREGROUND:
        /* Restart your loops here.
           Your app is interactive and getting CPU again.
        */
        return 0;
    default:
        /* No special processing, add it to the event queue */
        return 1;
    }
}

int main(int argc, char *argv[])
{
    SDL_SetEventFilter(HandleAppEvents, NULL);

    //... run your main loop

    return 0;
}

I have a few questions about this code.

What does SDL_SetEventFilter() do? I read the SDL Wiki page, and it seemed particularly vague.

In practice, how does the HandleAppEvents() function work? For example, if I have code like this:

int main(int argc, char* argv[])
{
    //Initialize SDL, etc...
    SDL_SetEventFilter(HandleAppEvents, NULL);


    //I've got some SDL_Textures and windows and things...
    SDL_Window* my_window;
    SDL_Renderer* windowrend;
    SDL_Texture* tex1, tex2, tex3;

    //Primitive game loop
    while(game_is_running){
        handle_input();
        do_logic();
        update_screen();
    }

    destroy_all_my_data();
    SDL_Quit();
    return 0;
}

What sort of code should be placed in HandleAppEvents() or main() to destroy memory or stop my game loop when I receive a SDL_APP_WILLENTERBACKGROUND, for example?

Let's say that tex2 is expendable and can be deleted if the app receives a SDL_APP_LOWMEMORY. How would I delete tex2 from HandleAppEvents() without messing with other data?

What is in the userdata pointer?

When my app enters the background, should I convert my textures into surfaces, and save them in the ../tmp/ directory as bmps, or will they still be in memory when the app comes back to the foreground?

I hope my confusing questions make some sort of sense. If there's a place I can find a thorough documentation for SDL2, it would be great to know.

Thanks for taking a look!

like image 335
BrainSteel Avatar asked Sep 01 '13 22:09

BrainSteel


2 Answers

SDL_SetEventFilter is a way to "get ahead" of SDL's event queue. You basically get the events as they are received, before they get placed in the queue, and in iOS case you have to react to them immediately.

The technical reason behind this is that for these sort of messages, iOS uses a series of callbacks, which SDL receives and wraps for you in order to make the cross platform experience as seamless as possible, but the fact remains that iOS still expects you to act on them before returning from the callback.

So, for example, if we were to just put the message that the system is low on memory on the queue instead of passing it directly to the app via this mechanism, and you just do nothing until that event goes through the queue, you poll it, etc, iOS can forcefully close your app because it doesn't behave as expected.

When the app goes to the background, you don't need to save your textures. iOS does it for you, and if it doesn't have enough memory to do so it just kills your app (you don't ever loose the GL ES/ES2 contexts, which is something that can happen on certain Android devices).

The userdata pointer is going to contain the data you pass as the second parameter to SDL_SetEventFilter, so if you use SDL_SetEventFilter(HandleAppEvents, NULL), userdata will be NULL.

On SDL_APP_WILLENTERBACKGROUND, if I remember correctly, you don't have to do anything. I haven't fired up my iOS app in a while, but I think SDL handles all of its internal state (including blocking the event loop and then restarting it) on its own. The events you do have to handle yourself are SDL_APP_LOWMEMORY and SDL_APP_TERMINATING, how you handle that is app specific though (delete textures, free memory, etc, it goes beyond SDL specifically)

like image 131
gabomdq Avatar answered Oct 21 '22 18:10

gabomdq


As it appears from this thread you have to stop your game loop on SDL_APP_WILLENTERBACKGROUND and resume it on SDL_APP_WILLENTERFOREGROUND to avoid crashes.

like image 38
ezolotko Avatar answered Oct 21 '22 18:10

ezolotko