// This file is part of the 64k demo project. // It implements the generic asset retrieval logic with runtime caching. #include "util/asset_manager.h" #if defined(USE_TEST_ASSETS) #include "generated/test_assets.h" #else #include "generated/assets.h" #endif /* defined(USE_TEST_ASSETS) */ #include // For potential dynamic allocation for procedural assets #include // For placement new #include // For free // These are defined in the generated assets_data.cc #if defined(USE_TEST_ASSETS) extern const AssetRecord g_assets[]; extern const size_t g_assets_count; #else extern const AssetRecord g_assets[]; extern const size_t g_assets_count; #endif // Array-based cache for assets. // Initialized to all zeros (nullptr data, 0 size, false is_procedural) // The size is derived from the generated ASSET_LAST_ID enum value. static AssetRecord g_asset_cache[(size_t)AssetId::ASSET_LAST_ID] = {}; const uint8_t* GetAsset(AssetId asset_id, size_t* out_size) { uint16_t index = (uint16_t)asset_id; // Assert that ASSET_LAST_ID is not used for retrieval. // This ensures the size of the cache is correctly used and not accessed out of bounds. // If this assert fails, it means assets.txt has an ID larger than expected // or ASSET_LAST_ID is not correctly generated/updated. // This is a design decision: ASSET_LAST_ID is purely for sizing and range checking, // not for a valid asset retrieval itself. if (index >= (uint16_t)AssetId::ASSET_LAST_ID) { if (out_size) *out_size = 0; return nullptr; // Invalid asset_id } // Check cache first if (g_asset_cache[index].data != nullptr) { if (out_size) *out_size = g_asset_cache[index].size; return g_asset_cache[index].data; } // Not in cache, retrieve from static data (packed in binary) if (index >= g_assets_count) { if (out_size) *out_size = 0; return nullptr; // This asset is not in the static packed data either. } // Store static record in cache for future use g_asset_cache[index] = g_assets[index]; g_asset_cache[index].is_procedural = false; if (out_size) *out_size = g_asset_cache[index].size; return g_asset_cache[index].data; } void DropAsset(AssetId asset_id, const uint8_t* asset) { uint16_t index = (uint16_t)asset_id; if (index >= (uint16_t)AssetId::ASSET_LAST_ID) { return; // Invalid asset_id } // Only free memory for procedural assets. if (g_asset_cache[index].is_procedural && g_asset_cache[index].data == asset) { // In a more complex scenario, we might track ref counts. // For this demo, we assume a single owner for dynamically allocated assets. delete[] g_asset_cache[index].data; // Assuming `new uint8_t[]` was used for procedural g_asset_cache[index].data = nullptr; g_asset_cache[index].size = 0; g_asset_cache[index].is_procedural = false; } // For static assets, no dynamic memory to free. }