ScummVM API documentation
sprite_cache.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 //
23 // Sprite caching system.
24 //
25 // SpriteFile handles sprite serialization and streaming.
26 // SpriteCache provides bitmaps by demand; it uses SpriteFile to load sprites
27 // and does MRU (most-recent-use) caching.
28 //
29 // TODO: store sprite data in a specialized container type that is optimized
30 // for having most keys allocated in large continious sequences by default.
31 //
32 // Only for the reference: one of the ideas is for container to have a table
33 // of arrays of fixed size internally. When getting an item the hash would be
34 // first divided on array size to find the array the item resides in, then the
35 // item is taken from item from slot index = (hash - arrsize * arrindex).
36 // TODO: find out if there is already a hash table kind that follows similar
37 // principle.
38 //
39 //=============================================================================
40 
41 #ifndef AGS_SHARED_AC_SPRITE_CACHE_H
42 #define AGS_SHARED_AC_SPRITE_CACHE_H
43 
44 #include "common/std/memory.h"
45 #include "common/std/vector.h"
46 #include "common/std/list.h"
47 #include "ags/shared/ac/sprite_file.h"
48 #include "ags/shared/core/platform.h"
49 #include "ags/shared/gfx/bitmap.h"
50 #include "ags/shared/util/error.h"
51 #include "ags/shared/util/geometry.h"
52 
53 namespace AGS3 {
54 
55 namespace AGS {
56 namespace Shared {
57 class String;
58 class Stream;
59 class Bitmap;
60 } // namespace AGS3
61 } // namespace AGS
62 
63 using namespace AGS; // FIXME later
64 typedef AGS::Shared::HError HAGSError;
65 
66 struct SpriteInfo;
67 
68 // Max size of the sprite cache, in bytes
69 #if AGS_PLATFORM_OS_ANDROID || AGS_PLATFORM_OS_IOS
70 #define DEFAULTCACHESIZE_KB (32 * 1024)
71 #else
72 #define DEFAULTCACHESIZE_KB (128 * 1024)
73 #endif
74 
75 struct SpriteInfo;
76 
77 namespace AGS {
78 namespace Shared {
79 
80 class SpriteCache {
81 public:
82  static const sprkey_t MIN_SPRITE_INDEX = 1; // 0 is reserved for "empty sprite"
83  static const sprkey_t MAX_SPRITE_INDEX = INT32_MAX - 1;
84  static const size_t MAX_SPRITE_SLOTS = INT32_MAX;
85 
86  typedef Size (*PfnAdjustSpriteSize)(const Size &size, const uint32_t sprite_flags);
87  typedef Bitmap *(*PfnInitSprite)(sprkey_t index, Bitmap *image, uint32_t &sprite_flags);
88  typedef void (*PfnPostInitSprite)(sprkey_t index);
89  typedef void (*PfnPrewriteSprite)(Bitmap *image);
90 
91  struct Callbacks {
92  PfnAdjustSpriteSize AdjustSize;
93  PfnInitSprite InitSprite;
94  PfnPostInitSprite PostInitSprite;
95  PfnPrewriteSprite PrewriteSprite;
96  };
97 
98  SpriteCache(std::vector<SpriteInfo> &sprInfos, const Callbacks &callbacks);
99  ~SpriteCache() = default;
100 
101  // Loads sprite reference information and inits sprite stream
102  HError InitFile(const String &filename, const String &sprindex_filename);
103  // Saves current cache contents to the file
104  int SaveToFile(const String &filename, int store_flags, SpriteCompression compress, SpriteFileIndex &index);
105  // Closes an active sprite file stream
106  void DetachFile();
107 
108  inline int GetStoreFlags() const {
109  return _file.GetStoreFlags();
110  }
111  inline SpriteCompression GetSpriteCompression() const {
112  return _file.GetSpriteCompression();
113  }
114 
115  // Tells if there is a sprite registered for the given index;
116  // this includes sprites that were explicitly assigned but failed to init and were remapped
117  bool DoesSpriteExist(sprkey_t index) const;
118  // Returns sprite's resolution; or empty Size if sprite does not exist
119  Size GetSpriteResolution(sprkey_t index) const;
120  // Makes sure sprite cache has allocated slots for all sprites up to the given inclusive limit;
121  // returns requested index on success, or -1 on failure.
122  sprkey_t EnlargeTo(sprkey_t topmost);
123  // Finds a free slot index, if all slots are occupied enlarges sprite bank; returns index
124  sprkey_t GetFreeIndex();
125  // Returns current size of the cache, in bytes; this includes locked size too!
126  size_t GetCacheSize() const;
127  // Gets the total size of the locked sprites, in bytes
128  size_t GetLockedSize() const;
129  // Returns maximal size limit of the cache, in bytes; this includes locked size too!
130  size_t GetMaxCacheSize() const;
131  // Returns number of sprite slots in the bank (this includes both actual sprites and free slots)
132  size_t GetSpriteSlotCount() const;
133  // Tells if the sprite storage still has unoccupied slots to put new sprites in
134  bool HasFreeSlots() const;
135  // Tells if the given slot is reserved for the asset sprite, that is a "static"
136  // sprite cached from the game assets
137  bool IsAssetSprite(sprkey_t index) const;
138  // Loads sprite using SpriteFile if such index is known,
139  // frees the space if cache size reaches the limit
140  void PrecacheSprite(sprkey_t index);
141  // Locks sprite, preventing it from getting removed by the normal cache limit.
142  // If this is a registered sprite from the game assets, then loads it first.
143  // If this is a sprite with SPRCACHEFLAG_EXTERNAL flag, then does nothing,
144  // as these are always "locked".
145  // If such sprite does not exist, then fails silently.
146  void LockSprite(sprkey_t index);
147  // Unlocks sprite, putting it back into the cache logic,
148  // where it counts towards normal limit may be deleted to free space.
149  // NOTE: sprites with SPRCACHEFLAG_EXTERNAL flag cannot be unlocked,
150  // only explicitly removed.
151  // If such sprite was not present in memory, then fails silently.
152  void UnlockSprite(sprkey_t index);
153  // Unregisters sprite from the bank and returns the bitmap
154  Bitmap *RemoveSprite(sprkey_t index);
155  // Deletes particular sprite, marks slot as unused
156  void DeleteSprite(sprkey_t index);
157  // Deletes a loaded asset image (non-external) from memory, ignoring its
158  // locked status; this keeps an auxiliary sprite information intact,
159  // so that the same sprite can be cached back later.
160  void DisposeCached(sprkey_t index);
161  // Deletes all free cached asset images (non-locked, non-external)
162  // from memory; this keeps all the auxiliary sprite information intact,
163  // so that the same sprite(s) can be cached back later.
164  void DisposeAllFreeCached();
165  // Deletes all data and resets cache to the clear state
166  void Reset();
167  // Assigns new sprite for the given index; this sprite won't be auto disposed.
168  // *Deletes* the previous sprite if one was found at the same index.
169  // "flags" are SPF_* constants that define sprite's behavior in game.
170  bool SetSprite(sprkey_t index, std::unique_ptr<Bitmap> image, int flags = 0);
171  // Assigns new dummy for the given index, silently remapping it to placeholder;
172  // optionally marks it as an asset placeholder.
173  // *Deletes* the previous sprite if one was found at the same index.
174  void SetEmptySprite(sprkey_t index, bool as_asset);
175  // Sets max cache size in bytes
176  void SetMaxCacheSize(size_t size);
177 
178  // Loads (if it's not in cache yet) and returns bitmap by the sprite index
179  Bitmap *operator[](sprkey_t index);
180 
181 private:
182  // Load sprite from game resource
183  size_t LoadSprite(sprkey_t index, bool lock = false);
184  // Remap the given index to the placeholder
185  void RemapSpriteToPlaceholder(sprkey_t index);
186  // Delete the oldest (least recently used) image in cache
187  void DisposeOldest();
188  // Keep disposing oldest elements until cache has at least the given free space
189  void FreeMem(size_t space);
190  // Initialize the empty sprite slot
191  void InitNullSprite(sprkey_t index);
192  //
193  // Dummy no-op variants for callbacks
194  //
195  static Size DummyAdjustSize(const Size &size, const uint32_t) { return size; }
196  static Bitmap *DummyInitSprite(sprkey_t, Bitmap *image, uint32_t &) { return image; }
197  static void DummyPostInitSprite(sprkey_t) { /* do nothing */ }
198  static void DummyPrewriteSprite(Bitmap *) { /* do nothing */ }
199 
200  // Information required for the sprite streaming
201  struct SpriteData {
202  size_t Size = 0; // to track cache size, 0 = means don't track
203  uint32_t Flags = 0; // SPRCACHEFLAG* flags
204  std::unique_ptr<Bitmap> Image; // actual bitmap
205 
206  // MRU list reference
208 
209  SpriteData() = default;
210  SpriteData(SpriteData &&other) = default;
211  SpriteData(Bitmap *image, size_t size, uint32_t flags) : Size(size), Flags(flags), Image(image) {}
212 
213  SpriteData &operator=(SpriteData &&other) = default;
214 
215  // Tells if this slot has a valid sprite assigned (not empty slot)
216  bool IsValid() const { return Flags != 0u; }
217  // Tells if there actually is a registered sprite in this slot
218  bool DoesSpriteExist() const;
219  // Tells if there's a game resource corresponding to this slot
220  bool IsAssetSprite() const;
221  // Tells if a sprite failed to load from assets, and should not be used
222  bool IsError() const;
223  // Tells if sprite was added externally, not loaded from game resources
224  bool IsExternalSprite() const;
225  // Tells if sprite is locked and should not be disposed by cache logic
226  bool IsLocked() const;
227  };
228 
229  // Provided map of sprite infos, to fill in loaded sprite properties
230  std::vector<SpriteInfo> &_sprInfos;
231  // Array of sprite references
232  std::vector<SpriteData> _spriteData;
233  // Placeholder sprite, returned from operator[] for a non-existing sprite
234  std::unique_ptr<Bitmap> _placeholder;
235 
236  Callbacks _callbacks;
237  SpriteFile _file;
238 
239  size_t _maxCacheSize; // cache size limit
240  size_t _lockedSize; // size in bytes of currently locked images
241  size_t _cacheSize; // size in bytes of currently cached images
242 
243  // MRU list: the way to track which sprites were used recently.
244  // When clearing up space for new sprites, cache first deletes the sprites
245  // that were last time used long ago.
246  std::list<sprkey_t> _mru;
247 
248 };
249 
250 } // namespace Shared
251 } // namespace AGS
252 } // namespace AGS3
253 
254 #endif
Definition: achievements_tables.h:27
Definition: vector.h:39
Definition: allegro_bitmap.h:44
Definition: sprite_file.h:127
Definition: list.h:39
Definition: sprite_cache.h:80
Definition: ptr.h:572
Definition: sprite_file.h:94
Definition: sprite_cache.h:91
Definition: string.h:62
Definition: geometry.h:148
Definition: movie_decoder.h:32
Definition: error.h:110
Definition: ags.h:40