#include #include #include #include #include #include #include #include #include #include #include #include #define LOG_TAG "moku" #define _LOG(priority, fmt, ...) \ ((void)__android_log_print((priority), (LOG_TAG), \ (fmt)__VA_OPT__(, ) __VA_ARGS__)) #define LOGE(fmt, ...) _LOG(ANDROID_LOG_ERROR, (fmt)__VA_OPT__(, ) __VA_ARGS__) #define LOGW(fmt, ...) _LOG(ANDROID_LOG_WARN, (fmt)__VA_OPT__(, ) __VA_ARGS__) #define LOGI(fmt, ...) _LOG(ANDROID_LOG_INFO, (fmt)__VA_OPT__(, ) __VA_ARGS__) enum Color { COLOR_RED = 0x000000ff, COLOR_GREEN = 0x0000ff00, COLOR_BLUE = 0x00ff0000 }; struct engine { struct android_app *app; int window_initialized; int running; int color; uint64_t last_update; }; struct engine *engine_new(struct android_app* app) { struct engine engine; memset(&engine, 0, sizeof(engine)); engine.window_initialized = 0; engine.app = app; engine.running = 0; engine.color = 0; engine.last_update = (uint64_t)0; } uint64_t get_timestamp_ns() { struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); return (uint64_t)ts.tv_nsec + (uint64_t)ts.tv_sec * 1000000000; } static void engine_schedule_tick(struct engine *engine); static void engine_real_tick(struct engine *engine) { if (!engine->running) return; engine_schedule_tick(engine); } static void engine_tick(long frameTimeNanos, void *data) { struct engine *engine; if (!data) return; engine = (struct engine*)data; engine_real_tick(engine); } static void engine_schedule_tick(struct engine *engine) { AChoreographer_postFrameCallback(AChoreographer_getInstance(), engine_tick, (void*)engine); } /* TODO implement these stubs */ void engine_attach_window(struct engine *engine) { if (ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM) < 0) { engine->window_initialized = 0; return; } engine->window_initialized = 1; engine->color = COLOR_RED; engine->last_update = get_timestamp_ns(); }; void engine_detach_window(struct engine *engine) { /* Called when native window for app is destroyed. * Doesn't mean app is being killed, also happens on rotate * Normally, with a traditional OpenGL app, do cleanup here * At the moment, it's fine to just set a flag to disable the rendering loop */ engine->window_initialized = 0; }; void engine_resume(struct engine *engine) { if (!engine->running) { engine->running = 1; engine_schedule_tick(engine); } }; void engine_pause(struct engine *engine) { }; static void engine_handle_cmd(struct android_app *app, int32_t cmd) { struct engine *engine; engine = (struct engine *)app->userData; switch (cmd) { case APP_CMD_INIT_WINDOW: engine_attach_window(engine); break; case APP_CMD_TERM_WINDOW: engine_detach_window(engine); break; case APP_CMD_GAINED_FOCUS: engine_resume(engine); break; case APP_CMD_LOST_FOCUS: engine_pause(engine); break; } } void android_main(struct android_app *state) { /* Declarations */ struct android_poll_source *source; struct engine engine; int events; /* Code starts here */ app_dummy(); memset(&engine, 0, sizeof(engine)); state->userData = &engine; state->onAppCmd = engine_handle_cmd; /* do stuff here */ while (!state->destroyRequested) { if (ALooper_pollAll(-1, NULL, &events, (void**)&source) >= 0) { if (source) { source->process(state, source); } } /* more stuff here */ } }