File: sprite_cache.h

package info (click to toggle)
scummvm 2.9.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 450,580 kB
  • sloc: cpp: 4,299,825; asm: 28,322; python: 12,901; sh: 11,302; java: 9,289; xml: 7,895; perl: 2,639; ansic: 2,465; yacc: 1,670; javascript: 1,020; makefile: 933; lex: 578; awk: 275; objc: 82; sed: 11; php: 1
file content (249 lines) | stat: -rw-r--r-- 10,102 bytes parent folder | download | duplicates (2)
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

//
// Sprite caching system.
//
// SpriteFile handles sprite serialization and streaming.
// SpriteCache provides bitmaps by demand; it uses SpriteFile to load sprites
// and does MRU (most-recent-use) caching.
//
// TODO: store sprite data in a specialized container type that is optimized
// for having most keys allocated in large continious sequences by default.
//
// Only for the reference: one of the ideas is for container to have a table
// of arrays of fixed size internally. When getting an item the hash would be
// first divided on array size to find the array the item resides in, then the
// item is taken from item from slot index = (hash - arrsize * arrindex).
// TODO: find out if there is already a hash table kind that follows similar
// principle.
//
//=============================================================================

#ifndef AGS_SHARED_AC_SPRITE_CACHE_H
#define AGS_SHARED_AC_SPRITE_CACHE_H

#include "common/std/memory.h"
#include "common/std/vector.h"
#include "common/std/list.h"
#include "ags/shared/ac/sprite_file.h"
#include "ags/shared/core/platform.h"
#include "ags/shared/gfx/bitmap.h"
#include "ags/shared/util/error.h"
#include "ags/shared/util/geometry.h"

namespace AGS3 {

namespace AGS {
namespace Shared {
class String;
class Stream;
class Bitmap;
} // namespace AGS3
} // namespace AGS

using namespace AGS; // FIXME later
typedef AGS::Shared::HError HAGSError;

struct SpriteInfo;

// Max size of the sprite cache, in bytes
#if AGS_PLATFORM_OS_ANDROID || AGS_PLATFORM_OS_IOS
#define DEFAULTCACHESIZE_KB (32 * 1024)
#else
#define DEFAULTCACHESIZE_KB (128 * 1024)
#endif

struct SpriteInfo;

namespace AGS {
namespace Shared {

class SpriteCache {
public:
	static const sprkey_t MIN_SPRITE_INDEX = 1; // 0 is reserved for "empty sprite"
	static const sprkey_t MAX_SPRITE_INDEX = INT32_MAX - 1;
	static const size_t   MAX_SPRITE_SLOTS = INT32_MAX;

	typedef Size (*PfnAdjustSpriteSize)(const Size &size, const uint32_t sprite_flags);
	typedef Bitmap *(*PfnInitSprite)(sprkey_t index, Bitmap *image, uint32_t &sprite_flags);
	typedef void (*PfnPostInitSprite)(sprkey_t index);
	typedef void (*PfnPrewriteSprite)(Bitmap *image);

	struct Callbacks {
		PfnAdjustSpriteSize AdjustSize;
		PfnInitSprite InitSprite;
		PfnPostInitSprite PostInitSprite;
		PfnPrewriteSprite PrewriteSprite;
	};

	SpriteCache(std::vector<SpriteInfo> &sprInfos, const Callbacks &callbacks);
	~SpriteCache() = default;

	// Loads sprite reference information and inits sprite stream
	HError      InitFile(const String &filename, const String &sprindex_filename);
	// Saves current cache contents to the file
	int         SaveToFile(const String &filename, int store_flags, SpriteCompression compress, SpriteFileIndex &index);
	// Closes an active sprite file stream
	void        DetachFile();

	inline int GetStoreFlags() const {
		return _file.GetStoreFlags();
	}
	inline SpriteCompression GetSpriteCompression() const {
		return _file.GetSpriteCompression();
	}

