コード例 #1
0
ファイル: ceu_os.c プロジェクト: hihihippp/ceu
int ceu_go_all (tceu_app* app)
{
    /* All code run atomically:
     * - the program is always locked as a whole
     * -    thread spawns will unlock => re-lock
     * - but program will still run to completion
     */
    app->init(app);     /* calls CEU_THREADS_MUTEX_LOCK() */

#ifdef CEU_IN_OS_START
#if defined(CEU_RET) || defined(CEU_OS)
    if (app->isAlive)
#endif
        ceu_sys_go(app, CEU_IN_OS_START, (tceu_evtp)NULL);
#endif

#ifdef CEU_ASYNCS
    while(
#if defined(CEU_RET) || defined(CEU_OS)
            app->isAlive &&
#endif
            (
#ifdef CEU_THREADS
                app->threads_n>0 ||
#endif
                app->pendingAsyncs
            ) )
    {
        ceu_sys_go(app, CEU_IN__ASYNC, (tceu_evtp)NULL);
#ifdef CEU_THREADS
        CEU_THREADS_MUTEX_UNLOCK(&app->threads_mutex);
        /* allow threads to also execute */
        CEU_THREADS_MUTEX_LOCK(&app->threads_mutex);
#endif
    }
#endif

#ifdef CEU_THREADS
    CEU_THREADS_MUTEX_UNLOCK(&app->threads_mutex);
#endif

#ifdef CEU_NEWS
#ifdef CEU_RUNTESTS
    assert(_ceu_dyns_ == 0);
#endif
#endif

#ifdef CEU_RET
    return app->ret;
#else
    return 0;
#endif
}
コード例 #2
0
ファイル: main.c プロジェクト: Johnicholas/rocks
int main (int argc, char *argv[])
#endif
{
    int err = SDL_Init(SDL_INIT_EVERYTHING);
    if (err != 0) {
        printf("SDL_Init failed: %s\n", SDL_GetError());
        return err;
    }

    WCLOCK_nxt = CEU_WCLOCK_INACTIVE;
    u32 old = SDL_GetTicks();
    u32 fps_old = old;

#ifdef CEU_THREADS
    // just before executing CEU code
    CEU_THREADS_MUTEX_LOCK(&CEU.threads_mutex);
#endif

    char CEU_DATA[sizeof(CEU_Main)];
    tceu_app app;
        app.data = (tceu_org*) &CEU_DATA;
        app.init = &ceu_app_init;

    app.init(&app);    /* calls CEU_THREADS_MUTEX_LOCK() */
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif

#ifdef CEU_IN_OS_START
    ceu_sys_go(&app, CEU_IN_OS_START, (tceu_evtp)NULL);
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif
#endif

#ifdef CEU_IN_SDL_REDRAW
    ceu_sys_go(&app, CEU_IN_SDL_REDRAW, (tceu_evtp)NULL);
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif
#endif

    SDL_Event evt;
#ifdef __ANDROID__
    int isPaused = 0;
#endif

    for (;;)
    {
#ifdef CEU_THREADS
        // unlock from INIT->START->REDRAW or last loop iteration
        CEU_THREADS_MUTEX_UNLOCK(&CEU.threads_mutex);
#endif

#ifndef SDL_SIMUL

        /*
         * With    SDL_DT, 'tm=0' (update as fast as possible).
         * Without SDL_DT, 'tm=?' respects the timers.
         */
#ifdef CEU_IN_SDL_DT
        s32 tm =  0;
#else
        s32 tm = -1;
#ifdef CEU_WCLOCKS
        if (WCLOCK_nxt != CEU_WCLOCK_INACTIVE)
            tm = WCLOCK_nxt / 1000;
#endif
#ifdef CEU_ASYNCS
        if (app.pendingAsyncs) {
            tm = 0;
        }
#endif
#endif  // CEU_IN_SDL_DT

        //SDL_EventState(SDL_FINGERMOTION, SDL_IGNORE);

        int has;
#ifdef __ANDROID__
        if (isPaused) {
            has = SDL_WaitEvent(&evt);
        } else
#endif
        {
            has = SDL_WaitEventTimeout(&evt, tm);
        }

        u32 now = SDL_GetTicks();
        if (old == now) now++;      // force a minimum change
        s32 dt = now - old;
        old = now;

        // DT/WCLOCK/REDRAW respecting FPS (at most)
        int fps_ok = !SDL_PollEvent(NULL);
        if (! fps_ok) {
            if (old >= fps_old+1000/CEU_SDL_FPS) {
                fps_old = old;
                fps_ok = 1;
            }
        }

#ifdef CEU_THREADS
        // just before executing CEU code
        CEU_THREADS_MUTEX_LOCK(&CEU.threads_mutex);
#endif

#ifdef __ANDROID__
        if (!isPaused)
#endif
        if (fps_ok) {
#ifdef CEU_WCLOCKS
#ifndef CEU_IN_SDL_DT
            if (WCLOCK_nxt != CEU_WCLOCK_INACTIVE)
            {
                //redraw = WCLOCK_nxt <= 1000*dt;
#endif
                ceu_sys_go(&app, CEU_IN__WCLOCK, (tceu_evtp)(1000*dt));
#ifdef CEU_RET
                if (! app.isAlive)
                    goto END;
#endif

                while (WCLOCK_nxt <= 0) {
                    ceu_sys_go(&app, CEU_IN__WCLOCK, (tceu_evtp)0);
#ifdef CEU_RET
                    if (! app.isAlive)
                        goto END;
#endif
                }
#ifndef CEU_IN_SDL_DT
            }
#endif
#endif
#ifdef CEU_IN_SDL_DT
            if (fps_ok) {
                ceu_sys_go(&app, CEU_IN_SDL_DT, (tceu_evtp)dt);
            }
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
            //redraw = 1;
#endif
        }

        // OTHER EVENTS
        if (has)
        {
            int handled = 1;        // =1 for defined events
            tceu_evtp evtp = (tceu_evtp)(void*)&evt;
            switch (evt.type) {
#ifdef CEU_IN_SDL_QUIT
                case SDL_QUIT:
                    ceu_sys_go(&app, CEU_IN_SDL_QUIT, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_WINDOWEVENT
                case SDL_WINDOWEVENT:
                    ceu_sys_go(&app, CEU_IN_SDL_WINDOWEVENT, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_KEYDOWN
                case SDL_KEYDOWN:
                    ceu_sys_go(&app, CEU_IN_SDL_KEYDOWN, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_KEYUP
                case SDL_KEYUP:
                    ceu_sys_go(&app, CEU_IN_SDL_KEYUP, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_TEXTINPUT
                case SDL_TEXTINPUT:
                    ceu_sys_go(&app, CEU_IN_SDL_TEXTINPUT, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_TEXTEDITING
                case SDL_TEXTEDITING:
                    ceu_sys_go(&app, CEU_IN_SDL_TEXTEDITING, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_MOUSEMOTION
                case SDL_MOUSEMOTION:
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEMOTION, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_MOUSEBUTTONDOWN
                case SDL_MOUSEBUTTONDOWN:
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEBUTTONDOWN, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_MOUSEBUTTONUP
                case SDL_MOUSEBUTTONUP:
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEBUTTONUP, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_FINGERDOWN
                case SDL_FINGERDOWN:
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERDOWN, evtp);
                    break;
#endif
#ifdef CEU_IN_SDL_FINGERUP
                case SDL_FINGERUP:
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERUP, evtp);
                    break;
#endif

#if defined(CEU_IN_SDL_APP_WILLENTERBACKGROUND) || defined(__ANDROID__)
                case SDL_APP_WILLENTERBACKGROUND:
#ifdef __ANDROID__
                    // handle onPause/onResume
                    isPaused = 1;
#endif
#ifdef CEU_IN_SDL_APP_WILLENTERBACKGROUND
                    ceu_sys_go(&app, CEU_IN_SDL_APP_WILLENTERBACKGROUND, evtp);
#endif
                    break;
#endif
#if defined(CEU_IN_SDL_APP_WILLENTERFOREGROUND) || defined(__ANDROID__)
                case SDL_APP_WILLENTERFOREGROUND:
#ifdef __ANDROID__
                    // handle onPause/onResume
                    isPaused = 0;
                    old = SDL_GetTicks();   // ignores previous 'old' on resume
#endif
#ifdef CEU_IN_SDL_APP_WILLENTERFOREGROUND
                    ceu_sys_go(&app, CEU_IN_SDL_APP_WILLENTERFOREGROUND, evtp);
#endif
                    break;
#endif
#ifdef CEU_IN_SDL_FINGERMOTION
                case SDL_FINGERMOTION:
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERMOTION, evtp);
                    break;
#endif
                default:
                    handled = 0;    // undefined event
            }
#ifdef CEU_RET
            if (! app.isAlive) goto END;
#endif
            //redraw = redraw || handled;
        }

#ifdef CEU_IN_SDL_REDRAW
        //if (redraw && !SDL_PollEvent(NULL)) {
        if (fps_ok) {
            ceu_sys_go(&app, CEU_IN_SDL_REDRAW, (tceu_evtp)NULL);
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
        }
#endif

#endif  // SDL_SIMUL

#ifdef CEU_ASYNCS
        if (app.pendingAsyncs) {
            ceu_sys_go(&app, CEU_IN__ASYNC, (tceu_evtp)NULL);
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
        }
#endif
    }
END:
#ifdef CEU_THREADS
    // only reachable if LOCKED
    CEU_THREADS_MUTEX_UNLOCK(&CEU.threads_mutex);
#endif
    SDL_Quit();         // TODO: slow
#ifdef CEU_RET
    return app.ret;
#else
    return 0;
#endif
}
コード例 #3
0
ファイル: main.c プロジェクト: droid-in-the-sky/rocks
int main (int argc, char *argv[])
#endif
{
    int err = SDL_Init(SDL_INIT_EVERYTHING);
    if (err != 0) {
        printf("SDL_Init failed: %s\n", SDL_GetError());
        return err;
    }

    WCLOCK_nxt = CEU_WCLOCK_INACTIVE;
    u32 old = SDL_GetTicks();
#ifdef CEU_FPS
    int fps_next = (1000/CEU_FPS);
#endif

    tceu_app app;
        app.data = (tceu_org*) &CEU_DATA;
        app.init = &ceu_app_init;

#ifdef CEU_THREADS
    // just before executing CEU code
    CEU_THREADS_MUTEX_LOCK(&app.threads_mutex);
#endif

    app.init(&app);    /* calls CEU_THREADS_MUTEX_LOCK() */
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif

#ifndef SIMULATION_TEST

#ifdef CEU_IN_OS_START_
    ceu_sys_go(&app, CEU_IN_OS_START_, NULL);
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif
#endif
#ifdef CEU_IN_OS_START
if (!CEU_TIMEMACHINE_ON) {
    ceu_sys_go(&app, CEU_IN_OS_START, NULL);
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif
}
#endif

#ifdef CEU_IN_SDL_REDRAW_
    ceu_sys_go(&app, CEU_IN_SDL_REDRAW_, NULL);
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif
#endif
#ifdef CEU_IN_SDL_REDRAW
if (!CEU_TIMEMACHINE_ON) {
    ceu_sys_go(&app, CEU_IN_SDL_REDRAW, NULL);
#ifdef CEU_RET
    if (! app.isAlive)
        goto END;
#endif
}
#endif

#endif  /* SIMULATION_TEST */

    SDL_Event evt;
#ifdef __ANDROID__
    int isPaused = 0;
#endif

    for (;;)
    {
#ifdef CEU_THREADS
        // unlock from INIT->START->REDRAW or last loop iteration
        CEU_THREADS_MUTEX_UNLOCK(&app.threads_mutex);
#endif

        /*
         * With    SDL_DT, 'tm=0' (update as fast as possible).
         * Without SDL_DT, 'tm=?' respects the timers.
         */
#if defined(CEU_IN_SDL_DT) || defined(CEU_IN_SDL_DT_) || defined(CEU_FPS)

#ifdef CEU_FPS
        s32 tm = (CEU_TIMEMACHINE_ON ? 0 : fps_next);
#else
        s32 tm = 0;     // as fast as possible
#endif

#else /* !(defined(CEU_IN_SDL_DT) || defined(CEU_IN_SDL_DT_) || defined(CEU_FPS)) */

        s32 tm = -1;
#ifdef CEU_WCLOCKS
        if (WCLOCK_nxt != CEU_WCLOCK_INACTIVE)
            tm = WCLOCK_nxt / 1000;
#endif
#ifdef CEU_ASYNCS
        if (app.pendingAsyncs) {
            tm = 0;
        }
#endif

#endif /* defined(CEU_IN_SDL_DT) || defined(CEU_IN_SDL_DT_) || defined(CEU_FPS) */

        //SDL_EventState(SDL_FINGERMOTION, SDL_IGNORE);

        int has;
#ifdef __ANDROID__
        if (isPaused) {
            has = SDL_WaitEvent(&evt);
        } else
#endif
        {
            has = SDL_WaitEventTimeout(&evt, tm);
        }

#ifndef SIMULATION_TEST

        u32 now = SDL_GetTicks();
        s32 dt_ms = (now - old);
        assert(dt_ms >= 0);
        old = now;

#ifdef CEU_FPS
        /* force dt_ms=(1000/CEU_FPS) */
        int fps_ok = 0;
        int togo = (fps_next - dt_ms);
        if (togo <= 0) {
            fps_ok = 1;
            dt_ms = (1000/CEU_FPS);
            fps_next = (dt_ms + togo);
            if (fps_next < 0) {
/*printf("[TODO: main.c] delayed %d\n", -fps_next);*/
                fps_next = 0;
            }
        } else {
            fps_next = togo;
        }
        assert(fps_next >= 0);
#else
        int fps_ok = 1;
#endif

        s32 dt_us = dt_ms*1000;

#ifdef CEU_THREADS
        // just before executing CEU code
        CEU_THREADS_MUTEX_LOCK(&app.threads_mutex);
#endif

#ifdef __ANDROID__
        if (!isPaused)
#endif
        if (fps_ok) {
#ifdef CEU_WCLOCKS
#if ! (defined(CEU_IN_SDL_DT) || defined(CEU_IN_SDL_DT_))
            if (WCLOCK_nxt != CEU_WCLOCK_INACTIVE)
            {
                //redraw = WCLOCK_nxt <= dt_us;
#endif
#ifdef CEU_TIMEMACHINE
//#ifdef CEU_IN__WCLOCK_ (TODO: always defined)
                ceu_sys_go(&app, CEU_IN__WCLOCK_, &dt_us);
#ifdef CEU_RET
                if (! app.isAlive)
                    goto END;
#endif
                while (WCLOCK_nxt <= 0) {
                    s32 dt_us = 0;
                    ceu_sys_go(&app, CEU_IN__WCLOCK_, &dt_us);
#ifdef CEU_RET
                    if (! app.isAlive)
                        goto END;
#endif
                }
#endif
if (!CEU_TIMEMACHINE_ON) {
                ceu_sys_go(&app, CEU_IN__WCLOCK, &dt_us);
#ifdef CEU_RET
                if (! app.isAlive)
                    goto END;
#endif
                while (WCLOCK_nxt <= 0) {
                    s32 dt_us = 0;
                    ceu_sys_go(&app, CEU_IN__WCLOCK, &dt_us);
#ifdef CEU_RET
                    if (! app.isAlive)
                        goto END;
#endif
                }
}
#if ! (defined(CEU_IN_SDL_DT) || defined(CEU_IN_SDL_DT_))
            }
#endif
#endif

#ifdef CEU_IN_SDL_DT_
            if (fps_ok) {
                ceu_sys_go(&app, CEU_IN_SDL_DT_, &dt_ms);
            }
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
            //redraw = 1;
#endif
#ifdef CEU_IN_SDL_DT
if (!CEU_TIMEMACHINE_ON) {
            if (fps_ok) {
                ceu_sys_go(&app, CEU_IN_SDL_DT, &dt_ms);
            }
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
            //redraw = 1;
}
#endif
        }

        // OTHER EVENTS
        if (has)
        {
            int handled = 1;        // =1 for defined events
            SDL_Event* evtp = &evt;
            switch (evt.type) {
                case SDL_QUIT:
#ifdef CEU_IN_SDL_QUIT_
                    ceu_sys_go(&app, CEU_IN_SDL_QUIT_, &evtp);
#endif
#ifdef CEU_IN_SDL_QUIT
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_QUIT, &evtp);
}
#endif
                    break;
                case SDL_WINDOWEVENT:
#ifdef CEU_IN_SDL_WINDOWEVENT_
                    ceu_sys_go(&app, CEU_IN_SDL_WINDOWEVENT_, &evtp);
#endif
#ifdef CEU_IN_SDL_WINDOWEVENT
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_WINDOWEVENT, &evtp);
}
#endif
                    break;
                case SDL_KEYDOWN:
#ifdef CEU_IN_SDL_KEYDOWN_
                    ceu_sys_go(&app, CEU_IN_SDL_KEYDOWN_, &evtp);
#endif
#ifdef CEU_IN_SDL_KEYDOWN
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_KEYDOWN, &evtp);
}
#endif
                    break;
                case SDL_KEYUP:
#ifdef CEU_IN_SDL_KEYUP_
                    ceu_sys_go(&app, CEU_IN_SDL_KEYUP_, &evtp);
#endif
#ifdef CEU_IN_SDL_KEYUP
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_KEYUP, &evtp);
}
#endif
                    break;
                case SDL_TEXTINPUT:
