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

@@ -1,7 +1,7 @@
#ifndef _SDL_GAMECONTROLLERDB_H_ #ifndef _SDL_GAMECONTROLLERDB_H_
#define _SDL_GAMECONTROLLERDB_H_ #define _SDL_GAMECONTROLLERDB_H_
// Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Sun May 24 09:58:23 PM EDT 2026 // Taken from https://raw.githubusercontent.com/mdqinc/SDL_GameControllerDB/refs/heads/master/gamecontrollerdb.txt on Mon May 25 09:28:01 PM EDT 2026
#define AKGL_SDL_GAMECONTROLLER_DB_LEN 2228 #define AKGL_SDL_GAMECONTROLLER_DB_LEN 2228

View File

@@ -70,9 +70,11 @@ typedef struct akgl_Actor {
bool movement_controls_face; bool movement_controls_face;
void *actorData; void *actorData;
bool visible; bool visible;
SDL_Time logictimer; SDL_Time movetimer;
float32_t mass;
float32_t x; float32_t x;
float32_t y; float32_t y;
float32_t z;
float32_t scale; float32_t scale;
struct akgl_Actor *children[AKGL_ACTOR_MAX_CHILDREN]; struct akgl_Actor *children[AKGL_ACTOR_MAX_CHILDREN];
struct akgl_Actor *parent; struct akgl_Actor *parent;

View File

@@ -13,5 +13,6 @@
_Pragma("GCC diagnostic pop") _Pragma("GCC diagnostic pop")
#define AKGL_ERR_SDL AKERR_LAST_ERRNO_VALUE + 1 #define AKGL_ERR_SDL AKERR_LAST_ERRNO_VALUE + 1
#define AKGL_ERR_LOGICINTERRUPT AKERR_LAST_ERRNO_VALUE + 2
#endif // _ERROR_H_ #endif // _ERROR_H_

View File

@@ -2,10 +2,11 @@
#define _AKGL_GAME_H_ #define _AKGL_GAME_H_
#include <stdint.h> #include <stdint.h>
#include "types.h"
#include <SDL3_mixer/SDL_mixer.h> #include <SDL3_mixer/SDL_mixer.h>
#include "types.h"
#include "tilemap.h" #include "tilemap.h"
#include "renderer.h" #include "renderer.h"
#include "physics.h"
#define AKGL_VERSION "0.1.0" #define AKGL_VERSION "0.1.0"
@@ -33,6 +34,7 @@ typedef struct {
char name[256]; char name[256];
char uri[256]; char uri[256];
akgl_GameState state; akgl_GameState state;
SDL_Mutex *statelock;
int16_t fps; int16_t fps;
SDL_Time gameStartTime; SDL_Time gameStartTime;
SDL_Time lastIterTime; SDL_Time lastIterTime;
@@ -49,8 +51,10 @@ extern MIX_Track *akgl_tracks[AKGL_GAME_AUDIO_MAX_TRACKS];
extern SDL_FRect camera; extern SDL_FRect camera;
extern akgl_Game game; extern akgl_Game game;
extern akgl_RenderBackend renderer; extern akgl_RenderBackend renderer;
extern akgl_PhysicsBackend physics;
#define AKGL_BITMASK_HAS(x, y) (x & y) == y #define AKGL_BITMASK_HAS(x, y) (x & y) == y
#define AKGL_BITMASK_HASNOT(x, y) (x & y) != y
#define AKGL_BITMASK_ADD(x, y) x |= y #define AKGL_BITMASK_ADD(x, y) x |= y
#define AKGL_BITMASK_DEL(x, y) x &= ~(y) #define AKGL_BITMASK_DEL(x, y) x &= ~(y)
#define AKGL_BITMASK_CLEAR(x) x = 0; #define AKGL_BITMASK_CLEAR(x) x = 0;
@@ -61,5 +65,8 @@ void akgl_game_updateFPS();
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath); akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath);
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath); akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath);
void akgl_game_lowfps(void); void akgl_game_lowfps(void);
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_state_lock(void);
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_state_unlock(void);
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_update(akgl_Iterator *opflags);
#endif //_AKGL_GAME_H_ #endif //_AKGL_GAME_H_

View File

@@ -30,6 +30,7 @@ extern akgl_Character HEAP_CHARACTER[AKGL_MAX_HEAP_CHARACTER];
extern akgl_String HEAP_STRING[AKGL_MAX_HEAP_STRING]; extern akgl_String HEAP_STRING[AKGL_MAX_HEAP_STRING];
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_init(); akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_init();
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_init_actor();
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_actor(akgl_Actor **dest); akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_actor(akgl_Actor **dest);
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_sprite(akgl_Sprite **dest); akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_sprite(akgl_Sprite **dest);
akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest); akerr_ErrorContext AKERR_NOIGNORE *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest);

View File

