summaryrefslogtreecommitdiff
path: root/src/util/asset_manager.cc
blob: 387453599fb000429fedb500cf72b5833bd5d743 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 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 <vector> // For potential dynamic allocation for procedural assets
#include <new>    // For placement new
#include <cstdlib> // 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.
}