1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
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 STARK_RESOURCES_RESOURCE_H
24 #define STARK_RESOURCES_RESOURCE_H
25 
26 #include "common/array.h"
27 #include "common/str.h"
28 
29 namespace Stark {
30 
31 namespace Formats {
32 class XRCReadStream;
33 }
34 class ResourceSerializer;
35 
36 namespace Resources {
37 
38 class Type {
39 public:
40 	enum ResourceType {
41 		kInvalid                = 0,
42 		kRoot                   = 1,
43 		kLevel                  = 2,
44 		kLocation               = 3,
45 		kLayer                  = 4,
46 		kCamera                 = 5,
47 		kFloor                  = 6,
48 		kFloorFace              = 7,
49 		kItem                   = 8,
50 		kScript                 = 9,
51 		kAnimHierarchy          = 10,
52 		kAnim                   = 11,
53 		kDirection              = 12,
54 		kImage                  = 13,
55 		kAnimScript             = 14,
56 		kAnimScriptItem         = 15,
57 		kSoundItem              = 16,
58 		kPath                   = 17,
59 		kFloorField             = 18,
60 		kBookmark               = 19,
61 		kKnowledgeSet           = 20,
62 		kKnowledge              = 21,
63 		kCommand                = 22,
64 		kPATTable               = 23,
65 		kContainer              = 26,
66 		kDialog                 = 27,
67 		kSpeech                 = 29,
68 		kLight                  = 30,
69 		kCursor                 = 31, // Not sure about this one
70 		kBonesMesh              = 32,
71 		kScroll                 = 33,
72 		kFMV                    = 34,
73 		kLipSync                = 35,
74 		kAnimSoundTrigger       = 36,
75 		kString                 = 37,
76 		kTextureSet             = 38
77 	};
78 
79 	Type();
80 	Type(ResourceType type);
81 
82 	ResourceType get() const;
83 	const char *getName() const;
84 
85 	bool operator==(const Type &other) const {
86 		return other._type == _type;
87 	}
88 
89 	bool operator!=(const Type &other) const {
90 		return other._type != _type;
91 	}
92 
93 	bool operator==(const Type::ResourceType other) const {
94 		return other == _type;
95 	}
96 
97 	bool operator!=(const Type::ResourceType other) const {
98 		return other != _type;
99 	}
100 
101 private:
102 	ResourceType _type;
103 };
104 
105 /**
106  * Game resource base object
107  *
108  * The in-game objects are represented using subclasses of this class.
109  *
110  * The game world is made of a tree of resources, with each level further down
111  * the tree adding further details. An instance of this class is a node in that
112  * tree.
113  *
114  * The first few tree levels are as follow:
115  * - Root
116  * - Level
117  * - Location
118  * - Layer
119  *
120  * The actual world tree is cut off in several sub-trees. There is one sub-tree
121  * per xarc archive. For resource management reasons the sub-trees are not merged
122  * in memory, the sub-trees are loaded and unloaded as needed, according to the
123  * current level / location.
124  *
125  * The xarc archives contain each an xrc file, which is a serialized version
126  * of the initial state of a resource sub-tree. The readData method is called for
127  * each resource by the archive loader when a resource tree is loaded to set up
128  * its initial state.
129  *
130  * As the game plays, modifications are made to the resources to reflect
131  * the game's state. When the resource sub-trees are loaded or unloaded their
132  * state is restored or persisted by the state provider. The saveLoad method
133  * is called to perform the serialization / deserialization of a resource.
134  * The saveLoadCurrent method is additionally called when loading or saving
135  * a sub-tree corresponding to the current level / location. This allows to
136  * persist additional data needed when restoring an active location.
137  *
138  * The OnEnterLocation and OnExitLocation methods are called by the resource
139  * provider when entering or leaving a level / location.
140  *
141  * The OnGameLoop method is called during the game loop.
142  *
143  */
144 class Object {
145 public:
146 	virtual ~Object();
147 
148 	/** Get the resource type */
getType()149 	Type getType() const { return _type; }
150 
151 	/** Get the resource sub type */
getSubType()152 	byte getSubType() const { return _subType; }
153 
154 	/** Get the resource index */
getIndex()155 	uint16 getIndex() const { return _index; }
156 
157 	/** Get the resource index as a string */
getIndexAsString()158 	Common::String getIndexAsString() const { return Common::String::format("%02x", _index); }
159 
160 	/** Get the name of the resource */
getName()161 	Common::String getName() const { return _name; }
162 
163 	/**
164 	 * Deserialize the resource static data and initial state.
165 	 */
166 	virtual void readData(Formats::XRCReadStream *stream);
167 
168 	/**
169 	 * Persist / restore the resource state
170 	 */
171 	virtual void saveLoad(ResourceSerializer *serializer);
172 
173 	/**
174 	 * Persist / restore the resource state
175 	 *
176 	 * Called only for active locations
177 	 */
178 	virtual void saveLoadCurrent(ResourceSerializer *serializer);
179 
180 	/**
181 	 * Called when the node's initialization is complete.
182 	 *
183 	 * Allows to load additional data from file.
184 	 */
185 	virtual void onPostRead();
186 
187 	/**
188 	 * Called when the resource sub-tree is entirely loaded.
189 	 *
190 	 * Allows to load data from other nodes.
191 	 */
192 	virtual void onAllLoaded();
193 
194 	/**
195 	 * Called when entering a location
196 	 */
197 	virtual void onEnterLocation();
198 
199 	/**
200 	 * Called once per game loop
201 	 */
202 	virtual void onGameLoop();
203 
204 	/**
205 	 * Called when ScummVM pauses or resumes the engine
206 	 */
207 	virtual void onEnginePause(bool pause);
208 
209 	/**
210 	 * Called when exiting a location
211 	 */
212 	virtual void onExitLocation();
213 
214 	/**
215 	 * Called before a resource sub-tree is unloaded.
216 	 */
217 	virtual void onPreDestroy();
218 
219 	/**
220 	 * Cast a resource, performing a type check
221 	 */
222 	template<class T>
223 	static T *cast(Object *resource);
224 
225 	/** Find the first parent resource with the specified type */
226 	template<class T>
227 	T *findParent();
228 
229 	/** Find a child resource matching the specified type, index and subtype */
230 	Object *findChildWithIndex(Type type, uint16 index, int subType = -1) const;
231 
232 	/** Find a child resource matching the specified type, order in the children list and subtype */
233 	Object *findChildWithOrder(Type type, uint16 order, int subType = -1) const;
234 
235 	/** Find a child resource matching the specified type, name and subtype */
236 	Object *findChildWithName(Type type, const Common::String &name, int subType = -1) const;
237 
238 	/** Find a child matching the template parameter type */
239 	template<class T>
240 	T *findChild(bool mustBeUnique = true) const;
241 
242 	/** Find a child matching the template parameter type and the specified subtype */
243 	template<class T>
244 	T *findChildWithSubtype(int subType, bool mustBeUnique = true) const;
245 
246 	/** Find a child matching the template parameter type and the specified index */
247 	template<class T>
248 	T *findChildWithIndex(uint16 index, int subType = -1) const;
249 
250 	/** Find a child matching the template parameter type, order in the children list and subtype */
251 	template<class T>
252 	T *findChildWithOrder(uint16 order, int subType = -1) const;
253 
254 	/** Find a child matching the template parameter type, name and subtype */
255 	template<class T>
256 	T *findChildWithName(const Common::String &name, int subType = -1) const;
257 
258 	/** List children matching the template parameter type and the specified subtype */
259 	template<class T>
260 	Common::Array<T *> listChildren(int subType = -1) const;
261 
262 	/** List children recursively matching the template parameter type and the specified subtype */
263 	template<class T>
264 	Common::Array<T *> listChildrenRecursive(int subType = -1);
265 
266 	/** Add a resource to the children list */
267 	void addChild(Object *child);
268 
269 	/** Print debug information for the resource */
270 	virtual void print(uint depth = 0);
271 
272 protected:
273 	Object(Object *parent, byte subType, uint16 index, const Common::String &name);
274 
275 	void printWithDepth(uint depth, const Common::String &string) const;
276 	void printDescription(uint depth) const;
277 	virtual void printData();
278 
279 	Type _type;
280 	byte _subType;
281 	uint16 _index;
282 	Common::String _name;
283 
284 	Object *_parent;
285 	Common::Array<Object *> _children;
286 };
287 
288 /**
289  * An unimplemented resource type.
290  *
291  * Used to display the raw resource data when dumping a resource tree.
292  * To be removed once all the resource types are implemented.
293  */
294 class UnimplementedResource : public Object {
295 public:
296 	UnimplementedResource(Object *parent, Type type, byte subType, uint16 index, const Common::String &name);
297 	virtual ~UnimplementedResource();
298 
299 protected:
300 	void readData(Formats::XRCReadStream *stream) override;
301 	void printData() override;
302 
303 	uint32 _dataLength;
304 	byte *_data;
305 };
306 
307 template <class T>
cast(Object * resource)308 T* Object::cast(Object *resource) {
309 	if (resource && resource->_type != T::TYPE) {
310 		error("Unexpected resource type when casting resource %s instead of %s",
311 				resource->_type.getName(), Type(T::TYPE).getName());
312 	}
313 
314 	return (T *) resource;
315 }
316 
317 template<>
318 Object *Object::cast<Object>(Object *resource);
319 
320 template<class T>
findParent()321 T *Object::findParent() {
322 	if (getType() == T::TYPE) {
323 		return cast<T>(this);
324 	} else if (!_parent) {
325 		return nullptr;
326 	} else {
327 		return _parent->findParent<T>();
328 	}
329 }
330 
331 template<>
332 Object *Object::findParent();
333 
334 template <class T>
listChildren(int subType)335 Common::Array<T *> Object::listChildren(int subType) const {
336 	Common::Array<T *> list;
337 
338 	for (uint i = 0; i < _children.size(); i++) {
339 		if (_children[i]->getType() == T::TYPE
340 				&& (_children[i]->getSubType() == subType || subType == -1)) {
341 			// Found a matching child
342 			list.push_back(Object::cast<T>(_children[i]));
343 		}
344 	}
345 
346 	return list;
347 }
348 
349 template<class T>
listChildrenRecursive(int subType)350 Common::Array<T *> Object::listChildrenRecursive(int subType) {
351 	Common::Array<T *> list;
352 
353 	for (uint i = 0; i < _children.size(); i++) {
354 		if (_children[i]->getType() == T::TYPE
355 				&& (_children[i]->getSubType() == subType || subType == -1)) {
356 			// Found a matching child
357 			list.push_back(Object::cast<T>(_children[i]));
358 		}
359 
360 		// Look for matching resources in the child's children
361 		list.push_back(_children[i]->listChildrenRecursive<T>(subType));
362 	}
363 
364 	return list;
365 }
366 
367 template<>
368 Common::Array<Object *> Object::listChildren<Object>(int subType) const;
369 
370 template<class T>
findChild(bool mustBeUnique)371 T *Object::findChild(bool mustBeUnique) const {
372 	return findChildWithSubtype<T>(-1, mustBeUnique);
373 }
374 
375 template <class T>
findChildWithSubtype(int subType,bool mustBeUnique)376 T *Object::findChildWithSubtype(int subType, bool mustBeUnique) const {
377 	Common::Array<T *> list = listChildren<T>(subType);
378 
379 	if (list.empty()) {
380 		return nullptr;
381 	}
382 
383 	if (list.size() > 1 && mustBeUnique) {
384 		error("Several children resources matching criteria type = %s, subtype = %d", Type(T::TYPE).getName(), subType);
385 	}
386 
387 	return list.front();
388 }
389 
390 template <class T>
findChildWithIndex(uint16 index,int subType)391 T *Object::findChildWithIndex(uint16 index, int subType) const {
392 	return Object::cast<T>(findChildWithIndex(T::TYPE, index, subType));
393 }
394 
395 template <class T>
findChildWithOrder(uint16 order,int subType)396 T *Object::findChildWithOrder(uint16 order, int subType) const {
397 	return Object::cast<T>(findChildWithOrder(T::TYPE, order, subType));
398 }
399 
400 template<class T>
findChildWithName(const Common::String & name,int subType)401 T *Object::findChildWithName(const Common::String &name, int subType) const {
402 	return Object::cast<T>(findChildWithName(T::TYPE, name, subType));
403 }
404 
405 } // End of namespace Resources
406 } // End of namespace Stark
407 
408 #endif // STARK_RESOURCES_RESOURCE_H
409