	// Tells if there is a sprite registered for the given index;
	// this includes sprites that were explicitly assigned but failed to init and were remapped
	bool        DoesSpriteExist(sprkey_t index) const;
	// Returns sprite's resolution; or empty Size if sprite does not exist
	Size		GetSpriteResolution(sprkey_t index) const;
	// Makes sure sprite cache has allocated slots for all sprites up to the given inclusive limit;
	// returns requested index on success, or -1 on failure.
	sprkey_t    EnlargeTo(sprkey_t topmost);
	// Finds a free slot index, if all slots are occupied enlarges sprite bank; returns index
	sprkey_t    GetFreeIndex();
	// Returns current size of the cache, in bytes; this includes locked size too!
	size_t      GetCacheSize() const;
	// Gets the total size of the locked sprites, in bytes
	size_t      GetLockedSize() const;
	// Returns maximal size limit of the cache, in bytes; this includes locked size too!
	size_t      GetMaxCacheSize() const;
	// Returns number of sprite slots in the bank (this includes both actual sprites and free slots)
	size_t      GetSpriteSlotCount() const;
	// Tells if the sprite storage still has unoccupied slots to put new sprites in
	bool		HasFreeSlots() const;
	// Tells if the given slot is reserved for the asset sprite, that is a "static"
	// sprite cached from the game assets
	bool		IsAssetSprite(sprkey_t index) const;
	// Loads sprite using SpriteFile if such index is known,
	// frees the space if cache size reaches the limit
	void        PrecacheSprite(sprkey_t index);
	// Locks sprite, preventing it from getting removed by the normal cache limit.
	// If this is a registered sprite from the game assets, then loads it first.
	// If this is a sprite with SPRCACHEFLAG_EXTERNAL flag, then does nothing,
	// as these are always "locked".
	// If such sprite does not exist, then fails silently.
	void        LockSprite(sprkey_t index);
	// Unlocks sprite, putting it back into the cache logic,
	// where it counts towards normal limit may be deleted to free space.
	// NOTE: sprites with SPRCACHEFLAG_EXTERNAL flag cannot be unlocked,
	// only explicitly removed.
	// If such sprite was not present in memory, then fails silently.
	void        UnlockSprite(sprkey_t index);
	// Unregisters sprite from the bank and returns the bitmap
	Bitmap		*RemoveSprite(sprkey_t index);
	// Deletes particular sprite, marks slot as unused
	void		DisposeSprite(sprkey_t index);
	// Deletes all loaded asset (non-locked, non-external) images from the cache;
	// this keeps all the auxiliary sprite information intact
	void        DisposeAllCached();
	// Deletes all data and resets cache to the clear state
	void        Reset();
	// Assigns new sprite for the given index; this sprite won't be auto disposed.
	// *Deletes* the previous sprite if one was found at the same index.
	// "flags" are SPF_* constants that define sprite's behavior in game.
	bool        SetSprite(sprkey_t index, std::unique_ptr<Bitmap> image, int flags = 0);
	// Assigns new dummy for the given index, silently remapping it to placeholder;
	// optionally marks it as an asset placeholder.
	// *Deletes* the previous sprite if one was found at the same index.
	void        SetEmptySprite(sprkey_t index, bool as_asset);
	// Sets max cache size in bytes
	void        SetMaxCacheSize(size_t size);

	// Loads (if it's not in cache yet) and returns bitmap by the sprite index
	Bitmap *operator[](sprkey_t index);

private:
	// Load sprite from game resource
	size_t      LoadSprite(sprkey_t index, bool lock = false);
	// Remap the given index to the placeholder
	void        RemapSpriteToPlaceholder(sprkey_t index);
	// Delete the oldest (least recently used) image in cache
	void        DisposeOldest();
	// Keep disposing oldest elements until cache has at least the given free space
	void        FreeMem(size_t space);
	// Initialize the empty sprite slot
	void 		InitNullSprite(sprkey_t index);
	//
    // Dummy no-op variants for callbacks
    //
	static Size   DummyAdjustSize(const Size &size, const uint32_t) { return size; }
	static Bitmap *DummyInitSprite(sprkey_t, Bitmap *image, uint32_t &) { return image; }
	static void   DummyPostInitSprite(sprkey_t) { /* do nothing */ }
	static void   DummyPrewriteSprite(Bitmap *) { /* do nothing */ }

	// Information required for the sprite streaming
	struct SpriteData {
		size_t	 Size  = 0;			   // to track cache size, 0 = means don't track
		uint32_t Flags = 0;			   // SPRCACHEFLAG* flags
		std::unique_ptr<Bitmap> Image; // actual bitmap

		// MRU list reference
		std::list<sprkey_t>::iterator MruIt;

		SpriteData() = default;
		SpriteData(SpriteData &&other) = default;
		SpriteData(Bitmap *image, size_t size, uint32_t flags) : Size(size), Flags(flags), Image(image) {}

		SpriteData &operator=(SpriteData &&other) = default;

		// Tells if this slot has a valid sprite assigned (not empty slot)
		bool IsValid() const { return Flags != 0u; }
		// Tells if there actually is a registered sprite in this slot
		bool DoesSpriteExist() const;
		// Tells if there's a game resource corresponding to this slot
		bool IsAssetSprite() const;
		// Tells if a sprite failed to load from assets, and should not be used
		bool IsError() const;
		// Tells if sprite was added externally, not loaded from game resources
		bool IsExternalSprite() const;
		// Tells if sprite is locked and should not be disposed by cache logic
		bool IsLocked() const;
	};

	// Provided map of sprite infos, to fill in loaded sprite properties
	std::vector<SpriteInfo> &_sprInfos;
	// Array of sprite references
	std::vector<SpriteData> _spriteData;
	// Placeholder sprite, returned from operator[] for a non-existing sprite
	std::unique_ptr<Bitmap> _placeholder;

	Callbacks _callbacks;
	SpriteFile _file;

	size_t _maxCacheSize;  // cache size limit
	size_t _lockedSize;    // size in bytes of currently locked images
	size_t _cacheSize;     // size in bytes of currently cached images

	// MRU list: the way to track which sprites were used recently.
	// When clearing up space for new sprites, cache first deletes the sprites
	// that were last time used long ago.
	std::list<sprkey_t> _mru;

};

} // namespace Shared
} // namespace AGS
} // namespace AGS3

#endif