1
2 /* Battle Tanks Game
3 * Copyright (C) 2006-2009 Battle Tanks team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 * Additional rights can be granted beyond the GNU General Public License
22 * on the terms provided in the Exception. If you modify this file,
23 * you may extend this exception to your version of the file,
24 * but you are not obligated to do so. If you do not wish to provide this
25 * exception without modification, you must delete this exception statement
26 * from your version and license this file solely under the GPL without exception.
27 */
28
29 #include "resource_manager.h"
30 #include "mrt/logger.h"
31 #include "sdlx/surface.h"
32 #include "sdlx/font.h"
33 #include "sdlx/c_map.h"
34 #include "object.h"
35 #include "animation_model.h"
36 #include "utils.h"
37 #include "sound/mixer.h"
38 #include "config.h"
39 #include "finder.h"
40 #include "xml_parser.h"
41 #include "rt_config.h"
42
43 #include <algorithm>
44
45 IMPLEMENT_SINGLETON(ResourceManager, IResourceManager);
46
47 class PreloadParser : public XMLParser {
48 public:
start(const std::string & name,Attrs & attr)49 virtual void start(const std::string &name, Attrs &attr) {
50 if (name == "object") {
51 std::string id = attr["id"];
52 if (id.empty())
53 return;
54
55 if (current_map.empty()) {
56 //parent object
57 current_object = attr["id"];
58 } else {
59 data[current_map].insert(id);
60 }
61 } else if (name == "map") {
62 current_map = attr["id"];
63 } else if (name == "animation") {
64 std::string id = attr["id"];
65 if (current_object.empty() || id.empty())
66 return;
67 object_data[current_object].insert(id);
68 }
69 }
end(const std::string & name)70 virtual void end(const std::string &name) {
71 if (name == "object") {
72 current_object.clear();
73 } else if (name == "map") {
74 current_map.clear();
75 }
76 }
update(IResourceManager::PreloadMap & preload_map,IResourceManager::PreloadMap & object_map,const std::string & base) const77 void update(IResourceManager::PreloadMap &preload_map, IResourceManager::PreloadMap &object_map, const std::string &base) const {
78 for(PreloadMap::const_iterator i = object_data.begin(); i != object_data.end(); ++i) {
79 const std::set<std::string> &src = i->second;
80 std::set<std::string> &dst = object_map[std::pair<std::string, std::string>(base, i->first)];
81 for(std::set<std::string>::const_iterator j = src.begin(); j != src.end(); ++j) {
82 dst.insert(*j);
83 }
84 }
85
86 for(PreloadMap::const_iterator i = data.begin(); i != data.end(); ++i) {
87 const std::set<std::string> &src = i->second;
88 std::set<std::string> &dst = preload_map[std::pair<std::string, std::string>(base, i->first)];
89 for(std::set<std::string>::const_iterator j = src.begin(); j != src.end(); ++j) {
90 dst.insert(*j);
91 }
92 }
93 }
94 private:
95 typedef std::map<const std::string, std::set<std::string> > PreloadMap;
96
97 std::string current_object, current_map;
98 PreloadMap data, object_data;
99 };
100
onFile(const std::string & base,const std::string & file)101 void IResourceManager::onFile(const std::string &base, const std::string &file) {
102 _base_dir = base;
103
104 if (base.empty())
105 return;
106
107 TRY {
108 std::string preload = Finder->find(base, "preload.xml", false);
109 if (preload.empty())
110 return;
111 LOG_DEBUG(("parsing preload file: %s", preload.c_str()));
112 PreloadParser p;
113 p.parse_file(preload);
114 p.update(_preload_map, _object_preload_map, base);
115 } CATCH("parsing preload file", {});
116 }
117
start(const std::string & name,Attrs & attr)118 void IResourceManager::start(const std::string &name, Attrs &attr) {
119 if (name == "resources") {
120 _tw = atol(attr["tile_width"].c_str());
121 if (_tw == 0)
122 throw_ex(("resources tag must contain `tile_width' attribute (default tile width)"));
123 _th = atol(attr["tile_height"].c_str());
124 if (_th == 0)
125 throw_ex(("resources tag must contain `tile_height' attribute (default tile height)"));
126 if (attr["version"].empty())
127 throw_ex(("resources tag must contain `version' attribute"));
128 LOG_DEBUG(("file version: %s", attr["version"].c_str()));
129 } else if (name == "animation") {
130 status = "animation";
131 const std::string &id = attr["id"];
132 if (id.empty())
133 throw_ex(("animation.id was not set"));
134
135 const std::string &model = attr["model"];
136 if (model.empty())
137 throw_ex(("animation.model was not set"));
138
139 long tw = atol(attr["tile_width"].c_str());
140 long th = atol(attr["tile_height"].c_str());
141 long sz = atol(attr["size"].c_str());
142 if (tw == 0) tw = _tw;
143 if (th == 0) th = _th;
144 if (sz != 0) tw = th = sz;
145
146 sdlx::Surface *s = NULL;
147 sdlx::CollisionMap *cmap = NULL;
148 bool real_load = !attr["persistent"].empty();
149
150 GET_CONFIG_VALUE("engine.preload", bool , preload_all, false);
151 real_load |= preload_all;
152
153 std::string &tile = attr["tile"];
154 if (_base_dir.empty())
155 throw_ex(("base directory was not defined (multiply resources tag ? invalid resource structure?)"));
156
157 if (_surfaces.find(tile) == _surfaces.end()) {
158 TRY {
159 if (real_load) {
160 mrt::Chunk data;
161 std::string tname = "tiles/" + tile;
162 Finder->load(data, tname);
163
164 s = new sdlx::Surface;
165 s->load_image(data);
166 s->display_format_alpha();
167
168 cmap = create_cmap(s, tname);
169
170 LOG_DEBUG(("loaded animation '%s'", id.c_str()));
171 }
172
173 _surfaces[tile] = s;
174 s = NULL;
175
176 _cmaps[tile] = cmap;
177 cmap = NULL;
178
179 } CATCH(mrt::format_string("loading animation \"%s\"", tile.c_str()).c_str(), { delete s; s = NULL; delete cmap; cmap = NULL; throw; });
180 //
181 } else {
182 LOG_DEBUG(("tile '%s' was already loaded, skipped.", tile.c_str()));
183 }
184
185 _animations[id] = new Animation(model, _base_dir, tile, tw, th);
186
187 } else if (name == "animation-model") {
188 status = "model";
189
190 const std::string & id = attr["id"];
191 if (id.empty())
192 throw_ex(("animation model must have id"));
193
194 float speed = atof(attr["speed"].c_str());
195 if (speed == 0)
196 throw_ex(("animation model must have default speed"));
197
198 _am = new AnimationModel(speed);
199 _am_id = id;
200 } else if (name == "pose") {
201 if (_am == NULL)
202 throw_ex(("pose tag must have parent animation-model"));
203 _pose_id = attr["id"];
204 if (_pose_id.empty())
205 throw_ex(("pose must have id"));
206 float speed = atof(attr["speed"].c_str());
207 if (speed == 0)
208 speed = _am->default_speed;
209
210 int z = (!attr["z"].empty())?atoi(attr["z"].c_str()) : -100001;
211 const std::string &sound = attr["sound"];
212 _pose = new Pose(speed, z, sound);
213 const std::string &gain = attr["gain"];
214 if (!gain.empty()) {
215 _pose->gain = atof(gain.c_str());
216 LOG_DEBUG(("adjusting gain for sample %s to %g", sound.c_str(), _pose->gain));
217 }
218 const std::string ¬ify = attr["notify"];
219 if (!notify.empty() && (notify[0] == 't' || notify[0] == '1'))
220 _pose->need_notify = true;
221 if (!sound.empty() && sound[0] != '@')
222 Mixer->loadSample(sound);
223 } else if (name == "object") {
224 status = "object";
225 const std::string classname = attr["class"];
226 if (classname.empty())
227 throw_ex(("tag 'object' must provide its classname id."));
228 ObjectMap::iterator object;
229 if ((object = _objects.find(classname)) == _objects.end()) {
230 throw_ex(("class '%s' was not registered. ", classname.c_str()));
231 }
232 LOG_DEBUG(("setting up class '%s'", classname.c_str()));
233
234 if (attr.find("parent") != attr.end()) {
235 ObjectMap::iterator parent;
236 if ((parent = _objects.find(attr["parent"])) == _objects.end()) {
237 throw_ex(("class '%s' declared as parent of '%s' was not registered. skipped.", attr["parent"].c_str(), classname.c_str()));
238 }
239 object->second->inherit_parameters(parent->second);
240 }
241
242 for (Attrs::iterator i = attr.begin(); i != attr.end(); ++i) {
243 const std::string &name = i->first;
244 const std::string &value = i->second;
245 if (name == "speed") {
246 object->second->speed = atol(value.c_str());
247 } else if (name == "mass") {
248 object->second->mass = atof(value.c_str());
249 } else if (name == "ttl") {
250 object->second->ttl = atof(value.c_str());
251 } else if (name == "piercing") {
252 object->second->piercing = (value[0] == 't' || value[0] == '1' || value[0] == 'y');
253 } else if (name == "pierceable") {
254 object->second->pierceable = (value[0] == 't' || value[0] == '1' || value[0] == 'y');
255 } else if (name == "hp") {
256 object->second->max_hp = object->second->hp = atol(value.c_str());
257 } else if (name == "impassability") {
258 object->second->impassability = atof(value.c_str());
259 } else if (name == "fadeout_time") {
260 object->second->fadeout_time = atof(value.c_str());
261 } else if (name == "z") {
262 object->second->set_z(atoi(value.c_str()));
263 } else if (name != "class" && name != "parent")
264 LOG_WARN(("attr '%s' is not supported", name.c_str()));
265 }
266 LOG_DEBUG(("%s", object->second->dump().c_str()));
267 } else if (name == "alias") {
268 status = "object";
269 std::string name = attr["name"];
270 std::string classname = attr["class"];
271 if (name.empty() || classname.empty())
272 throw_ex(("alias must have both 'name' and 'class' attributes"));
273 createAlias(name, classname);
274 } else if (name == "sound") {
275 status = "sound";
276 std::string file = attr["file"];
277 if (file.empty())
278 throw_ex(("sound.file MUST not be empty."));
279 TRY {
280 Mixer->loadSample(file, attr["class"]);
281 } CATCH("loadSample", {});
282 } else LOG_WARN(("unhandled tag: %s", name.c_str()));
283 NotifyingXMLParser::start(name, attr);
284 }
285
end(const std::string & name)286 void IResourceManager::end(const std::string &name) {
287 mrt::trim(_data);
288 if (name == "pose") {
289 LOG_DEBUG(("pose frames: %s", _data.c_str()));
290 std::vector<std::string> frames;
291 mrt::split(frames, _data, ",");
292
293 for(size_t i = 0; i < frames.size(); ++i) {
294 //LOG_DEBUG(("%d: %s", i, frames[i].c_str()));
295 mrt::trim(frames[i]);
296 unsigned int frame = atoi(frames[i].c_str());
297 //LOG_DEBUG(("%d: %d", i, frame));
298 _pose->frames.push_back(frame);
299 }
300 _am->addPose(_pose_id, _pose);
301 _pose = NULL;
302 } else if (name == "animation-model") {
303 delete _animation_models[_am_id];
304 _animation_models[_am_id] = _am;
305 _am = NULL;
306 LOG_DEBUG(("added animation model '%s'", _am_id.c_str()));
307 } else if (name == "resources") {
308 _base_dir.clear();
309 }
310 NotifyingXMLParser::end(name);
311 _data.clear();
312 }
cdata(const std::string & data)313 void IResourceManager::cdata(const std::string &data) {
314 _data += data;
315 }
316
IResourceManager()317 IResourceManager::IResourceManager() : _am(0) {
318 }
319
hasAnimation(const std::string & id) const320 const bool IResourceManager::hasAnimation(const std::string &id) const {
321 return _animations.find(id) != _animations.end();
322 }
323
getAnimation(const std::string & id)324 Animation *IResourceManager::getAnimation(const std::string &id) {
325 AnimationMap::iterator i = _animations.find(id);
326 #ifdef DEBUG
327 assert(i != _animations.end());
328 #endif
329 if (i == _animations.end())
330 throw_ex(("could not find animation with id '%s'", id.c_str()));
331 return i->second;
332 }
333
getAnimation(const std::string & id) const334 const Animation *IResourceManager::getAnimation(const std::string &id) const {
335 AnimationMap::const_iterator i = _animations.find(id);
336 #ifdef DEBUG
337 assert(i != _animations.end());
338 #endif
339 if (i == _animations.end())
340 throw_ex(("could not find animation with id '%s'", id.c_str()));
341 return i->second;
342 }
343
get_animation_model(const std::string & id)344 AnimationModel *IResourceManager::get_animation_model(const std::string &id) {
345 AnimationModelMap::iterator i = _animation_models.find(id);
346 if (i == _animation_models.end())
347 throw_ex(("could not find animation model with id '%s'", id.c_str()));
348 return i->second;
349 }
350
get_surface(const std::string & id) const351 const sdlx::Surface *IResourceManager::get_surface(const std::string &id) const {
352 SurfaceMap::const_iterator i = _surfaces.find(id);
353 if (i == _surfaces.end())
354 throw_ex(("could not find surface with id '%s'", id.c_str()));
355 return i->second;
356 }
357
unload_surface(const std::string & id)358 void IResourceManager::unload_surface(const std::string &id) {
359 SurfaceMap::iterator i = _surfaces.find(id);
360 if (i == _surfaces.end())
361 return;
362 delete i->second;
363 _surfaces.erase(i);
364 }
365
load_surface(const std::string & id,int scale_to_w,int scale_to_h)366 const sdlx::Surface *IResourceManager::load_surface(const std::string &id, int scale_to_w, int scale_to_h) {
367 SurfaceMap::iterator i = _surfaces.find(id);
368 if (i != _surfaces.end() && i->second != NULL)
369 return i->second;
370
371 sdlx::Surface *s = NULL;
372 TRY {
373 GET_CONFIG_VALUE("engine.generate-alpha-tiles", bool, gat, false);
374 mrt::Chunk data;
375 std::string tname = "tiles/" + id;
376 Finder->load(data, tname);
377
378 s = new sdlx::Surface;
379 s->load_image(data);
380 LOG_DEBUG(("loaded surface '%s'", id.c_str()));
381 if (scale_to_w != 0 || scale_to_h != 0) {
382 if (scale_to_w == 0)
383 scale_to_w = scale_to_h * s->get_width() / s->get_height();
384 if (scale_to_h == 0)
385 scale_to_h = scale_to_w * s->get_height() / s->get_width();
386 LOG_DEBUG(("scaling surface to %dx%d", scale_to_w, scale_to_h));
387 s->zoom(1.0 * scale_to_w / s->get_width(), 1.0 * scale_to_h / s->get_height());
388 }
389 s->display_format_alpha();
390 _surfaces[id] = s;
391 } CATCH("loading surface", { delete s; throw; });
392 return s;
393 }
394
loadFont(const std::string & name,const bool alpha)395 const sdlx::Font *IResourceManager::loadFont(const std::string &name, const bool alpha) {
396 std::pair<std::string, bool> id(name, alpha);
397 FontMap::iterator i = _fonts.find(id);
398 if (i != _fonts.end() && i->second != NULL)
399 return i->second;
400
401 sdlx::Font *f = NULL;
402 TRY {
403 mrt::Chunk data;
404 Finder->load(data, "font/" + name + ".png");
405 f = new sdlx::Font;
406 f->load(data, sdlx::Font::Ascii, alpha);
407 LOG_DEBUG(("loaded font '%s'", name.c_str()));
408 _fonts[id] = f;
409 } CATCH("loading font", { delete f; throw; });
410
411 mrt::Chunk data;
412 const std::string page0400 = Finder->find("font/" + name + "_0400.png", false);
413 if (!page0400.empty()) {
414 Finder->load(data, "font/" + name + "_0400.png");
415 f->add_page(0x0400, data, alpha);
416 }
417
418 const std::string page0080 = Finder->find("font/" + name + "_0080.png", false);
419 if (!page0080.empty()) {
420 Finder->load(data, "font/" + name + "_0080.png");
421 f->add_page(0x00a0, data, alpha);
422 }
423
424 const std::string page2460 = Finder->find("font/" + name + "_2460.png", false);
425 if (!page2460.empty()) {
426 Finder->load(data, "font/" + name + "_2460.png");
427 f->add_page(0x2460, data, alpha);
428 }
429 return f;
430 }
431
432
getCollisionMap(const std::string & id) const433 const sdlx::CollisionMap *IResourceManager::getCollisionMap(const std::string &id) const {
434 CollisionMap::const_iterator i = _cmaps.find(id);
435 if (i == _cmaps.end())
436 throw_ex(("could not find collision map with id '%s'", id.c_str()));
437 return i->second;
438 }
439
440
init(const std::vector<std::pair<std::string,std::string>> & fname)441 void IResourceManager::init(const std::vector<std::pair<std::string, std::string> > &fname) {
442 parse_files(fname);
443 status = "menu"; //small hack. menu takes some time to setup and load.
444 }
445
446 #include "mrt/file.h"
447 #include "tmx/map.h"
448 #include "mrt/directory.h"
449
clear()450 void IResourceManager::clear() {
451 LOG_DEBUG(("freeing resources"));
452 std::for_each(_animations.begin(), _animations.end(), delete_ptr2<AnimationMap::value_type>());
453 _animations.clear();
454 std::for_each(_animation_models.begin(), _animation_models.end(), delete_ptr2<AnimationModelMap::value_type>());
455 _animation_models.clear();
456 std::for_each(_surfaces.begin(), _surfaces.end(), delete_ptr2<SurfaceMap::value_type>());
457 _surfaces.clear();
458 std::for_each(_cmaps.begin(), _cmaps.end(), delete_ptr2<CollisionMap::value_type>());
459 _cmaps.clear();
460 std::for_each(_fonts.begin(), _fonts.end(), delete_ptr2<FontMap::value_type>());
461 _fonts.clear();
462 std::for_each(_objects.begin(), _objects.end(), delete_ptr2<ObjectMap::value_type>());
463 _objects.clear();
464
465 _am = NULL;
466
467 if (RTConfig->editor_mode)
468 return;
469
470 std::map<const std::string, std::string> xml_data;
471 for(PreloadMap::const_iterator i = _preload_map.begin(); i != _preload_map.end(); ++i) {
472 std::string &dst = xml_data[i->first.first];
473 dst += mrt::format_string("\t<map id=\"%s\">\n", escape(i->first.second).c_str());
474 for(std::set<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
475 //LOG_DEBUG(("map: %s, %s", i->first.c_str(), j->c_str()));
476 dst += mrt::format_string("\t\t<object id=\"%s\"/>\n", escape(*j).c_str());
477 }
478 dst += "\t</map>\n";
479 }
480 for(PreloadMap::const_iterator i = _object_preload_map.begin(); i != _object_preload_map.end(); ++i) {
481 std::string &dst = xml_data[i->first.first];
482 dst += mrt::format_string("\t<object id=\"%s\">\n", escape(i->first.second).c_str());
483 for(std::set<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
484 //LOG_DEBUG(("map: %s, %s", i->first.c_str(), j->c_str()));
485 dst += mrt::format_string("\t\t<animation id=\"%s\"/>\n", escape(*j).c_str());
486 }
487 dst += "\t</object>\n";
488 }
489
490
491 for(std::map<const std::string, std::string>::iterator i = xml_data.begin(); i != xml_data.end(); ++i) {
492 //LOG_DEBUG(("xml data for %s, size: %u", i->first.c_str(), (unsigned)i->second.size()));
493 TRY {
494 assert(!i->first.empty());
495 if (Finder->packed(i->first))
496 continue;
497
498 try {
499 mrt::Directory dir;
500 dir.create(i->first, true);
501 } catch(...) {}
502
503 mrt::File f;
504 f.open(i->first + "/preload.xml", "wb");
505 i->second.insert(0, "<?xml version=\"1.0\"?>\n<preload>\n");
506 i->second += "</preload>\n";
507 f.write_all(i->second);
508 } CATCH("writing to the preload cache", {});
509 }
510 }
511
~IResourceManager()512 IResourceManager::~IResourceManager() {
513 }
514
registerObject(const std::string & classname,Object * o)515 void IResourceManager::registerObject(const std::string &classname, Object *o) {
516 Variants vars;
517 vars.parse(classname);
518 if (!vars.empty())
519 throw_ex(("registering object with variants ('%s') is prohibited", classname.c_str()));
520
521 assert(!classname.empty());
522 *const_cast<std::string *>(&o->registered_name) = classname;
523 assert(!o->registered_name.empty());
524
525 Object *old = _objects[classname];
526 if (old != NULL)
527 LOG_DEBUG(("overriding object %s", classname.c_str()));
528 delete old;
529 _objects[classname] = o;
530 //LOG_DEBUG(("classname %s registered at %p", classname.c_str(), (void*)o));
531 }
532
createAlias(const std::string & name,const std::string & _classname)533 void IResourceManager::createAlias(const std::string &name, const std::string &_classname) {
534 Variants vars;
535 vars.parse(name);
536 if (!vars.empty())
537 throw_ex(("registering object with variants ('%s') is prohibited", name.c_str()));
538
539 std::string classname = vars.parse(_classname);
540
541 LOG_DEBUG(("creating alias '%s' -> '%s' (variants: '%s')", name.c_str(), classname.c_str(), vars.dump().c_str()));
542 ObjectMap::const_iterator i = _objects.find(classname);
543
544 if (i == _objects.end())
545 throw_ex(("object %s was not registered", classname.c_str()));
546
547 if (_objects.find(name) != _objects.end())
548 throw_ex(("attempt to create alias with duplicate name ('%s')", name.c_str()));
549
550 Object * r = i->second->clone();
551 if (r == NULL)
552 throw_ex(("%s->clone(\"\") returns NULL", classname.c_str()));
553
554 *const_cast<std::string *>(&r->registered_name) = name;
555
556 r->update_variants(vars);
557 _objects[name] = r;
558 }
559
createObject(const std::string & _classname) const560 Object *IResourceManager::createObject(const std::string &_classname) const {
561 Variants vars;
562 std::string classname = vars.parse(_classname);
563 assert(classname.find('(') == classname.npos);
564
565 ObjectMap::const_iterator i = _objects.find(classname);
566 if (i == _objects.end())
567 throw_ex(("classname '%s' was not registered", classname.c_str()));
568 Object * r = i->second->clone();
569
570 if (r == NULL)
571 throw_ex(("%s->clone() returns NULL", classname.c_str()));
572
573 if (r->registered_name.empty())
574 throw_ex(("%s::clone() did not use copy ctor. (you must write \" return new Class(*this)\" or smth.)", classname.c_str()));
575
576 r->update_variants(vars);
577
578 return r;
579 }
580
581 #include "tmx/map.h"
582
createObject(const std::string & classname,const std::string & animation) const583 Object *IResourceManager::createObject(const std::string &classname, const std::string &animation) const {
584 if (!Map->getName().empty()) {
585 std::string stripped_classname = Variants::strip(classname);
586 _preload_map[PreloadMap::key_type(Map->getPath(), Map->getName())].insert(stripped_classname);
587 _object_preload_map[PreloadMap::key_type(Map->getPath(), stripped_classname)].insert(animation);
588 }
589
590 Object *r = createObject(classname);
591
592 r->init(animation);
593 //LOG_DEBUG(("base: %s", i->second->dump().c_str()));
594 //LOG_DEBUG(("clone: %s", r->dump().c_str()));
595 r->animation = animation;
596
597 return r;
598 }
599
getClass(const std::string & classname) const600 const Object *IResourceManager::getClass(const std::string &classname) const {
601 ObjectMap::const_iterator i = _objects.find(classname);
602 if (i == _objects.end())
603 throw_ex(("classname '%s' was not registered", classname.c_str()));
604 return i->second;
605 }
606
hasClass(const std::string & classname) const607 const bool IResourceManager::hasClass(const std::string &classname) const {
608 return _objects.find(classname) != _objects.end();
609 }
610
611 #include "mrt/fs_node.h"
612
check_surface(const std::string & animation,const sdlx::Surface * & surface_ptr,const sdlx::CollisionMap * & cmap_ptr)613 void IResourceManager::check_surface(const std::string &animation, const sdlx::Surface *& surface_ptr, const sdlx::CollisionMap *& cmap_ptr) {
614 if (surface_ptr != NULL && cmap_ptr != NULL)
615 return;
616
617 const Animation * a = getAnimation(animation);
618 std::string tname = "tiles/" + a->surface;
619
620 sdlx::Surface *s = _surfaces[a->surface];
621 sdlx::CollisionMap *cmap = _cmaps[a->surface];
622
623
624 if (s == NULL) {
625 TRY {
626 mrt::Chunk data;
627 Finder->load(data, tname);
628 s = new sdlx::Surface;
629 s->load_image(data);
630 s->display_format_alpha();
631 GET_CONFIG_VALUE("engine.strip-alpha-from-object-tiles", bool, strip_alpha, false);
632 if (strip_alpha) {
633 s->lock();
634 Uint8 r,g,b,a;
635 for(int y = 0; y < s->get_height(); ++y)
636 for(int x = 0; x < s->get_width(); ++x) {
637 s->get_rgba(s->get_pixel(x, y), r, g, b, a);
638 if (a != 255)
639 s->put_pixel(x, y, s->map_rgba(r, g, b, (a > 51)?51:a));
640 }
641 s->unlock();
642 }
643
644 LOG_DEBUG(("loaded animation '%s'", animation.c_str()));
645 _surfaces[a->surface] = s;
646 } CATCH("loading surface", { delete s; throw; });
647 }
648 surface_ptr = s;
649
650 if (cmap == NULL) {
651 cmap = create_cmap(s, tname);
652 _cmaps[a->surface] = cmap;
653 }
654 cmap_ptr = cmap;
655 }
656
getAllClasses(std::set<std::string> & classes)657 void IResourceManager::getAllClasses(std::set<std::string> &classes) {
658 classes.clear();
659 for(ObjectMap::const_iterator i = _objects.begin(); i != _objects.end(); ++i) {
660 classes.insert(i->first);
661 }
662 }
663
preload()664 void IResourceManager::preload() {
665 LOG_DEBUG(("preloading surfaces..."));
666 std::pair<std::string, std::string> map_id(Map->getPath(), Map->getName());
667 PreloadMap::const_iterator map = _preload_map.find(map_id);
668 if (map == _preload_map.end())
669 return;
670
671 const std::set<std::string>& objects = map->second;
672 std::set<std::string> animations;
673
674 for(std::set<std::string>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
675 PreloadMap::const_iterator o = _object_preload_map.find(PreloadMap::key_type(Map->getPath(), *i));
676 if (o != _object_preload_map.end()) {
677 const std::set<std::string>& anims = o->second;
678 for(std::set<std::string>::const_iterator j = anims.begin(); j != anims.end(); ++j) {
679 animations.insert(*j);
680 }
681 }
682 }
683
684 if (animations.empty())
685 return;
686 LOG_DEBUG(("found %u surfaces, loading...", (unsigned)animations.size()));
687
688 reset_progress.emit(animations.size());
689 for(std::set<std::string>::iterator i = animations.begin(); i != animations.end(); ++i) {
690 const std::string &name = *i;
691 if (hasAnimation(name)) {
692 Animation *a = getAnimation(name);
693 load_surface(a->surface);
694 }
695 notify_progress.emit(1, "animation");
696 }
697 }
698
create_cmap(const sdlx::Surface * s,const std::string & name)699 sdlx::CollisionMap * IResourceManager::create_cmap(const sdlx::Surface *s, const std::string &name) {
700 sdlx::CollisionMap * cmap = new sdlx::CollisionMap;
701 GET_CONFIG_VALUE("engine.generate-static-collision-maps", bool, gscm, false);
702 if (true || !gscm) {
703 try {
704 mrt::Chunk data;
705 Finder->load(data, name + ".map");
706 if (cmap->load(s->get_width(), s->get_height(), data))
707 return cmap;
708 } CATCH("create_map(load)", {});
709 }
710 cmap->init(s, sdlx::CollisionMap::OnlyOpaque);
711 if (gscm) {
712 LOG_DEBUG(("generating collision map for the %s", name.c_str()));
713 IFinder::FindResult r;
714 Finder->findAll(r, name);
715 if (r.empty()) {
716 return cmap;
717 }
718 const std::string &base = r[0].first;
719 try {
720 std::string fname = base + "/" + name + ".map";
721 LOG_DEBUG(("saving collision map in %s", fname.c_str()));
722 cmap->save(fname);
723 } CATCH("create_map(save)", {})
724 }
725 return cmap;
726 }
727