From d7f8dde3dd9ac263ae826dda69243a2c278143c4 Mon Sep 17 00:00:00 2001 From: Piotr Usewicz Date: Tue, 17 Feb 2026 09:41:34 +0100 Subject: [PATCH] Introduce cf_sprite_is_valid `cf_sprite_is_valid` returns a `bool` depending whether the checks confirm the sprite is a valid struct by comparing the ids. --- include/cute_sprite.h | 14 ++++++++++++ src/cute_sprite.cpp | 12 +++++------ src/internal/cute_aseprite_cache_internal.h | 2 -- test/test_sprite.cpp | 24 +++++++++++++++++++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/include/cute_sprite.h b/include/cute_sprite.h index f15e51a36..c73b58b46 100644 --- a/include/cute_sprite.h +++ b/include/cute_sprite.h @@ -24,6 +24,8 @@ extern "C" { #endif // __cplusplus +#define CF_SPRITE_ID_INVALID (~0ULL) + /** * @enum CF_PlayDirection * @category sprite @@ -167,6 +169,16 @@ typedef struct CF_Sprite */ CF_API CF_Sprite CF_CALL cf_sprite_defaults(); +/** + * @function cf_sprite_is_valid + * @category sprite + * @brief Returns true if the sprite has been loaded (either as aseprite or easy sprite). + * @param sprite The sprite. + * @return Returns true if the sprite is valid (loaded), false if it's a default/unloaded sprite. + * @related CF_Sprite cf_sprite_defaults cf_make_sprite cf_make_easy_sprite_from_png + */ +CF_INLINE bool cf_sprite_is_valid(const CF_Sprite* sprite) { return sprite->id != CF_SPRITE_ID_INVALID || sprite->easy_sprite_id != 0; } + /** * @function cf_make_easy_sprite_from_png * @category sprite @@ -785,6 +797,8 @@ CF_INLINE CF_V2 sprite_pivot(const CF_Sprite* sprite) { return cf_sprite_pivot(s CF_INLINE void easy_sprite_update_pixels(CF_Sprite* sprite, const CF_Pixel* pixels) { cf_easy_sprite_update_pixels(sprite, pixels); } CF_INLINE void easy_sprite_unload(CF_Sprite* sprite) { cf_easy_sprite_unload(sprite); } CF_INLINE CF_Sprite make_sprite_from_memory(const char* unique_name, const void* aseprite_data, int size) { return cf_make_sprite_from_memory(unique_name, aseprite_data, size); } +CF_INLINE bool sprite_is_valid(const CF_Sprite* sprite) { return cf_sprite_is_valid(sprite); } +CF_INLINE bool sprite_is_valid(const CF_Sprite& sprite) { return cf_sprite_is_valid(&sprite); } } diff --git a/src/cute_sprite.cpp b/src/cute_sprite.cpp index fa5610993..05cc354d1 100644 --- a/src/cute_sprite.cpp +++ b/src/cute_sprite.cpp @@ -127,7 +127,7 @@ void cf_sprite_unload(const char* aseprite_path) void cf_sprite_reload(CF_Sprite* sprite) { - if (sprite->id == CF_SPRITE_ID_INVALID) return; + if (!cf_sprite_is_valid(sprite)) return; CF_SpriteAsset* asset = cf_sprite_get_asset(sprite->id); if (!asset->ase) return; // External assets can't be reloaded from disk. @@ -206,7 +206,7 @@ static const CF_Animation* s_get_animation(const CF_Sprite* sprite) // Cache _image_id, _pivot, _center_patch from the current animation state. static void s_cache_sprite_frame(CF_Sprite* sprite) { - if (sprite->id == CF_SPRITE_ID_INVALID) return; + if (!cf_sprite_is_valid(sprite)) return; const CF_Animation* anim = s_get_animation(sprite); if (!anim) return; int fi = sprite->frame_index; @@ -223,7 +223,7 @@ static void s_cache_sprite_frame(CF_Sprite* sprite) void cf_sprite_play(CF_Sprite* sprite, const char* animation) { CF_ASSERT(sprite); - if (sprite->id == CF_SPRITE_ID_INVALID) return; + if (!cf_sprite_is_valid(sprite)) return; const char* name = sintern(animation); CF_SpriteAsset* asset = cf_sprite_get_asset(sprite->id); const CF_Animation* anim = map_get(asset->animations, name); @@ -365,7 +365,7 @@ CF_Aabb cf_sprite_get_slice(CF_Sprite* sprite, const char* name) { CF_ASSERT(sprite); CF_Aabb not_found = { 0 }; - if (sprite->id == CF_SPRITE_ID_INVALID) return not_found; + if (!cf_sprite_is_valid(sprite)) return not_found; name = sintern(name); CF_SpriteAsset* asset = cf_sprite_get_asset(sprite->id); @@ -447,7 +447,7 @@ void cf_sprite_update(CF_Sprite* sprite) int cf_sprite_animation_count(const CF_Sprite* sprite) { CF_ASSERT(sprite); - if (sprite->id == CF_SPRITE_ID_INVALID) return 0; + if (!cf_sprite_is_valid(sprite)) return 0; CF_SpriteAsset* asset = cf_sprite_get_asset(sprite->id); return map_size(asset->animations); } @@ -455,7 +455,7 @@ int cf_sprite_animation_count(const CF_Sprite* sprite) const char* cf_sprite_animation_name_at(const CF_Sprite* sprite, int index) { CF_ASSERT(sprite); - if (sprite->id == CF_SPRITE_ID_INVALID) return NULL; + if (!cf_sprite_is_valid(sprite)) return NULL; CF_SpriteAsset* asset = cf_sprite_get_asset(sprite->id); if (index < 0 || index >= map_size(asset->animations)) return NULL; CF_Animation** anim_vals = map_items(asset->animations); diff --git a/src/internal/cute_aseprite_cache_internal.h b/src/internal/cute_aseprite_cache_internal.h index b333089fe..12751c2f8 100644 --- a/src/internal/cute_aseprite_cache_internal.h +++ b/src/internal/cute_aseprite_cache_internal.h @@ -15,8 +15,6 @@ #include -#define CF_SPRITE_ID_INVALID (~0ULL) - CF_Result cf_aseprite_cache_load(const char* aseprite_path, CF_Sprite* sprite_out); CF_Result cf_aseprite_cache_load_from_memory(const char* unique_name, const void* data, int sz, CF_Sprite* sprite_out); void cf_aseprite_cache_unload(const char* aseprite_path); diff --git a/test/test_sprite.cpp b/test/test_sprite.cpp index 81725caca..332cf2ba4 100644 --- a/test/test_sprite.cpp +++ b/test/test_sprite.cpp @@ -45,8 +45,32 @@ TEST_CASE(test_easy_sprite_unload) return true; } +TEST_CASE(test_sprite_is_valid) +{ + // Default (unloaded) sprite is invalid. + CF_Sprite def = cf_sprite_defaults(); + REQUIRE(!cf_sprite_is_valid(&def)); + + // Need app for loading sprites. + CHECK(cf_is_error(cf_make_app(NULL, 0, 0, 0, 0, 0, CF_APP_OPTIONS_HIDDEN_BIT | CF_APP_OPTIONS_NO_AUDIO_BIT | CF_APP_OPTIONS_NO_GFX_BIT, NULL))); + + // Aseprite sprite is valid. + CF_Sprite s = cf_make_demo_sprite(); + REQUIRE(cf_sprite_is_valid(&s)); + + // Easy sprite is valid. + CF_Pixel pixels[1] = {}; + pixels[0].val = 0xFF0000FF; + CF_Sprite easy = cf_make_easy_sprite_from_pixels(pixels, 1, 1); + REQUIRE(cf_sprite_is_valid(&easy)); + + cf_destroy_app(); + return true; +} + TEST_SUITE(test_sprite) { RUN_TEST_CASE(test_make_sprite); RUN_TEST_CASE(test_easy_sprite_unload); + RUN_TEST_CASE(test_sprite_is_valid); }