From 93d033a3c6734cf92c32b2219bbb9f8e3aea55bf Mon Sep 17 00:00:00 2001 From: Arslaan Pathan Date: Thu, 13 Aug 2026 19:10:04 +1200 Subject: Work on making a proper event loop and implementing more of the engine --- AndroidManifest.xml | 2 +- Makefile | 2 +- jni/Android.mk | 2 +- jni/Application.mk | 1 + jni/main.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 135 insertions(+), 4 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d2399c0..2ff66cb 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,7 +1,7 @@ - + #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 (1) { + while (!state->destroyRequested) { if (ALooper_pollAll(-1, NULL, &events, (void**)&source) >= 0) { if (source) { source->process(state, source); -- cgit v1.2.3