@@ -5,6 +5,8 @@
#include <akerror.h> #include <akerror.h>
#include <akgl/iterator.h>
typedef struct akgl_RenderBackend { typedef struct akgl_RenderBackend {
SDL_Renderer *sdl_renderer; SDL_Renderer *sdl_renderer;
akerr_ErrorContext AKERR_NOIGNORE *(*shutdown)(struct akgl_RenderBackend *self); akerr_ErrorContext AKERR_NOIGNORE *(*shutdown)(struct akgl_RenderBackend *self);
@@ -12,6 +14,7 @@ typedef struct akgl_RenderBackend {
akerr_ErrorContext AKERR_NOIGNORE *(*frame_end)(struct akgl_RenderBackend *self); akerr_ErrorContext AKERR_NOIGNORE *(*frame_end)(struct akgl_RenderBackend *self);
akerr_ErrorContext AKERR_NOIGNORE *(*draw_texture)(struct akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip); akerr_ErrorContext AKERR_NOIGNORE *(*draw_texture)(struct akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip);
akerr_ErrorContext AKERR_NOIGNORE *(*draw_mesh)(struct akgl_RenderBackend *self); akerr_ErrorContext AKERR_NOIGNORE *(*draw_mesh)(struct akgl_RenderBackend *self);
akerr_ErrorContext AKERR_NOIGNORE *(*draw_world)(struct akgl_RenderBackend *self, akgl_Iterator *opflags);
} akgl_RenderBackend; } akgl_RenderBackend;
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_shutdown(akgl_RenderBackend *self); akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_shutdown(akgl_RenderBackend *self);
@@ -19,6 +22,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_start(akgl_RenderBackend
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_end(akgl_RenderBackend *self); akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_end(akgl_RenderBackend *self);
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_texture(akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip); akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_texture(akgl_RenderBackend *self, SDL_Texture *texture, SDL_FRect *src, SDL_FRect *dest, double angle, SDL_FPoint *center, SDL_FlipMode flip);
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_mesh(akgl_RenderBackend *self); akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_mesh(akgl_RenderBackend *self);
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_world(akgl_RenderBackend *self, akgl_Iterator *opflags);
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_init2d(akgl_RenderBackend *self); akerr_ErrorContext AKERR_NOIGNORE *akgl_render_init2d(akgl_RenderBackend *self);

View File

@@ -3,6 +3,7 @@
#include <string.h> #include <string.h>
#include <akerror.h> #include <akerror.h>
#include <akgl/physics.h>
#include <akgl/game.h> #include <akgl/game.h>
#include <akgl/sprite.h> #include <akgl/sprite.h>
#include <akgl/actor.h> #include <akgl/actor.h>
@@ -112,27 +113,13 @@ akerr_ErrorContext *akgl_actor_logic_changeframe(akgl_Actor *obj, akgl_Sprite *c
SUCCEED_RETURN(errctx); SUCCEED_RETURN(errctx);
} }
// raises AKGL_ERR_LOGICINTERRUPT if we don't want the physics object to process us
akerr_ErrorContext *akgl_actor_logic_movement(akgl_Actor *obj, SDL_Time curtime) akerr_ErrorContext *akgl_actor_logic_movement(akgl_Actor *obj, SDL_Time curtime)
{ {
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "Null actor reference"); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "Null actor reference");
if ( obj->parent != NULL ) { // Effectively a NOOP, this is handled by the physics engine now
// Children don't move independently of their parents, they just have an offset // These functions are still present in case the library user wants per-actor behavior
SUCCEED_RETURN(errctx);
} else {
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_LEFT) ) {
obj->x -= obj->basechar->vx;
}
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_RIGHT) ) {
obj->x += obj->basechar->vx;
}
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_UP) ) {
obj->y -= obj->basechar->vy;
}
if ( AKGL_BITMASK_HAS(obj->state, AKGL_ACTOR_STATE_MOVING_DOWN) ) {
obj->y += obj->basechar->vy;
}
}
SUCCEED_RETURN(errctx); SUCCEED_RETURN(errctx);
} }
@@ -145,21 +132,11 @@ akerr_ErrorContext *akgl_actor_update(akgl_Actor *obj)
FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL actor reference"); FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL actor reference");
FAIL_ZERO_RETURN(errctx, obj->basechar, AKERR_NULLPOINTER, "Actor has NULL base character reference"); FAIL_ZERO_RETURN(errctx, obj->basechar, AKERR_NULLPOINTER, "Actor has NULL base character reference");
ATTEMPT { SDL_GetCurrentTime(&curtime);
SDL_GetCurrentTime(&curtime); PASS(errctx, obj->facefunc(obj));
CATCH(errctx, obj->facefunc(obj));
// is it time to apply movement logic?
if ( (curtime - obj->logictimer) >= obj->basechar->movementspeed ) {
CATCH(errctx, obj->movementlogicfunc(obj, curtime));
obj->logictimer = curtime;
}
} CLEANUP {
} PROCESS(errctx) {
} FINISH(errctx, false);
ATTEMPT { ATTEMPT {
CATCH(errctx, akgl_character_sprite_get(obj->basechar, obj->state, &curSprite)); CATCH(errctx, akgl_character_sprite_get(obj->basechar, obj->state, &curSprite));
// is it time to change frames?
if ( ((curtime) - obj->curSpriteFrameTimer) >= curSprite->speed) { if ( ((curtime) - obj->curSpriteFrameTimer) >= curSprite->speed) {
CATCH(errctx, obj->changeframefunc(obj, curSprite, curtime)); CATCH(errctx, obj->changeframefunc(obj, curSprite, curtime));
obj->curSpriteFrameTimer = curtime; obj->curSpriteFrameTimer = curtime;
@@ -167,6 +144,8 @@ akerr_ErrorContext *akgl_actor_update(akgl_Actor *obj)
} CLEANUP { } CLEANUP {
} PROCESS(errctx) { } PROCESS(errctx) {
} HANDLE(errctx, AKERR_KEY) { } HANDLE(errctx, AKERR_KEY) {
// TODO : Why are we passing this error? It could only come from akgl_character_sprite_get
// or changeframefunc, both of which should never return AKERR_KEY...
SUCCEED_RETURN(errctx); SUCCEED_RETURN(errctx);
} FINISH(errctx, true); } FINISH(errctx, true);
@@ -279,39 +258,6 @@ akerr_ErrorContext *akgl_actor_add_child(akgl_Actor *obj, akgl_Actor *child)
FAIL_RETURN(errctx, AKERR_OUTOFBOUNDS, "Parent object has no remaining child slots left"); FAIL_RETURN(errctx, AKERR_OUTOFBOUNDS, "Parent object has no remaining child slots left");
} }
// SDL iterator so we can't return error information here, void only
// this means we don't have anywhere to send exceptions up to, so if we hit an error, we log and exit(1) here
void akgl_registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name)
{
PREPARE_ERROR(errctx);
akgl_Iterator *opflags = (akgl_Iterator *)userdata;
ATTEMPT {
FAIL_ZERO_BREAK(errctx, name, AKERR_NULLPOINTER, "registry_iterate_actor received NULL property name");
FAIL_ZERO_BREAK(errctx, opflags, AKERR_NULLPOINTER, "received NULL iterator flags");
akgl_Actor *obj = (akgl_Actor *)SDL_GetPointerProperty(registry, name, NULL);
FAIL_ZERO_BREAK(errctx, obj, AKERR_KEY, "registry_iterate_actor received property name that was not in the registry");
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_LAYERMASK) ) {
if ( obj->layer != opflags->layerid ) {
break;
}
}
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_UPDATE) ) {
CATCH(errctx, obj->updatefunc(obj));
}
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_TILEMAPSCALE) ) {
CATCH(errctx, akgl_tilemap_scale_actor(&gamemap, obj));
} else {
obj->scale = 1.0;
}
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_RENDER) ) {
CATCH(errctx, obj->renderfunc(obj));
}
} CLEANUP {
} PROCESS(errctx) {
} FINISH_NORETURN(errctx);
}
akerr_ErrorContext AKERR_NOIGNORE *akgl_Actor_cmhf_left_on(akgl_Actor *obj, SDL_Event *event) akerr_ErrorContext AKERR_NOIGNORE *akgl_Actor_cmhf_left_on(akgl_Actor *obj, SDL_Event *event)
{ {
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);

View File

@@ -83,6 +83,13 @@ akerr_ErrorContext *akgl_controller_handle_event(void *appstate, SDL_Event *even
event->key.which == curmap->kbid && event->key.which == curmap->kbid &&
event->key.key == curcontrol->key) event->key.key == curcontrol->key)
); );
if ( event->type == 768 && event->key.which == 11 && event->key.key == 13 ) {
SDL_Log("Event type=%d, keyboard=%d, key=%d", event->type, event->key.which, event->key.key);
SDL_Log("ControlMap[%d].Controls[%d] keyboard=%d, key=%d", i, j, curmap->kbid, curcontrol->key);
SDL_Log("event %d -> control on %d off %d", event->type, curcontrol->event_on, curcontrol->event_off);
SDL_Log("eventButtonComboMatch for controlmap %d id %d = %d",
i, j, eventButtonComboMatch);
}
if ( event->type == curcontrol->event_on && eventButtonComboMatch) { if ( event->type == curcontrol->event_on && eventButtonComboMatch) {
CATCH(errctx, curcontrol->handler_on(curmap->target, event)); CATCH(errctx, curcontrol->handler_on(curmap->target, event));
goto _akgl_controller_handle_event_success; goto _akgl_controller_handle_event_success;

View File

@@ -15,10 +15,12 @@
#include <akgl/registry.h> #include <akgl/registry.h>
#include <akgl/staticstring.h> #include <akgl/staticstring.h>
#include <akgl/iterator.h> #include <akgl/iterator.h>
#include <akgl/physics.h>
#include <akgl/SDL_GameControllerDB.h> #include <akgl/SDL_GameControllerDB.h>
SDL_Window *window = NULL; SDL_Window *window = NULL;
akgl_RenderBackend renderer; akgl_RenderBackend renderer;
akgl_PhysicsBackend physics;
akgl_Frame ball; akgl_Frame ball;
akgl_Frame paddle1; akgl_Frame paddle1;
akgl_Frame paddle2; akgl_Frame paddle2;
@@ -42,28 +44,32 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
int screenheight = 0; int screenheight = 0;
int i = 0; int i = 0;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
ATTEMPT { ATTEMPT {
strncpy((char *)&game.libversion, AKGL_VERSION, 32); strncpy((char *)&game.libversion, AKGL_VERSION, 32);
game.gameStartTime = SDL_GetTicksNS(); game.gameStartTime = SDL_GetTicksNS();
game.lastIterTime = game.gameStartTime; game.lastIterTime = game.gameStartTime;
game.lastFPSTime = game.gameStartTime; game.lastFPSTime = game.gameStartTime;
game.lowfpsfunc = &akgl_game_lowfps; game.lowfpsfunc = &akgl_game_lowfps;
FAIL_ZERO_BREAK(errctx, strlen((char *)&game.name), AKERR_NULLPOINTER, "Must provide game name"); game.statelock = SDL_CreateMutex();
FAIL_ZERO_BREAK(errctx, strlen((char *)&game.version), AKERR_NULLPOINTER, "Must provide game version"); FAIL_ZERO_RETURN(e, game.statelock, AKGL_ERR_SDL, "%s", SDL_GetError());
FAIL_ZERO_BREAK(errctx, strlen((char *)&game.uri), AKERR_NULLPOINTER, "Must provide game uri"); CATCH(e, akgl_game_state_lock());
CATCH(errctx, akgl_heap_init()); FAIL_ZERO_BREAK(e, strlen((char *)&game.name), AKERR_NULLPOINTER, "Must provide game name");
CATCH(errctx, akgl_registry_init_actor()); FAIL_ZERO_BREAK(e, strlen((char *)&game.version), AKERR_NULLPOINTER, "Must provide game version");
CATCH(errctx, akgl_registry_init_sprite()); FAIL_ZERO_BREAK(e, strlen((char *)&game.uri), AKERR_NULLPOINTER, "Must provide game uri");
CATCH(errctx, akgl_registry_init_spritesheet()); CATCH(e, akgl_heap_init());
CATCH(errctx, akgl_registry_init_character()); CATCH(e, akgl_registry_init_actor());
CATCH(errctx, akgl_registry_init_font()); CATCH(e, akgl_registry_init_sprite());
CATCH(errctx, akgl_registry_init_music()); CATCH(e, akgl_registry_init_spritesheet());
CATCH(errctx, akgl_registry_init_properties()); CATCH(e, akgl_registry_init_character());
CATCH(errctx, akgl_registry_init_actor_state_strings()); 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 { } CLEANUP {
} PROCESS(errctx) { //IGNORE(akgl_game_state_unlock());
} FINISH(errctx, true) } PROCESS(e) {
} FINISH(e, true)
SDL_SetAppMetadata(game.name, game.version, game.uri); SDL_SetAppMetadata(game.name, game.version, game.uri);
@@ -72,7 +78,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_init()
} }
FAIL_ZERO_RETURN( FAIL_ZERO_RETURN(
errctx, e,
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD | SDL_INIT_AUDIO), SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD | SDL_INIT_AUDIO),
AKGL_ERR_SDL, AKGL_ERR_SDL,
"Couldn't initialize SDL: %s", "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++ ) { for ( i = 0; i < AKGL_SDL_GAMECONTROLLER_DB_LEN ; i++ ) {
if ( SDL_AddGamepadMapping(SDL_GAMECONTROLLER_DB[i]) == -1 ) { 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( FAIL_ZERO_RETURN(
errctx, e,
MIX_Init(), MIX_Init(),
AKGL_ERR_SDL, AKGL_ERR_SDL,
"Couldn't initialize audio: %s", "Couldn't initialize audio: %s",
SDL_GetError()); SDL_GetError());
akgl_mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, 0); akgl_mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, 0);
FAIL_ZERO_RETURN( FAIL_ZERO_RETURN(
errctx, e,
akgl_mixer, akgl_mixer,
AKGL_ERR_SDL, AKGL_ERR_SDL,
"Unable to create mixer device: %s", "Unable to create mixer device: %s",
SDL_GetError()); SDL_GetError());
FAIL_ZERO_RETURN( FAIL_ZERO_RETURN(
errctx, e,
TTF_Init(), TTF_Init(),
AKGL_ERR_SDL, AKGL_ERR_SDL,
"Couldn't initialize front engine: %s", "Couldn't initialize front engine: %s",
SDL_GetError()); 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() void akgl_game_updateFPS()
@@ -135,119 +163,119 @@ void akgl_game_save_actorname_iterator(void *userdata, SDL_PropertiesID props, c
{ {
FILE *fp = (FILE *)userdata; FILE *fp = (FILE *)userdata;
akgl_Actor *actor = NULL; akgl_Actor *actor = NULL;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(errctx, fp, AKERR_NULLPOINTER, "NULL file pointer"); FAIL_ZERO_BREAK(e, fp, AKERR_NULLPOINTER, "NULL file pointer");
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp)); CATCH(e, aksl_fwrite((char *)name, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp));
actor = SDL_GetPointerProperty(props, name, NULL); 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 { } CLEANUP {
} PROCESS(errctx) { } PROCESS(e) {
} FINISH_NORETURN(errctx); } FINISH_NORETURN(e);
} }
void akgl_game_save_spritename_iterator(void *userdata, SDL_PropertiesID props, const char *name) void akgl_game_save_spritename_iterator(void *userdata, SDL_PropertiesID props, const char *name)
{ {
FILE *fp = (FILE *)userdata; FILE *fp = (FILE *)userdata;
akgl_Sprite *sprite = NULL; akgl_Sprite *sprite = NULL;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
ATTEMPT { 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); sprite = SDL_GetPointerProperty(props, name, NULL);
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp)); CATCH(e, 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(&sprite, 1, sizeof(akgl_Sprite *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(errctx) { } PROCESS(e) {
} FINISH_NORETURN(errctx); } FINISH_NORETURN(e);
} }
void akgl_game_save_spritesheetname_iterator(void *userdata, SDL_PropertiesID props, const char *name) void akgl_game_save_spritesheetname_iterator(void *userdata, SDL_PropertiesID props, const char *name)
{ {
FILE *fp = (FILE *)userdata; FILE *fp = (FILE *)userdata;
akgl_SpriteSheet *spritesheet = NULL; akgl_SpriteSheet *spritesheet = NULL;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
ATTEMPT { 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); spritesheet = SDL_GetPointerProperty(props, name, NULL);
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp)); CATCH(e, 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(&spritesheet, 1, sizeof(akgl_SpriteSheet *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(errctx) { } PROCESS(e) {
} FINISH_NORETURN(errctx); } FINISH_NORETURN(e);
} }
void akgl_game_save_charactername_iterator(void *userdata, SDL_PropertiesID props, const char *name) void akgl_game_save_charactername_iterator(void *userdata, SDL_PropertiesID props, const char *name)
{ {
FILE *fp = (FILE *)userdata; FILE *fp = (FILE *)userdata;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
akgl_Character *character = NULL; akgl_Character *character = NULL;
ATTEMPT { 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); character = SDL_GetPointerProperty(props, name, NULL);
CATCH(errctx, aksl_fwrite((char *)name, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp)); CATCH(e, 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(&character, 1, sizeof(akgl_Character *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(errctx) { } PROCESS(e) {
} FINISH_NORETURN(errctx); } FINISH_NORETURN(e);
} }
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save_actors(FILE *fp) akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save_actors(FILE *fp)
{ {
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
char nullval = 0x00; char nullval = 0x00;
ATTEMPT { 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 // write the actor name pointer table
SDL_EnumerateProperties( SDL_EnumerateProperties(
AKGL_REGISTRY_ACTOR, AKGL_REGISTRY_ACTOR,
&akgl_game_save_actorname_iterator, &akgl_game_save_actorname_iterator,
(void *)fp); (void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_ACTOR_MAX_NAME_LENGTH, fp)); CATCH(e, 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, sizeof(akgl_Actor *), fp));
// write the sprite name pointer table // write the sprite name pointer table
SDL_EnumerateProperties( SDL_EnumerateProperties(
AKGL_REGISTRY_SPRITE, AKGL_REGISTRY_SPRITE,
&akgl_game_save_spritename_iterator, &akgl_game_save_spritename_iterator,
(void *)fp); (void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_MAX_NAME_LENGTH, fp)); CATCH(e, 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, sizeof(akgl_Sprite *), fp));
// write the spritesheet name pointer table // write the spritesheet name pointer table
SDL_EnumerateProperties( SDL_EnumerateProperties(
AKGL_REGISTRY_SPRITESHEET, AKGL_REGISTRY_SPRITESHEET,
&akgl_game_save_spritesheetname_iterator, &akgl_game_save_spritesheetname_iterator,
(void *)fp); (void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH, fp)); CATCH(e, 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, sizeof(akgl_SpriteSheet *), fp));
// write the character name pointer table // write the character name pointer table
SDL_EnumerateProperties( SDL_EnumerateProperties(
AKGL_REGISTRY_CHARACTER, AKGL_REGISTRY_CHARACTER,
&akgl_game_save_charactername_iterator, &akgl_game_save_charactername_iterator,
(void *)fp); (void *)fp);
CATCH(errctx, aksl_fwrite((void *)&nullval, 1, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH, fp)); CATCH(e, 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, sizeof(akgl_Character *), fp));
} CLEANUP { } CLEANUP {
} PROCESS(errctx) { } PROCESS(e) {
} FINISH(errctx, true); } FINISH(e, true);
SUCCEED_RETURN(errctx); SUCCEED_RETURN(e);
} }
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath) akerr_ErrorContext AKERR_NOIGNORE *akgl_game_save(char *fpath)
{ {
FILE *fp = NULL; FILE *fp = NULL;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
ATTEMPT { ATTEMPT {
FAIL_ZERO_BREAK(errctx, fpath, AKERR_NULLPOINTER, "NULL file path"); FAIL_ZERO_BREAK(e, fpath, AKERR_NULLPOINTER, "NULL file path");
CATCH(errctx, aksl_fopen(fpath, "wb", &fp)); CATCH(e, aksl_fopen(fpath, "wb", &fp));
CATCH(errctx, aksl_fwrite(&game, 1, sizeof(akgl_Game), fp)); CATCH(e, aksl_fwrite(&game, 1, sizeof(akgl_Game), fp));
CATCH(errctx, akgl_game_save_actors(fp)); CATCH(e, akgl_game_save_actors(fp));
} PROCESS(errctx) { } PROCESS(e) {
} CLEANUP { } CLEANUP {
if ( fp != NULL ) if ( fp != NULL )
fclose(fp); fclose(fp);
} FINISH(errctx, true); } FINISH(e, true);
SUCCEED_RETURN(errctx); // SUCCEED_NORETURN if in main(). 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) 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]; char objname[namelength];
int retval = 0; int retval = 0;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
while ( 1 ) { while ( 1 ) {
CATCH(errctx, aksl_fread((void *)&objname, 1, namelength, fp)); CATCH(e, aksl_fread((void *)&objname, 1, namelength, fp));
CATCH(errctx, aksl_fread((void *)&ptr, 1, ptrlength, fp)); CATCH(e, aksl_fread((void *)&ptr, 1, ptrlength, fp));
// End of the map // End of the map
if ( ptr == 0x00 && objname[0] == 0x00 ) { if ( ptr == 0x00 && objname[0] == 0x00 ) {
break; 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 // 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. // 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); snprintf((char *)&ptrstring, 32, "%p", ptr);
SDL_SetPointerProperty( SDL_SetPointerProperty(
map, map,
ptrstring, ptrstring,
SDL_GetPointerProperty(registry, objname, NULL)); 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) akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_versioncmp(char *versiontype, char *newversion, char *curversion)
{ {
semver_t current_version = {}; semver_t current_version = {};
semver_t compare_version = {}; semver_t compare_version = {};
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
FAIL_ZERO_RETURN(errctx, versiontype, AKERR_NULLPOINTER, "NULL argument"); FAIL_ZERO_RETURN(e, versiontype, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(errctx, curversion, AKERR_NULLPOINTER, "NULL argument"); FAIL_ZERO_RETURN(e, curversion, AKERR_NULLPOINTER, "NULL argument");
FAIL_ZERO_RETURN(errctx, newversion, AKERR_NULLPOINTER, "NULL argument"); FAIL_ZERO_RETURN(e, newversion, AKERR_NULLPOINTER, "NULL argument");
ATTEMPT { ATTEMPT {
// Check save game library version // Check save game library version
FAIL_NONZERO_BREAK( FAIL_NONZERO_BREAK(
errctx, e,
semver_parse((const char *)curversion, &current_version), semver_parse((const char *)curversion, &current_version),
AKERR_VALUE, AKERR_VALUE,
"Invalid semantic %s version in current game: %s", "Invalid semantic %s version in current game: %s",
versiontype, versiontype,
(char *)curversion); (char *)curversion);
FAIL_NONZERO_BREAK( FAIL_NONZERO_BREAK(
errctx, e,
semver_parse((const char *)newversion, &compare_version), semver_parse((const char *)newversion, &compare_version),
AKERR_VALUE, AKERR_VALUE,
"Invalid semantic %s version in save game: %s", "Invalid semantic %s version in save game: %s",
versiontype, versiontype,
(char *)&newversion); (char *)&newversion);
FAIL_ZERO_BREAK( FAIL_ZERO_BREAK(
errctx, e,
semver_satisfies(compare_version, current_version, "="), semver_satisfies(compare_version, current_version, "="),
AKERR_API, AKERR_API,
"Incompatible save game %s version (%s != %s)", "Incompatible save game %s version (%s != %s)",
@@ -319,9 +347,9 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load_versioncmp(char *versiontype,
} CLEANUP { } CLEANUP {
semver_free(&current_version); semver_free(&current_version);
semver_free(&compare_version); semver_free(&compare_version);
} PROCESS(errctx) { } PROCESS(e) {
} FINISH(errctx, true); } FINISH(e, true);
SUCCEED_RETURN(errctx); SUCCEED_RETURN(e);
} }
akerr_ErrorContext AKERR_NOIGNORE *akgl_game_load(char *fpath) 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; SDL_PropertiesID charactermap;
FILE *fp = NULL; FILE *fp = NULL;
PREPARE_ERROR(errctx); PREPARE_ERROR(e);
FAIL_ZERO_RETURN(errctx, fpath, AKERR_NULLPOINTER, "NULL file path"); FAIL_ZERO_RETURN(e, fpath, AKERR_NULLPOINTER, "NULL file path");
ATTEMPT { ATTEMPT {
CATCH(errctx, aksl_fopen(fpath, "rb", &fp)); CATCH(e, aksl_fopen(fpath, "rb", &fp));
CATCH(errctx, aksl_fread((void *)&savegame, 1, sizeof(akgl_Game), fp)); CATCH(e, aksl_fread((void *)&savegame, 1, sizeof(akgl_Game), fp));
CATCH(errctx, akgl_game_load_versioncmp("library", (char *)&savegame.libversion, (char *)AKGL_VERSION)); CATCH(e, 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, akgl_game_load_versioncmp("game", (char *)&savegame.version, (char *)&game.version));
FAIL_NONZERO_RETURN( FAIL_NONZERO_RETURN(
errctx, e,
strncmp((char *)&savegame.name, (char *)&game.name, 256), strncmp((char *)&savegame.name, (char *)&game.name, 256),
AKERR_API, AKERR_API,
"Savegame is not compatible with this game"); "Savegame is not compatible with this game");
FAIL_NONZERO_RETURN( FAIL_NONZERO_RETURN(
errctx, e,
strncmp((char *)&savegame.uri, (char *)&game.uri, 256), strncmp((char *)&savegame.uri, (char *)&game.uri, 256),
AKERR_API, AKERR_API,
"Savegame is not compatible with this game"); "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)); memcpy((void *)&game, (void *)&savegame, sizeof(akgl_Game));
// Load actor name map // Load actor name map
actormap = SDL_CreateProperties(); 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 // Load sprite name map
spritemap = SDL_CreateProperties(); 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 // Load spritesheet name map
spritesheetmap = SDL_CreateProperties(); 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 // Load character name map
charactermap = SDL_CreateProperties(); 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 // Now that we have all of our pointer maps built, we can load the actual binary objects and reset their pointers
} CLEANUP { } CLEANUP {
if ( fp != NULL ) { if ( fp != NULL ) {
fclose(fp); fclose(fp);
} }
} PROCESS(errctx) { } PROCESS(e) {
} FINISH(errctx, true); } 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);
} }

View File

@@ -20,9 +20,7 @@ akerr_ErrorContext *akgl_heap_init()
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);
int i = 0; int i = 0;
akerr_name_for_status(AKGL_ERR_SDL, "SDL Error"); akerr_name_for_status(AKGL_ERR_SDL, "SDL Error");
for ( i = 0; i < AKGL_MAX_HEAP_ACTOR; i++) { PASS(errctx, akgl_heap_init_actor());
memset(&HEAP_ACTOR[i], 0x00, sizeof(akgl_Actor));
}
for ( i = 0; i < AKGL_MAX_HEAP_SPRITE; i++) { for ( i = 0; i < AKGL_MAX_HEAP_SPRITE; i++) {
memset(&HEAP_SPRITE[i], 0x00, sizeof(akgl_Sprite)); memset(&HEAP_SPRITE[i], 0x00, sizeof(akgl_Sprite));
} }
@@ -38,6 +36,15 @@ akerr_ErrorContext *akgl_heap_init()
SUCCEED_RETURN(errctx); SUCCEED_RETURN(errctx);
} }
akerr_ErrorContext *akgl_heap_init_actor(void)
{
PREPARE_ERROR(e);
for ( int i = 0; i < AKGL_MAX_HEAP_ACTOR; i++) {
memset(&HEAP_ACTOR[i], 0x00, sizeof(akgl_Actor));
}
SUCCEED_RETURN(e);
}
akerr_ErrorContext *akgl_heap_next_actor(akgl_Actor **dest) akerr_ErrorContext *akgl_heap_next_actor(akgl_Actor **dest)
{ {
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);

View File

@@ -39,6 +39,9 @@ akerr_ErrorContext *akgl_registry_init()
akerr_ErrorContext *akgl_registry_init_actor() akerr_ErrorContext *akgl_registry_init_actor()
{ {
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);
if ( AKGL_REGISTRY_ACTOR != NULL ) {
SDL_DestroyProperties(AKGL_REGISTRY_ACTOR);
}
AKGL_REGISTRY_ACTOR = SDL_CreateProperties(); AKGL_REGISTRY_ACTOR = SDL_CreateProperties();
FAIL_ZERO_RETURN(errctx, AKGL_REGISTRY_ACTOR, AKERR_NULLPOINTER, "Error initializing actor registry"); FAIL_ZERO_RETURN(errctx, AKGL_REGISTRY_ACTOR, AKERR_NULLPOINTER, "Error initializing actor registry");
SUCCEED_RETURN(errctx); SUCCEED_RETURN(errctx);

View File

@@ -43,6 +43,7 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_render_init2d(akgl_RenderBackend *self)
self->frame_end = &akgl_render_2d_frame_end; self->frame_end = &akgl_render_2d_frame_end;
self->draw_texture = &akgl_render_2d_draw_texture; self->draw_texture = &akgl_render_2d_draw_texture;
self->draw_mesh = &akgl_render_2d_draw_mesh; self->draw_mesh = &akgl_render_2d_draw_mesh;
self->draw_world = &akgl_render_2d_draw_world;
SUCCEED_RETURN(e); SUCCEED_RETURN(e);
} }
@@ -56,14 +57,17 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_shutdown(akgl_RenderBackend *s
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_start(akgl_RenderBackend *self) akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_start(akgl_RenderBackend *self)
{ {
PREPARE_ERROR(e); PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, self->sdl_renderer, AKERR_NULLPOINTER, "No valid SDL rendering backend");
SDL_SetRenderDrawColor(self->sdl_renderer, 0, 0, 0, 255);
SDL_RenderClear(self->sdl_renderer);
SUCCEED_RETURN(e); SUCCEED_RETURN(e);
} }
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_end(akgl_RenderBackend *self) akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_frame_end(akgl_RenderBackend *self)
{ {
PREPARE_ERROR(e); PREPARE_ERROR(e);
FAIL_ZERO_RETURN(e, renderer.sdl_renderer, AKERR_NULLPOINTER, "No valid SDL rendering backend"); FAIL_ZERO_RETURN(e, self->sdl_renderer, AKERR_NULLPOINTER, "No valid SDL rendering backend");
SDL_RenderPresent(renderer.sdl_renderer); SDL_RenderPresent(self->sdl_renderer);
SUCCEED_RETURN(e); SUCCEED_RETURN(e);
} }
@@ -98,3 +102,35 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_mesh(akgl_RenderBackend *
FAIL_RETURN(e, AKERR_API, "Not implemented"); FAIL_RETURN(e, AKERR_API, "Not implemented");
} }
akerr_ErrorContext AKERR_NOIGNORE *akgl_render_2d_draw_world(akgl_RenderBackend *self, akgl_Iterator *opflags)
{
PREPARE_ERROR(e);
akgl_Iterator defflags;
SDL_Time curTime = SDL_GetTicksNS();
akgl_Actor *actor = NULL;
int j = 0;
FAIL_ZERO_RETURN(e, self, AKERR_NULLPOINTER, "self");
if ( opflags == NULL ) {
opflags = &defflags;
PASS(e, aksl_memset((void *)opflags, 0x00, sizeof(akgl_Iterator)));
}
for ( int i = 0; i < AKGL_TILEMAP_MAX_LAYERS ; i++ ) {
if ( i < gamemap.numlayers ) {
PASS(e, akgl_tilemap_draw((akgl_Tilemap *)&gamemap, &camera, i));
}
for ( int j = 0; j < AKGL_MAX_HEAP_ACTOR ; j++ ) {
actor = &HEAP_ACTOR[j];
if ( actor->refcount == 0 ) {
continue;
}
if ( actor->layer != i ) {
continue;
}
PASS(e, actor->renderfunc(actor));
}
}
SUCCEED_RETURN(e);
}

View File

@@ -24,6 +24,7 @@ akerr_ErrorContext *akgl_get_json_tilemap_property(json_t *obj, char *key, char
json_t *properties = NULL; json_t *properties = NULL;
json_t *property = NULL; json_t *property = NULL;
akgl_String *tmpstr = NULL; akgl_String *tmpstr = NULL;
akgl_String *typestr = NULL;
int i = 0; int i = 0;
// This is not a generic JSON helper. It assumes we are receiving an object with a 'properties' key // This is not a generic JSON helper. It assumes we are receiving an object with a 'properties' key
// inside of it. That key is an array of objects, and each object has a name, type, and value. // inside of it. That key is an array of objects, and each object has a name, type, and value.
@@ -38,9 +39,9 @@ akerr_ErrorContext *akgl_get_json_tilemap_property(json_t *obj, char *key, char
CATCH(errctx, akgl_heap_release_string(tmpstr)); CATCH(errctx, akgl_heap_release_string(tmpstr));
continue; continue;
} }
CATCH(errctx, akgl_get_json_string_value(property, "type", &tmpstr)); CATCH(errctx, akgl_get_json_string_value(property, "type", &typestr));
if ( strcmp(tmpstr->data, type) != 0 ) { if ( strcmp(typestr->data, type) != 0 ) {
FAIL_BREAK(errctx, AKERR_TYPE, "Object property is present but is incorrect type"); FAIL_BREAK(errctx, AKERR_TYPE, "Property %s is present but is incorrect type(expected %s got %s)", key, type, (char *)typestr->data);
} }
*dest = property; *dest = property;
SUCCEED_RETURN(errctx); SUCCEED_RETURN(errctx);
@@ -49,13 +50,15 @@ akerr_ErrorContext *akgl_get_json_tilemap_property(json_t *obj, char *key, char
if ( tmpstr != NULL ) { if ( tmpstr != NULL ) {
IGNORE(akgl_heap_release_string(tmpstr)); IGNORE(akgl_heap_release_string(tmpstr));
} }
if ( typestr != NULL ) {
IGNORE(akgl_heap_release_string(typestr));
}
} PROCESS(errctx) { } PROCESS(errctx) {
} FINISH(errctx, true); } FINISH(errctx, true);
FAIL_RETURN(errctx, AKERR_KEY, "Property not found in properties map"); FAIL_RETURN(errctx, AKERR_KEY, "Property not found in properties map");
} }
akerr_ErrorContext *akgl_get_json_properties_string(json_t *obj, char *key, akgl_String **dest) akerr_ErrorContext *akgl_get_json_properties_string(json_t *obj, char *key, akgl_String **dest)
{ {
PREPARE_ERROR(errctx); PREPARE_ERROR(errctx);
@@ -101,6 +104,20 @@ akerr_ErrorContext *akgl_get_json_properties_number(json_t *obj, char *key, floa
SUCCEED_RETURN(errctx); SUCCEED_RETURN(errctx);
} }
akerr_ErrorContext *akgl_get_json_properties_float(json_t *obj, char *key, float *dest)
{
PREPARE_ERROR(errctx);
json_t *property = NULL;
ATTEMPT {
CATCH(errctx, akgl_get_json_tilemap_property(obj, key, "float", &property));
CATCH(errctx, akgl_get_json_number_value(property, "value", dest));
} CLEANUP {
} PROCESS(errctx) {
} FINISH(errctx, true);
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilemap *dest, int tsidx, akgl_String *dirname) akerr_ErrorContext *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilemap *dest, int tsidx, akgl_String *dirname)
{ {
PREPARE_ERROR(e); PREPARE_ERROR(e);
@@ -302,11 +319,11 @@ akerr_ErrorContext *akgl_tilemap_load_layer_objects(akgl_Tilemap *dest, json_t *
if ( strcmp((char *)curobj->name, "p_foreground") == 0 ) { if ( strcmp((char *)curobj->name, "p_foreground") == 0 ) {
dest->p_foreground_y = curobj->y; dest->p_foreground_y = curobj->y;
CATCH(errctx, akgl_get_json_integer_value((json_t *)layerdatavalue, "height", &dest->p_foreground_h)); CATCH(errctx, akgl_get_json_integer_value((json_t *)layerdatavalue, "height", &dest->p_foreground_h));
CATCH(errctx, akgl_get_json_properties_number((json_t *)layerdatavalue, "scale", &dest->p_foreground_scale)); CATCH(errctx, akgl_get_json_properties_float((json_t *)layerdatavalue, "scale", &dest->p_foreground_scale));
} else if ( strcmp((char *)curobj->name, "p_vanishing") == 0 ) { } else if ( strcmp((char *)curobj->name, "p_vanishing") == 0 ) {
dest->p_vanishing_y = curobj->y; dest->p_vanishing_y = curobj->y;
CATCH(errctx, akgl_get_json_integer_value((json_t *)layerdatavalue, "height", &dest->p_vanishing_h)); CATCH(errctx, akgl_get_json_integer_value((json_t *)layerdatavalue, "height", &dest->p_vanishing_h));
CATCH(errctx, akgl_get_json_properties_number((json_t *)layerdatavalue, "scale", &dest->p_vanishing_scale)); CATCH(errctx, akgl_get_json_properties_float((json_t *)layerdatavalue, "scale", &dest->p_vanishing_scale));
} }
} }