#ifdef CEU_IN_SDL_TEXTINPUT_
                    ceu_sys_go(&app, CEU_IN_SDL_TEXTINPUT_, &evtp);
#endif
#ifdef CEU_IN_SDL_TEXTINPUT
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_TEXTINPUT, &evtp);
}
#endif
                    break;
                case SDL_TEXTEDITING:
#ifdef CEU_IN_SDL_TEXTEDITING_
                    ceu_sys_go(&app, CEU_IN_SDL_TEXTEDITING_, &evtp);
#endif
#ifdef CEU_IN_SDL_TEXTEDITING
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_TEXTEDITING, &evtp);
}
#endif
                    break;
                case SDL_MOUSEMOTION:
#ifdef CEU_IN_SDL_MOUSEMOTION_
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEMOTION_, &evtp);
#endif
#ifdef CEU_IN_SDL_MOUSEMOTION
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEMOTION, &evtp);
}
#endif
                    break;
                case SDL_MOUSEBUTTONDOWN:
#ifdef CEU_IN_SDL_MOUSEBUTTONDOWN_
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEBUTTONDOWN_, &evtp);
#endif
#ifdef CEU_IN_SDL_MOUSEBUTTONDOWN
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEBUTTONDOWN, &evtp);
}
#endif
                    break;
                case SDL_MOUSEBUTTONUP:
