FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
atlasloader.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2011 by the FIFE team *
3  * http://www.fifengine.net *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 
24 // 3rd party library includes
25 
26 // FIFE includes
27 // These includes are split up in two parts, separated by one empty line
28 // First block: files included from the FIFE root src directory
29 // Second block: files included from the same folder
30 #include "ext/tinyxml/fife_tinyxml.h"
31 #include "model/model.h"
32 #include "model/structures/layer.h"
33 #include "vfs/fife_boost_filesystem.h"
34 #include "vfs/vfs.h"
35 #include "vfs/raw/rawdata.h"
36 #include "util/base/exception.h"
37 #include "util/log/logger.h"
38 #include "util/resource/resource.h"
39 #include "util/resource/resourcemanager.h"
40 #include "view/visual.h"
41 
42 #include "atlasloader.h"
43 
44 namespace FIFE {
45  static Logger _log(LM_NATIVE_LOADERS);
46 
47 
48  size_t Atlas::getImageCount() const {
49  return m_subimages.size();
50  }
51 
52  ImagePtr& Atlas::getPackedImage() {
53  return m_image;
54  }
55 
56  ImagePtr Atlas::getImage(const std::string& id) {
57  SubimageMap::iterator iter = m_subimages.find(id);
58  if(iter == m_subimages.end())
59  return ImagePtr();
60  return iter->second.image;
61  }
62 
63  ImagePtr Atlas::getImage(uint32_t index) {
64  if(index > getImageCount())
65  return ImagePtr();
66 
67  SubimageMap::iterator iter = m_subimages.begin();
68  for(uint32_t i = 0; i < index; ++i, ++iter);
69  return iter->second.image;
70  }
71 
72  bool Atlas::addImage(const std::string& imagename, const AtlasData& data) {
73  return m_subimages.insert(std::pair<std::string, AtlasData>(imagename, data)).second;
74  }
75 
76  void Atlas::setPackedImage(const ImagePtr& image) {
77  m_image = image;
78  }
79 
80  const std::string& Atlas::getName() const {
81  return m_name;
82  }
83 
84  AtlasLoader::AtlasLoader(Model* model, VFS* vfs, ImageManager* imageManager)
85  : m_model(model), m_vfs(vfs), m_imageManager(imageManager) {
86  }
87 
88  AtlasLoader::~AtlasLoader() {
89  }
90 
91  bool AtlasLoader::isLoadable(const std::string& filename) {
92  bfs::path atlasPath(filename);
93  std::string atlasFilename = atlasPath.string();
94  TiXmlDocument atlasFile;
95 
96  try {
97  RawData* data = m_vfs->open(atlasFilename);
98 
99  if (data) {
100  if (data->getDataLength() != 0) {
101  atlasFile.Parse(data->readString(data->getDataLength()).c_str());
102 
103  if (atlasFile.Error()) {
104  return false;
105  }
106  } else {
107  return false;
108  }
109 
110  // done with data delete resource
111  delete data;
112  data = 0;
113  }
114  } catch (NotFound&) {
115  return false;
116  }
117 
118  // if we get here then loading the file went well
119  TiXmlElement* root = atlasFile.RootElement();
120 
121  if (root && root->ValueStr() == "atlas") {
122  return true;
123  }
124  else {
125  return false;
126  }
127  }
128 
129  AtlasPtr AtlasLoader::load(const std::string& filename) {
130  bfs::path atlasPath(filename);
131  bfs::path atlasPathDirectory;
132  m_atlasFilename = atlasPath.string();
133 
134  if (HasParentPath(atlasPath)) {
135  // save the directory where the atlas file is located
136  atlasPathDirectory = GetParentPath(atlasPath);
137  }
138 
139  TiXmlDocument doc;
140  AtlasPtr atlas;
141 
142  try {
143  RawData* data = m_vfs->open(m_atlasFilename);
144 
145  if (data) {
146  if (data->getDataLength() != 0) {
147  doc.Parse(data->readString(data->getDataLength()).c_str());
148 
149  if (doc.Error()) {
150  return atlas;
151  }
152 
153  // done with data delete resource
154  delete data;
155  data = 0;
156  }
157  }
158  }
159  catch (NotFound& e) {
160  FL_ERR(_log, e.what());
161 
162  // TODO - should we abort here
163  // or rethrow the exception
164  // or just keep going
165 
166  return atlas;
167  }
168 
169  // if we get here then everything loaded properly
170  // so we can just parse out the contents
171  TiXmlElement* root = doc.RootElement();
172 
173  if (root && root->ValueStr() == "atlas") {
174  const std::string* atlasName = root->Attribute(std::string("name"));
175  if(atlasName) {
176  const std::string* namespaceId = root->Attribute(std::string("namespace"));
177  if(!namespaceId) {
178  namespaceId = atlasName;
179  }
180 
181  // Atlas itself doesn't have appended namespace
182  bfs::path atlasImagePath = atlasPathDirectory / *atlasName;
183  atlas.reset(new Atlas(atlasImagePath.string()));
184 
185  // End-user could create the same atlas for the second time.
186  // Since we don't hold any data for Atlases like ImageManager we need to recreate
187  // atlas parameters (to return proper AtlasPtr) but don't reload pixel data (they are held by ImageManager).
188 
189  bool atlasExists = m_imageManager->exists(atlas->getName());
190 
191  if(!atlasExists) {
192  atlas->setPackedImage(m_imageManager->create(atlas->getName()));
193  }
194  else {
195  atlas->setPackedImage(m_imageManager->getPtr(atlas->getName()));
196  }
197 
198  // We don't really need this now, though we could use it to assert if the loaded atlas is the same sized as these
199  //int atlasWidth, atlasHeight;
200  //root->QueryValueAttribute("width", &atlasWidth);
201  //root->QueryValueAttribute("height", &atlasHeight);
202  bool subsExists = true;
203  for (TiXmlElement* imageElem = root->FirstChildElement("image");
204  imageElem != 0; imageElem = imageElem->NextSiblingElement("image")) {
205 
206  Rect region;
207  imageElem->QueryValueAttribute("xpos", &region.x);
208  imageElem->QueryValueAttribute("ypos", &region.y);
209  imageElem->QueryValueAttribute("width", &region.w);
210  imageElem->QueryValueAttribute("height", &region.h);
211 
212  const std::string* subimageName = imageElem->Attribute(std::string("source"));
213 
214  if (subimageName) {
215  std::string finalname = *namespaceId + ":" +*subimageName;
216  ImagePtr subImage;
217 
218  bool subExists = m_imageManager->exists(finalname);
219  if (!subExists) {
220  subsExists = false;
221  subImage = m_imageManager->create(finalname);
222  }
223  else {
224  subImage = m_imageManager->getPtr(finalname);
225  }
226  subImage->useSharedImage(atlas->getPackedImage(), region);
227 
228  AtlasData atlas_data = {region, subImage};
229  atlas->addImage(finalname, atlas_data);
230  }
231  }
232  subsExists = subsExists && atlasExists;
233 
234  // Now parse object definition
235  for(TiXmlElement* objElem = root->NextSiblingElement("object");
236  objElem != 0; objElem = objElem->NextSiblingElement("object"))
237  {
238  // sanity check
239  if(objElem->ValueStr() == "object") {
240  parseObject(atlas.get(), objElem, subsExists);
241  }
242  }
243  }
244  }
245 
246  return atlas;
247  }
248 
249  void AtlasLoader::parseObject(Atlas* atlas, TiXmlElement* root, bool exists) {
250  const std::string* objectId = root->Attribute(std::string("id"));
251  const std::string* namespaceId = root->Attribute(std::string("namespace"));
252 
253  Object* obj = NULL;
254  if (objectId && namespaceId) {
255  const std::string* parentId = root->Attribute(std::string("parent"));
256 
257  if (parentId) {
258  Object* parent = m_model->getObject(*parentId, *namespaceId);
259  if (parent) {
260  try {
261  obj = m_model->createObject(*objectId, *namespaceId, parent);
262  }
263  catch (NameClash&) {
264  // TODO - handle exception
265  assert(false);
266  }
267  }
268  }
269  else {
270  // this will make sure the object has not already been loaded
271  if (m_model->getObject(*objectId, *namespaceId) == NULL) {
272  try {
273  obj = m_model->createObject(*objectId, *namespaceId);
274  }
275  catch (NameClash&) {
276  // TODO - handle exception
277  assert(false);
278  }
279  // if atlas or subimage was recreated then we have to update the ObjectVisual
280  } else if (!exists) {
281  obj = m_model->getObject(*objectId, *namespaceId);
282  ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
283  // make sure obj have visual
284  if (!objVisual) {
285  objVisual = ObjectVisual::create(obj);
286  }
287 
288  for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
289  const std::string* sourceId = imageElement->Attribute(std::string("source"));
290 
291  if (sourceId) {
292  std::string source = *namespaceId + ":" + *sourceId;
293  if(!m_imageManager->exists(source)) {
294  throw NotFound(source + " couldn't be found.");
295  }
296  ImagePtr imagePtr = m_imageManager->getPtr(source);
297 
298  int xOffset = 0;
299  int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
300  if (success == TIXML_SUCCESS) {
301  imagePtr->setXShift(xOffset);
302  }
303 
304  int yOffset = 0;
305  success = imageElement->QueryIntAttribute("y_offset", &yOffset);
306  if (success == TIXML_SUCCESS) {
307  imagePtr->setYShift(yOffset);
308  }
309 
310  int direction = 0;
311  success = imageElement->QueryIntAttribute("direction", &direction);
312  if (success == TIXML_SUCCESS) {
313  if (objVisual) {
314  objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
315  }
316  }
317  }
318  }
319  return;
320  }
321  }
322  }
323 
324  if (obj) {
325  //obj->setFilename(atlas->getName());
326  obj->setFilename(m_atlasFilename);
327  ObjectVisual::create(obj);
328 
329  int isBlocking = 0;
330  root->QueryIntAttribute("blocking", &isBlocking);
331  obj->setBlocking(isBlocking!=0);
332 
333  int isStatic = 0;
334  root->QueryIntAttribute("static", &isStatic);
335  obj->setStatic(isStatic!=0);
336 
337  const std::string* pather = root->Attribute(std::string("pather"));
338 
339  if (pather) {
340  obj->setPather(m_model->getPather(*pather));
341  }
342  else {
343  obj->setPather(m_model->getPather("RoutePather"));
344  }
345 
346  // loop over all image tags
347  for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
348  const std::string* sourceId = imageElement->Attribute(std::string("source"));
349 
350  if (sourceId) {
351  std::string source = *namespaceId + ":" + *sourceId;
352  if(!m_imageManager->exists(source)) {
353  throw NotFound(source + " couldn't be found.");
354  }
355  ImagePtr imagePtr = m_imageManager->getPtr(source);
356  int xOffset = 0;
357  int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
358 
359  if (success == TIXML_SUCCESS) {
360  imagePtr->setXShift(xOffset);
361  }
362 
363  int yOffset = 0;
364  success = imageElement->QueryIntAttribute("y_offset", &yOffset);
365 
366  if (success == TIXML_SUCCESS) {
367  imagePtr->setYShift(yOffset);
368  }
369 
370  int direction = 0;
371  success = imageElement->QueryIntAttribute("direction", &direction);
372 
373  if (success == TIXML_SUCCESS) {
374  ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
375 
376  if (objVisual) {
377  objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
378  }
379  }
380  }
381  }
382  }
383  }
384 
385  AtlasLoader* createDefaultAtlasLoader(Model* model, VFS* vfs, ImageManager* imageManager) {
386  return new AtlasLoader(model, vfs, imageManager);
387  }
388 }
bool Error() const
Definition: tinyxml.h:1456
int QueryIntAttribute(const char *name, int *_value) const
Definition: tinyxml.cpp:643
AtlasLoader * createDefaultAtlasLoader(Model *model, VFS *vfs, ImageManager *imageManager)
virtual const char * Parse(const char *p, TiXmlParsingData *data=0, TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
bool HasParentPath(const bfs::path &path)
bfs::path GetParentPath(const bfs::path &path)
const TiXmlElement * NextSiblingElement() const
Definition: tinyxml.cpp:461
const char * Attribute(const char *name) const
Definition: tinyxml.cpp:555
Definition: vfs.h:58
virtual void useSharedImage(const ImagePtr &shared, const Rect &region)=0
const TiXmlElement * RootElement() const
Definition: tinyxml.h:1448
const TiXmlElement * FirstChildElement() const
Convenience function to get through elements.
Definition: tinyxml.cpp:431