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
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (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, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #ifndef GNAP_RESOURCE_H
24 #define GNAP_RESOURCE_H
25 
26 #include "common/array.h"
27 #include "common/events.h"
28 #include "common/file.h"
29 #include "common/memstream.h"
30 #include "common/str.h"
31 #include "common/stream.h"
32 #include "common/substream.h"
33 #include "common/system.h"
34 
35 #include "graphics/surface.h"
36 
37 #include "gnap/datarchive.h"
38 
39 namespace Gnap {
40 
41 enum {
42 	kResTypeSprite		= 0,
43 	kResTypeBitmap		= 1,
44 	kResTypeSound		= 2,
45 	kResTypeSequence	= 3
46 };
47 
48 struct SequenceFrame {
49 	int16 _duration;
50 	bool _isScaled;
51 	Common::Rect _rect;
52 	int32 _spriteId;
53 	int32 _soundId;
54 	void loadFromStream(Common::MemoryReadStream &stream);
55 };
56 
57 struct SequenceAnimation {
58 	int32 _additionalDelay;
59 	int16 _framesCount;
60 	int16 _maxTotalDuration;
61 	SequenceFrame *frames;
62 
SequenceAnimationSequenceAnimation63 	SequenceAnimation() : frames(nullptr), _additionalDelay(0), _framesCount(0), _maxTotalDuration(0) {}
~SequenceAnimationSequenceAnimation64 	~SequenceAnimation() { delete[] frames; }
65 	void loadFromStream(Common::MemoryReadStream &stream);
66 };
67 
68 class SequenceResource {
69 public:
70 	SequenceResource(byte *data, uint32 size);
71 	~SequenceResource();
72 public:
73 	int32 _sequenceId;
74 	int32 _defaultId;
75 	int32 _sequenceId2;
76 	uint32 _defaultId2;
77 	uint32 _flags;
78 	int32 _totalDuration;
79 	int16 _xOffs;
80 	int16 _yOffs;
81 	int32 _animationsCount;
82 	SequenceAnimation *_animations;
83 };
84 
85 class SpriteResource {
86 public:
87 	SpriteResource(byte *data, uint32 size);
88 	~SpriteResource();
89 public:
90 	byte *_data;
91 	byte *_pixels;
92 	uint32 *_palette;
93 	int16 _width, _height;
94 	uint16 _unknownVal1;
95 	uint16 _unknownVal2;
96 	bool _transparent;
97 	uint16 _colorsCount;
98 };
99 
100 class SoundResource {
101 public:
102 	SoundResource(byte *data, uint32 size);
103 	~SoundResource();
104 public:
105 	byte *_data;
106 	uint32 _size;
107 };
108 
109 template <class ResourceClass, int ResourceType, bool FreeAfterLoad>
110 class ResourceCacheTemplate {
111 public:
112 
ResourceCacheTemplate(DatManager * dat)113 	ResourceCacheTemplate(DatManager *dat) : _dat(dat) {
114 	}
115 
~ResourceCacheTemplate()116 	~ResourceCacheTemplate() {
117 	}
118 
get(int resourceId)119 	ResourceClass *get(int resourceId) {
120 		Resource *resource = find(resourceId);
121 		if (!resource) {
122 			debug(9, "Loading resource type %d with ID %08X from disk", ResourceType, resourceId);
123 			resource = new Resource(load(resourceId));
124 			_cache[resourceId] = resource;
125 		} else {
126 			debug(9, "Resource type %d with ID %08X was in cache", ResourceType, resourceId);
127 		}
128 		resource->_isLocked = true;
129 		return resource->_obj;
130 	}
131 
release(int resourceId)132 	void release(int resourceId) {
133 		Resource *resource = find(resourceId);
134 		if (resource)
135 			resource->_isLocked = false;
136 	}
137 
138 	void purge(bool force = false) {
139 		for (CacheMapIterator it = _cache.begin(); it != _cache.end(); ++it) {
140 			Resource *resource = it->_value;
141 			if (force || !resource->_isLocked) {
142 				delete resource;
143 				_cache.erase(it);
144 			}
145 		}
146 	}
147 
148 protected:
149 
150 	struct Resource {
151 		ResourceClass *_obj;
152 		bool _isLocked;
ResourceResource153 		Resource(ResourceClass *obj) : _obj(obj), _isLocked(false) {}
~ResourceResource154 		~Resource() { delete _obj; }
155 	};
156 
157 	typedef Common::HashMap<int, Resource *> CacheMap;
158 	typedef typename CacheMap::iterator CacheMapIterator;
159 
160 	DatManager *_dat;
161 	CacheMap _cache;
162 
find(int resourceId)163 	Resource *find(int resourceId) {
164 		CacheMapIterator it = _cache.find(resourceId);
165 		if (it != _cache.end())
166 			return it->_value;
167 		return nullptr;
168 	}
169 
load(int resourceId)170 	ResourceClass *load(int resourceId) {
171 		if (_dat->getResourceType(resourceId) != ResourceType)
172 			error("ResourceCache::load() Wrong resource type: Expected %d, got %d", ResourceType, _dat->getResourceType(resourceId));
173 
174 		byte *resourceData = _dat->loadResource(resourceId);
175 		uint32 resourceSize = _dat->getResourceSize(resourceId);
176 		ResourceClass *obj = new ResourceClass(resourceData, resourceSize);
177 		if (FreeAfterLoad)
178 			delete[] resourceData;
179 		return obj;
180 	}
181 
182 };
183 
184 typedef ResourceCacheTemplate<SpriteResource, kResTypeSprite, false> SpriteCache;
185 typedef ResourceCacheTemplate<SoundResource, kResTypeSound, false> SoundCache;
186 typedef ResourceCacheTemplate<SequenceResource, kResTypeSequence, true> SequenceCache;
187 
188 } // End of namespace Gnap
189 
190 #endif // GNAP_RESOURCE_H
191