#ifdef CEU_IN_SDL_MOUSEBUTTONUP_
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEBUTTONUP_, &evtp);
#endif
#ifdef CEU_IN_SDL_MOUSEBUTTONUP
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_MOUSEBUTTONUP, &evtp);
}
#endif
                    break;
                case SDL_FINGERDOWN:
#ifdef CEU_IN_SDL_FINGERDOWN_
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERDOWN_, &evtp);
#endif
#ifdef CEU_IN_SDL_FINGERDOWN
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERDOWN, &evtp);
}
#endif
                    break;
                case SDL_FINGERUP:
#ifdef CEU_IN_SDL_FINGERUP_
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERUP_, &evtp);
#endif
#ifdef CEU_IN_SDL_FINGERUP
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERUP, &evtp);
}
#endif
                    break;
                case SDL_FINGERMOTION:
#ifdef CEU_IN_SDL_FINGERMOTION_
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERMOTION_, &evtp);
#endif
#ifdef CEU_IN_SDL_FINGERMOTION
if (!CEU_TIMEMACHINE_ON) {
                    ceu_sys_go(&app, CEU_IN_SDL_FINGERMOTION, &evtp);
}
#endif
                    break;

/* TODO: "_" events */
#if defined(CEU_IN_SDL_APP_WILLENTERBACKGROUND) || defined(__ANDROID__)
                case SDL_APP_WILLENTERBACKGROUND:
