More rendering subsystem breakout, added a physics subsystem, everything now fires from akgl_game_update() for the user

This commit is contained in:
2026-05-25 21:29:18 -04:00
parent 6314ad7f26
commit d87c5d2c20
13 changed files with 276 additions and 176 deletions

View File

@@ -15,10 +15,12 @@
#include <akgl/registry.h>
#include <akgl/staticstring.h>
#include <akgl/iterator.h>
#include <akgl/physics.h>
#include <akgl/SDL_GameControllerDB.h>
SDL_Window *window = NULL;
akgl_RenderBackend renderer;
akgl_PhysicsBackend physics;
akgl_Frame ball;
akgl_Frame paddle1;
akgl_Frame paddle2;
@@ -42,28 +44,32 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
int screenheight = 0;
int i = 0;
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
ATTEMPT {
strncpy((char *)&game.libversion, AKGL_VERSION, 32);
game.gameStartTime = SDL_GetTicksNS();
game.lastIterTime = game.gameStartTime;
game.lastFPSTime = game.gameStartTime;
game.lowfpsfunc = &akgl_game_lowfps;
FAIL_ZERO_BREAK(errctx, strlen((char *)&game.name), AKERR_NULLPOINTER, "Must provide game name");
FAIL_ZERO_BREAK(errctx, strlen((char *)&game.version), AKERR_NULLPOINTER, "Must provide game version");
FAIL_ZERO_BREAK(errctx, strlen((char *)&game.uri), AKERR_NULLPOINTER, "Must provide game uri");
CATCH(errctx, akgl_heap_init());
CATCH(errctx, akgl_registry_init_actor());
CATCH(errctx, akgl_registry_init_sprite());
CATCH(errctx, akgl_registry_init_spritesheet());
CATCH(errctx, akgl_registry_init_character());
CATCH(errctx, akgl_registry_init_font());
CATCH(errctx, akgl_registry_init_music());
CATCH(errctx, akgl_registry_init_properties());
CATCH(errctx, akgl_registry_init_actor_state_strings());
game.statelock = SDL_CreateMutex();
FAIL_ZERO_RETURN(e, game.statelock, AKGL_ERR_SDL, "%s", SDL_GetError());
CATCH(e, akgl_game_state_lock());
FAIL_ZERO_BREAK(e, strlen((char *)&game.name), AKERR_NULLPOINTER, "Must provide game name");
FAIL_ZERO_BREAK(e, strlen((char *)&game.version), AKERR_NULLPOINTER, "Must provide game version");
FAIL_ZERO_BREAK(e, strlen((char *)&game.uri), AKERR_NULLPOINTER, "Must provide game uri");
CATCH(e, akgl_heap_init());
CATCH(e, akgl_registry_init_actor());
CATCH(e, akgl_registry_init_sprite());
CATCH(e, akgl_registry_init_spritesheet());
CATCH(e, akgl_registry_init_character());
CATCH(e, akgl_registry_init_font());
CATCH(e, akgl_registry_init_music());
CATCH(e, akgl_registry_init_properties());
CATCH(e, akgl_registry_init_actor_state_strings());
} CLEANUP {
} PROCESS(errctx) {
} FINISH(errctx, true)
//IGNORE(akgl_game_state_unlock());
} PROCESS(e) {
} FINISH(e, true)
SDL_SetAppMetadata(game.name, game.version, game.uri);
@@ -72,7 +78,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
}
FAIL_ZERO_RETURN(
errctx,
e,
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD | SDL_INIT_AUDIO),
AKGL_ERR_SDL,
"Couldn't initialize SDL: %s",
@@ -82,33 +88,55 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
for ( i = 0; i < AKGL_SDL_GAMECONTROLLER_DB_LEN ; i++ ) {
if ( SDL_AddGamepadMapping(SDL_GAMECONTROLLER_DB[i]) == -1 ) {
FAIL_ZERO_RETURN(errctx, 0, AKGL_ERR_SDL, "%s", SDL_GetError());
FAIL_ZERO_RETURN(e, 0, AKGL_ERR_SDL, "%s", SDL_GetError());
}
}
PASS(errctx, akgl_controller_open_gamepads());
PASS(e, akgl_controller_open_gamepads());
FAIL_ZERO_RETURN(
errctx,
e,
MIX_Init(),
AKGL_ERR_SDL,
"Couldn't initialize audio: %s",
SDL_GetError());
akgl_mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, 0);
FAIL_ZERO_RETURN(
errctx,
e,
akgl_mixer,
AKGL_ERR_SDL,
"Unable to create mixer device: %s",
SDL_GetError());
FAIL_ZERO_RETURN(
errctx,
e,
TTF_Init(),
AKGL_ERR_SDL,
"Couldn't initialize front engine: %s",
SDL_GetError());
PASS(e, akgl_game_state_unlock());
SUCCEED_RETURN(e);
}
SUCCEED_RETURN(errctx);
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_state_lock(void)
{
PREPARE_ERROR(e);
SDL_Time totaltime = 0;
while ( totaltime < AKGL_TIME_ONESEC_MS ) {
if ( SDL_TryLockMutex(game.statelock) == true ) {
SUCCEED_RETURN(e);
}
totaltime += 100;
SDL_Delay(100);
}
FAIL_RETURN(e, AKGL_ERR_SDL, "%s", SDL_GetError());
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_state_unlock(void)
{
PREPARE_ERROR(e);
SDL_UnlockMutex(game.statelock);
SUCCEED_RETURN(e);
}
void akgl_game_updateFPS()
@@ -135,119 +163,119 @@ void akgl_game_save_actorname_iterator(void *userdata, SDL_PropertiesID props, c
{
FILE *fp = (FILE *)userdata;
akgl_Actor *actor = NULL;
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
ATTEMPT {
FAIL_ZERO_BREAK(errctx, fp, AKERR_NULLPOINTER, "NULL file pointer");
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp));
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp));
actor = SDL_GetPointerProperty(props, name, NULL);
CATCH(errctx, aksl_fwrite(&actor, 1, sizeof(akgl_Actor *), fp));
CATCH(e, aksl_fwrite(&actor, 1, sizeof(akgl_Actor *), fp));
} CLEANUP {
} PROCESS(errctx) {
} FINISH_NORETURN(errctx);
} PROCESS(e) {
} FINISH_NORETURN(e);
}
void akgl_game_save_spritename_iterator(void *userdata, SDL_PropertiesID props, const char *name)
{
FILE *fp = (FILE *)userdata;
akgl_Sprite *sprite = NULL;
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
ATTEMPT {
FAIL_ZERO_BREAK(errctx, fp, AKERR_NULLPOINTER, "NULL file pointer");
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
sprite = SDL_GetPointerProperty(props, name, NULL);
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp));
CATCH(errctx, aksl_fwrite(&sprite, 1, sizeof(akgl_Sprite *), fp));
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite(&sprite, 1, sizeof(akgl_Sprite *), fp));
} CLEANUP {
} PROCESS(errctx) {
} FINISH_NORETURN(errctx);
} PROCESS(e) {
} FINISH_NORETURN(e);
}
void akgl_game_save_spritesheetname_iterator(void *userdata, SDL_PropertiesID props, const char *name)
{
FILE *fp = (FILE *)userdata;
akgl_SpriteSheet *spritesheet = NULL;
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
ATTEMPT {
FAIL_ZERO_BREAK(errctx, fp, AKERR_NULLPOINTER, "NULL file pointer");
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
spritesheet = SDL_GetPointerProperty(props, name, NULL);
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp));
CATCH(errctx, aksl_fwrite(&spritesheet, 1, sizeof(akgl_SpriteSheet *), fp));
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp));
CATCH(e, aksl_fwrite(&spritesheet, 1, sizeof(akgl_SpriteSheet *), fp));
} CLEANUP {
} PROCESS(errctx) {
} FINISH_NORETURN(errctx);
} PROCESS(e) {
} FINISH_NORETURN(e);
}
void akgl_game_save_charactername_iterator(void *userdata, SDL_PropertiesID props, const char *name)
{
FILE *fp = (FILE *)userdata;
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
akgl_Character *character = NULL;
ATTEMPT {
FAIL_ZERO_BREAK(errctx, fp, AKERR_NULLPOINTER, "NULL file pointer");
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
character = SDL_GetPointerProperty(props, name, NULL);
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp));
CATCH(errctx, aksl_fwrite(&character, 1, sizeof(akgl_Character *), fp));
CATCH(e, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite(&character, 1, sizeof(akgl_Character *), fp));
} CLEANUP {
} PROCESS(errctx) {
} FINISH_NORETURN(errctx);
} PROCESS(e) {
} FINISH_NORETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save_actors(FILE *fp)
{
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
char nullval = 0x00;
ATTEMPT {
FAIL_ZERO_BREAK(errctx, fp, AKERR_NULLPOINTER, "NULL file pointer");
FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
// write the actor name pointer table
SDL_EnumerateProperties(
AKGL_REGISTRY_ACTOR,
&akgl_game_save_actorname_iterator,
(void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp));
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_Actor *), fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_Actor *), fp));
// write the sprite name pointer table
SDL_EnumerateProperties(
AKGL_REGISTRY_SPRITE,
&akgl_game_save_spritename_iterator,
(void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp));
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_Sprite *), fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_Sprite *), fp));
// write the spritesheet name pointer table
SDL_EnumerateProperties(
AKGL_REGISTRY_SPRITESHEET,
&akgl_game_save_spritesheetname_iterator,
(void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp));
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_SpriteSheet *), fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_SpriteSheet *), fp));
// write the character name pointer table
SDL_EnumerateProperties(
AKGL_REGISTRY_CHARACTER,
&akgl_game_save_charactername_iterator,
(void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp));
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_Character *), fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp));
CATCH(e, aksl_fwrite((void *)&nullval, 1, sizeof(akgl_Character *), fp));
} CLEANUP {
} PROCESS(errctx) {
} FINISH(errctx, true);
SUCCEED_RETURN(errctx);
} PROCESS(e) {
} FINISH(e, true);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath)
{
FILE *fp = NULL;
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
ATTEMPT {
FAIL_ZERO_BREAK(errctx, fpath, AKERR_NULLPOINTER, "NULL file path");
CATCH(errctx, aksl_fopen(fpath, "wb", &fp));
CATCH(errctx, aksl_fwrite(&game, 1, sizeof(akgl_Game), fp));
CATCH(errctx, akgl_game_save_actors(fp));
} PROCESS(errctx) {
FAIL_ZERO_BREAK(e, fpath, AKERR_NULLPOINTER, "NULL file path");
CATCH(e, aksl_fopen(fpath, "wb", &fp));
CATCH(e, aksl_fwrite(&game, 1, sizeof(akgl_Game), fp));
CATCH(e, akgl_game_save_actors(fp));
} PROCESS(e) {
} CLEANUP {
if ( fp != NULL )
fclose(fp);
} FINISH(errctx, true);
SUCCEED_RETURN(errctx); // SUCCEED_NORETURN if in main().
} FINISH(e, true);
SUCCEED_RETURN(e); // SUCCEED_NORETURN if in main().
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_objectnamemap(FILE *fp, SDL_PropertiesID map, int namelength, int ptrlength, SDL_PropertiesID registry)
@@ -257,10 +285,10 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_objectnamemap(FILE *fp, SDL_Pr
char objname[namelength];
int retval = 0;
PREPARE_ERROR(errctx);
PREPARE_ERROR(e);
while ( 1 ) {
CATCH(errctx, aksl_fread((void *)&objname, 1, namelength, fp));
CATCH(errctx, aksl_fread((void *)&ptr, 1, ptrlength, fp));
CATCH(e, aksl_fread((void *)&objname, 1, namelength, fp));
CATCH(e, aksl_fread((void *)&ptr, 1, ptrlength, fp));
// End of the map
if ( ptr == 0x00 && objname[0] == 0x00 ) {
break;
@@ -273,43 +301,43 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_objectnamemap(FILE *fp, SDL_Pr
// SDL_Properties objects can only use string keys, so we can't use the
// old pointer as a key without first converting it to a string.
CATCH(errctx, aksl_memset((void *)&ptrstring, 0x00, 32));
CATCH(e, aksl_memset((void *)&ptrstring, 0x00, 32));
snprintf((char *)&ptrstring, 32, "%p", ptr);
SDL_SetPointerProperty(
map,
ptrstring,
SDL_GetPointerProperty(registry, objname, NULL));
};
SUCCEED_RETURN(errctx);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_versioncmp(char *versiontype, char *newversion, char *curversion)
{
semver_t current_version = {};
semver_t compare_version = {};
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, versiontype, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(errctx, curversion, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(errctx, newversion, AKERR_NULLPOINTER, "NULL argument");
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, versiontype, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(e, curversion, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(e, newversion, AKERR_NULLPOINTER, "NULL argument");
ATTEMPT {
// Check save game library version
FAIL_NONZERO_BREAK(
errctx,
e,
semver_parse((const char *)curversion, &current_version),
AKERR_VALUE,
"Invalid semantic %s version in current game: %s",
versiontype,
(char *)curversion);
FAIL_NONZERO_BREAK(
errctx,
e,
semver_parse((const char *)newversion, &compare_version),
AKERR_VALUE,
"Invalid semantic %s version in save game: %s",
versiontype,
(char *)&newversion);
FAIL_ZERO_BREAK(
errctx,
e,
semver_satisfies(compare_version, current_version, "="),
AKERR_API,
"Incompatible save game %s version (%s != %s)",
@@ -319,9 +347,9 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_versioncmp(char *versiontype,
} CLEANUP {
semver_free(&current_version);
semver_free(&compare_version);
} PROCESS(errctx) {
} FINISH(errctx, true);
SUCCEED_RETURN(errctx);
} PROCESS(e) {
} FINISH(e, true);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath)
@@ -333,21 +361,21 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath)
SDL_PropertiesID charactermap;
FILE *fp = NULL;
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, fpath, AKERR_NULLPOINTER, "NULL file path");
PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, fpath, AKERR_NULLPOINTER, "NULL file path");
ATTEMPT {
CATCH(errctx, aksl_fopen(fpath, "rb", &fp));
CATCH(errctx, aksl_fread((void *)&savegame, 1, sizeof(akgl_Game), fp));
CATCH(errctx, akgl_game_load_versioncmp("library", (char *)&savegame.libversion, (char *)AKGL_VERSION));
CATCH(errctx, akgl_game_load_versioncmp("game", (char *)&savegame.version, (char *)&game.version));
CATCH(e, aksl_fopen(fpath, "rb", &fp));
CATCH(e, aksl_fread((void *)&savegame, 1, sizeof(akgl_Game), fp));
CATCH(e, akgl_game_load_versioncmp("library", (char *)&savegame.libversion, (char *)AKGL_VERSION));
CATCH(e, akgl_game_load_versioncmp("game", (char *)&savegame.version, (char *)&game.version));
FAIL_NONZERO_RETURN(
errctx,
e,
strncmp((char *)&savegame.name, (char *)&game.name, 256),
AKERR_API,
"Savegame is not compatible with this game");
FAIL_NONZERO_RETURN(
errctx,
e,
strncmp((char *)&savegame.uri, (char *)&game.uri, 256),
AKERR_API,
"Savegame is not compatible with this game");
@@ -355,23 +383,64 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath)
memcpy((void *)&game, (void *)&savegame, sizeof(akgl_Game));
// Load actor name map
actormap = SDL_CreateProperties();
CATCH(errctx, akgl_game_load_objectnamemap(fp, actormap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_Actor *), AKGL_REGISTRY_ACTOR));
CATCH(e, akgl_game_load_objectnamemap(fp, actormap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_Actor *), AKGL_REGISTRY_ACTOR));
// Load sprite name map
spritemap = SDL_CreateProperties();
CATCH(errctx, akgl_game_load_objectnamemap(fp, spritemap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_Sprite *), AKGL_REGISTRY_SPRITE));
CATCH(e, akgl_game_load_objectnamemap(fp, spritemap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_Sprite *), AKGL_REGISTRY_SPRITE));
// Load spritesheet name map
spritesheetmap = SDL_CreateProperties();
CATCH(errctx, akgl_game_load_objectnamemap(fp, spritesheetmap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_SpriteSheet *), AKGL_REGISTRY_SPRITESHEET));
CATCH(e, akgl_game_load_objectnamemap(fp, spritesheetmap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_SpriteSheet *), AKGL_REGISTRY_SPRITESHEET));
// Load character name map
charactermap = SDL_CreateProperties();
CATCH(errctx, akgl_game_load_objectnamemap(fp, charactermap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_Character *), AKGL_REGISTRY_CHARACTER));
CATCH(e, akgl_game_load_objectnamemap(fp, charactermap, AKGL_ACTOR_MAX_NAME_LENGTH, sizeof(akgl_Character *), AKGL_REGISTRY_CHARACTER));
// Now that we have all of our pointer maps built, we can load the actual binary objects and reset their pointers
} CLEANUP {
if ( fp != NULL ) {
fclose(fp);
}
} PROCESS(errctx) {
} FINISH(errctx, true);
} PROCESS(e) {
} FINISH(e, true);
SUCCEED_RETURN(errctx);
SUCCEED_RETURN(e);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_update(akgl_Iterator *opflags)
{
PREPARE_ERROR(e);
akgl_Iterator defflags = {
.flags = (AKGL_ITERATOR_OP_LAYERMASK | AKGL_ITERATOR_OP_LAYERMASK),
.layerid = 0
};
SDL_Time curTime = SDL_GetTicksNS();
akgl_Actor *actor = NULL;
if ( opflags == NULL ) {
opflags = &defflags;
}
PASS(e, akgl_game_state_lock());
akgl_game_updateFPS();
for ( int i = 0; i < AKGL_TILEMAP_MAX_LAYERS; i++ ) {
if ( opflags == &defflags ) {
opflags->layerid = i;
}
for ( int j = 0; j < AKGL_MAX_HEAP_ACTOR; j++ ) {
actor = &HEAP_ACTOR[j];
if ( actor->refcount == 0 ) {
continue;
}
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_TILEMAPSCALE) ) {
PASS(e, akgl_tilemap_scale_actor(&gamemap, actor));
} else {
actor->scale = 1.0;
}
PASS(e, actor->updatefunc(actor));
}
}
PASS(e, physics.simulate(&physics, NULL));
PASS(e, renderer.draw_world(&renderer, NULL));
PASS(e, akgl_game_state_unlock());
SUCCEED_RETURN(e);
}