Files
libakgl/src/heap.c

195 lines
5.6 KiB
C
Raw Normal View History

#include <stdlib.h>
#include <akerror.h>
#include <sdl3game/game.h>
#include <sdl3game/sprite.h>
#include <sdl3game/heap.h>
#include <sdl3game/registry.h>
#include <sdl3game/staticstring.h>
#include <sdl3game/iterator.h>
#include <sdl3game/error.h>
akgl_Actor HEAP_ACTOR[AKGL_MAX_HEAP_ACTOR];
akgl_Sprite HEAP_SPRITE[AKGL_MAX_HEAP_SPRITE];
akgl_SpriteSheet HEAP_SPRITESHEET[AKGL_MAX_HEAP_SPRITESHEET];
akgl_Character HEAP_CHARACTER[AKGL_MAX_HEAP_CHARACTER];
akgl_String HEAP_STRING[AKGL_MAX_HEAP_STRING];
akerr_ErrorContext *akgl_heap_init()
{
PREPARE_ERROR(errctx);
int i = 0;
akerr_name_for_status(AKGL_ERR_SDL, "SDL Error");
for ( i = 0; i < AKGL_MAX_HEAP_ACTOR; i++) {
memset(&HEAP_ACTOR[i], 0x00, sizeof(akgl_Actor));
}
for ( i = 0; i < AKGL_MAX_HEAP_SPRITE; i++) {
memset(&HEAP_SPRITE[i], 0x00, sizeof(akgl_Sprite));
}
for ( i = 0; i < AKGL_MAX_HEAP_SPRITESHEET; i++) {
memset(&HEAP_SPRITESHEET[i], 0x00, sizeof(akgl_SpriteSheet));
}
for ( i = 0; i < AKGL_MAX_HEAP_CHARACTER; i++) {
memset(&HEAP_CHARACTER[i], 0x00, sizeof(akgl_Character));
}
for ( i = 0; i < AKGL_MAX_HEAP_STRING; i++) {
memset(&HEAP_STRING[i], 0x00, sizeof(akgl_String));
}
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_heap_next_actor(akgl_Actor **dest)
{
PREPARE_ERROR(errctx);
for (int i = 0; i < AKGL_MAX_HEAP_ACTOR; i++ ) {
if ( HEAP_ACTOR[i].refcount != 0 ) {
continue;
}
*dest = &HEAP_ACTOR[i];
SUCCEED_RETURN(errctx);
}
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused actor on the heap");
}
akerr_ErrorContext *akgl_heap_next_sprite(akgl_Sprite **dest)
{
PREPARE_ERROR(errctx);
for (int i = 0; i < AKGL_MAX_HEAP_SPRITE; i++ ) {
if ( HEAP_SPRITE[i].refcount != 0 ) {
continue;
}
*dest = &HEAP_SPRITE[i];
SUCCEED_RETURN(errctx);
}
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused sprite on the heap");
}
akerr_ErrorContext *akgl_heap_next_spritesheet(akgl_SpriteSheet **dest)
{
PREPARE_ERROR(errctx);
for (int i = 0; i < AKGL_MAX_HEAP_SPRITESHEET; i++ ) {
if ( HEAP_SPRITESHEET[i].refcount != 0 ) {
continue;
}
*dest = &HEAP_SPRITESHEET[i];
SUCCEED_RETURN(errctx);
}
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused spritesheet on the heap");
}
akerr_ErrorContext *akgl_heap_next_character(akgl_Character **dest)
{
PREPARE_ERROR(errctx);
for (int i = 0; i < AKGL_MAX_HEAP_CHARACTER; i++ ) {
if ( HEAP_CHARACTER[i].refcount != 0 ) {
continue;
}
*dest = &HEAP_CHARACTER[i];
SUCCEED_RETURN(errctx);
}
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused character on the heap");
}
akerr_ErrorContext *akgl_heap_next_string(akgl_String **dest)
{
PREPARE_ERROR(errctx);
for (int i = 0; i < AKGL_MAX_HEAP_STRING; i++ ) {
if ( HEAP_STRING[i].refcount != 0 ) {
continue;
}
*dest = &HEAP_STRING[i];
SUCCEED_RETURN(errctx);
}
FAIL_RETURN(errctx, AKERR_HEAP, "Unable to find unused string on the heap");
}
akerr_ErrorContext *akgl_heap_release_actor(akgl_Actor *ptr)
{
int i = 0;
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, ptr, AKERR_NULLPOINTER, "NULL actor reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
for ( i = 0; i < AKGL_ACTOR_MAX_CHILDREN; i++ ) {
if ( ptr->children[i] != NULL ) {
CATCH_AND_RETURN(errctx, akgl_heap_release_actor(ptr->children[i]));
}
}
if ( ptr->basechar != NULL ) {
CATCH_AND_RETURN(errctx, akgl_heap_release_character(ptr->basechar));
}
memset(ptr, 0x00, sizeof(akgl_Actor));
SDL_ClearProperty(AKGL_REGISTRY_ACTOR, (char *)&ptr->name);
}
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_heap_release_character(akgl_Character *basechar)
{
PREPARE_ERROR(errctx);
akgl_Iterator opflags;
FAIL_ZERO_RETURN(errctx, basechar, AKERR_NULLPOINTER, "NULL character reference");
AKGL_BITMASK_CLEAR(opflags.flags);
AKGL_BITMASK_ADD(opflags.flags, AKGL_ITERATOR_OP_RELEASE);
if ( basechar->refcount > 0 ) {
basechar->refcount -= 1;
}
if ( basechar->refcount == 0 ) {
SDL_EnumerateProperties(basechar->state_sprites, &akgl_character_state_sprites_iterate, (void *)&opflags);
SDL_ClearProperty(AKGL_REGISTRY_CHARACTER, (char *)&basechar->name);
}
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_heap_release_sprite(akgl_Sprite *ptr)
{
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, ptr, AKERR_NULLPOINTER, "Received NULL sprite reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
ATTEMPT {
CATCH(errctx, akgl_heap_release_spritesheet(ptr->sheet));
} CLEANUP {
SDL_ClearProperty(AKGL_REGISTRY_SPRITE, (char *)&ptr->name);
} PROCESS(errctx) {
} FINISH(errctx, true);
}
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_heap_release_spritesheet(akgl_SpriteSheet *ptr)
{
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, ptr, AKERR_NULLPOINTER, "Received NULL spritesheet reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
// TODO : If we go threaded, make sure this is only happening on the main thread
SDL_ClearProperty(AKGL_AKGL_REGISTRY_SPRITESHEET, (char *)&ptr->name);
if ( ptr-> texture != NULL )
SDL_DestroyTexture(ptr->texture);
ptr->texture = NULL;
}
SUCCEED_RETURN(errctx);
}
akerr_ErrorContext *akgl_heap_release_string(akgl_String *ptr)
{
PREPARE_ERROR(errctx);
FAIL_ZERO_RETURN(errctx, ptr, AKERR_NULLPOINTER, "Received NULL string reference");
if ( ptr->refcount > 0 ) {
ptr->refcount -= 1;
}
if ( ptr->refcount == 0 ) {
memset(&ptr->data, 0x00, AKGL_MAX_STRING_LENGTH);
}
SUCCEED_RETURN(errctx);
}