#ifdef __ANDROID__
                    // handle onPause/onResume
                    isPaused = 1;
#endif
#ifdef CEU_IN_SDL_APP_WILLENTERBACKGROUND
                    ceu_sys_go(&app, CEU_IN_SDL_APP_WILLENTERBACKGROUND, &evtp);
#endif
                    break;
#endif
#if defined(CEU_IN_SDL_APP_WILLENTERFOREGROUND) || defined(__ANDROID__)
                case SDL_APP_WILLENTERFOREGROUND:
#ifdef __ANDROID__
                    // handle onPause/onResume
                    isPaused = 0;
                    old = SDL_GetTicks();   // ignores previous 'old' on resume
#endif
#ifdef CEU_IN_SDL_APP_WILLENTERFOREGROUND
                    ceu_sys_go(&app, CEU_IN_SDL_APP_WILLENTERFOREGROUND, &evtp);
#endif
                    break;
#endif
                default:
                    handled = 0;    // undefined event
            }
#ifdef CEU_RET
            if (! app.isAlive) goto END;
#endif
            //redraw = redraw || handled;
        }

#ifdef CEU_IN_SDL_REDRAW_
        //if (redraw && !SDL_PollEvent(NULL))
        if (fps_ok) {
            ceu_sys_go(&app, CEU_IN_SDL_REDRAW_, NULL);
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
        }
#endif
#ifdef CEU_IN_SDL_REDRAW
if (!CEU_TIMEMACHINE_ON) {
        //if (redraw && !SDL_PollEvent(NULL))
        if (fps_ok) {
            ceu_sys_go(&app, CEU_IN_SDL_REDRAW, NULL);
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
        }
}
#endif

#endif  /* SIMULATION_TEST */

/* TODO: "_" events */
#ifdef CEU_ASYNCS
        if (app.pendingAsyncs) {
            ceu_sys_go(&app, CEU_IN__ASYNC, NULL);
#ifdef CEU_RET
            if (! app.isAlive)
                goto END;
#endif
        }
#endif
    }
END:
#ifdef CEU_THREADS
    // only reachable if LOCKED
    CEU_THREADS_MUTEX_UNLOCK(&app.threads_mutex);
#endif
    SDL_Quit();         // TODO: slow
#ifdef CEU_RET
    return app.ret;
#else
    return 0;
#endif
}