FIFE
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
atlasloader.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2013 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"
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"
40 #include "view/visual.h"
41 
42 #include "atlasloader.h"
43 
44 namespace FIFE {
48  static Logger _log(LM_NATIVE_LOADERS);
49 
50 
51  size_t Atlas::getImageCount() const {
52  return m_subimages.size();
53  }
54 
56  return m_image;
57  }
58 
59  ImagePtr Atlas::getImage(const std::string& id) {
60  SubimageMap::iterator iter = m_subimages.find(id);
61  if(iter == m_subimages.end())
62  return ImagePtr();
63  return iter->second.image;
64  }
65 
67  if(index > getImageCount())
68  return ImagePtr();
69 
70  SubimageMap::iterator iter = m_subimages.begin();
71  for(uint32_t i = 0; i < index; ++i, ++iter);
72  return iter->second.image;
73  }
74 
75  bool Atlas::addImage(const std::string& imagename, const AtlasData& data) {
76  return m_subimages.insert(std::pair<std::string, AtlasData>(imagename, data)).second;
77  }
78 
79  void Atlas::setPackedImage(const ImagePtr& image) {
80  m_image = image;
81  }
82 
83  const std::string& Atlas::getName() const {
84  return m_name;
85  }
86 
87  AtlasLoader::AtlasLoader(Model* model, VFS* vfs, ImageManager* imageManager)
88  : m_model(model), m_vfs(vfs), m_imageManager(imageManager) {
89  }
90 
92  }
93 
94  bool AtlasLoader::isLoadable(const std::string& filename) {
95  bfs::path atlasPath(filename);
96  std::string atlasFilename = atlasPath.string();
97  TiXmlDocument atlasFile;
98 
99  try {
100  RawData* data = m_vfs->open(atlasFilename);
101 
102  if (data) {
103  if (data->getDataLength() != 0) {
104  atlasFile.Parse(data->readString(data->getDataLength()).c_str());
105 
106  if (atlasFile.Error()) {
107  return false;
108  }
109  } else {
110  return false;
111  }
112 
113  // done with data delete resource
114  delete data;
115  data = 0;
116  }
117  } catch (NotFound&) {
118  return false;
119  }
120 
121  // if we get here then loading the file went well
122  TiXmlElement* root = atlasFile.RootElement();
123 
124  if (root && root->ValueStr() == "atlas") {
125  return true;
126  }
127  else {
128  return false;
129  }
130  }
131 
132  AtlasPtr AtlasLoader::load(const std::string& filename) {
133  bfs::path atlasPath(filename);
134  bfs::path atlasPathDirectory;
135  m_atlasFilename = atlasPath.string();
136 
137  if (HasParentPath(atlasPath)) {
138  // save the directory where the atlas file is located
139  atlasPathDirectory = GetParentPath(atlasPath);
140  }
141 
142  TiXmlDocument doc;
143  AtlasPtr atlas;
144 
145  try {
146  RawData* data = m_vfs->open(m_atlasFilename);
147 
148  if (data) {
149  if (data->getDataLength() != 0) {
150  doc.Parse(data->readString(data->getDataLength()).c_str());
151 
152  if (doc.Error()) {
153  return atlas;
154  }
155 
156  // done with data delete resource
157  delete data;
158  data = 0;
159  }
160  }
161  }
162  catch (NotFound& e) {
163  FL_ERR(_log, e.what());
164 
165  // TODO - should we abort here
166  // or rethrow the exception
167  // or just keep going
168 
169  return atlas;
170  }
171 
172  // if we get here then everything loaded properly
173  // so we can just parse out the contents
174  TiXmlElement* root = doc.RootElement();
175 
176  if (root && root->ValueStr() == "atlas") {
177  const std::string* atlasName = root->Attribute(std::string("name"));
178  if(atlasName) {
179  const std::string* namespaceId = root->Attribute(std::string("namespace"));
180  if(!namespaceId) {
181  namespaceId = atlasName;
182  }
183 
184  // Atlas itself doesn't have appended namespace
185  bfs::path atlasImagePath = atlasPathDirectory / *atlasName;
186  atlas.reset(new Atlas(atlasImagePath.string()));
187 
188  // End-user could create the same atlas for the second time.
189  // Since we don't hold any data for Atlases like ImageManager we need to recreate
190  // atlas parameters (to return proper AtlasPtr) but don't reload pixel data (they are held by ImageManager).
191 
192  bool atlasExists = m_imageManager->exists(atlas->getName());
193 
194  if(!atlasExists) {
195  atlas->setPackedImage(m_imageManager->create(atlas->getName()));
196  }
197  else {
198  atlas->setPackedImage(m_imageManager->getPtr(atlas->getName()));
199  }
200 
201  // We don't really need this now, though we could use it to assert if the loaded atlas is the same sized as these
202  //int atlasWidth, atlasHeight;
203  //root->QueryValueAttribute("width", &atlasWidth);
204  //root->QueryValueAttribute("height", &atlasHeight);
205  bool subsExists = true;
206  for (TiXmlElement* imageElem = root->FirstChildElement("image");
207  imageElem != 0; imageElem = imageElem->NextSiblingElement("image")) {
208 
209  Rect region;
210  imageElem->QueryValueAttribute("xpos", &region.x);
211  imageElem->QueryValueAttribute("ypos", &region.y);
212  imageElem->QueryValueAttribute("width", &region.w);
213  imageElem->QueryValueAttribute("height", &region.h);
214 
215  const std::string* subimageName = imageElem->Attribute(std::string("source"));
216 
217  if (subimageName) {
218  std::string finalname = *namespaceId + ":" +*subimageName;
219  ImagePtr subImage;
220 
221  bool subExists = m_imageManager->exists(finalname);
222  if (!subExists) {
223  subsExists = false;
224  subImage = m_imageManager->create(finalname);
225  }
226  else {
227  subImage = m_imageManager->getPtr(finalname);
228  }
229  subImage->useSharedImage(atlas->getPackedImage(), region);
230 
231  AtlasData atlas_data = {region, subImage};
232  atlas->addImage(finalname, atlas_data);
233  }
234  }
235  subsExists = subsExists && atlasExists;
236 
237  // Now parse object definition
238  for(TiXmlElement* objElem = root->NextSiblingElement("object");
239  objElem != 0; objElem = objElem->NextSiblingElement("object"))
240  {
241  // sanity check
242  if(objElem->ValueStr() == "object") {
243  parseObject(atlas.get(), objElem, subsExists);
244  }
245  }
246  }
247  }
248 
249  return atlas;
250  }
251 
252  void AtlasLoader::parseObject(Atlas* atlas, TiXmlElement* root, bool exists) {
253  const std::string* objectId = root->Attribute(std::string("id"));
254  const std::string* namespaceId = root->Attribute(std::string("namespace"));
255 
256  Object* obj = NULL;
257  if (objectId && namespaceId) {
258  const std::string* parentId = root->Attribute(std::string("parent"));
259 
260  if (parentId) {
261  Object* parent = m_model->getObject(*parentId, *namespaceId);
262  if (parent) {
263  try {
264  obj = m_model->createObject(*objectId, *namespaceId, parent);
265  }
266  catch (NameClash&) {
267  // TODO - handle exception
268  assert(false);
269  }
270  }
271  }
272  else {
273  // this will make sure the object has not already been loaded
274  if (m_model->getObject(*objectId, *namespaceId) == NULL) {
275  try {
276  obj = m_model->createObject(*objectId, *namespaceId);
277  }
278  catch (NameClash&) {
279  // TODO - handle exception
280  assert(false);
281  }
282  // if atlas or subimage was recreated then we have to update the ObjectVisual
283  } else if (!exists) {
284  obj = m_model->getObject(*objectId, *namespaceId);
285  ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
286  // make sure obj have visual
287  if (!objVisual) {
288  objVisual = ObjectVisual::create(obj);
289  }
290 
291  for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
292  const std::string* sourceId = imageElement->Attribute(std::string("source"));
293 
294  if (sourceId) {
295  std::string source = *namespaceId + ":" + *sourceId;
296  if(!m_imageManager->exists(source)) {
297  throw NotFound(source + " couldn't be found.");
298  }
299  ImagePtr imagePtr = m_imageManager->getPtr(source);
300 
301  int xOffset = 0;
302  int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
303  if (success == TIXML_SUCCESS) {
304  imagePtr->setXShift(xOffset);
305  }
306 
307  int yOffset = 0;
308  success = imageElement->QueryIntAttribute("y_offset", &yOffset);
309  if (success == TIXML_SUCCESS) {
310  imagePtr->setYShift(yOffset);
311  }
312 
313  int direction = 0;
314  success = imageElement->QueryIntAttribute("direction", &direction);
315  if (success == TIXML_SUCCESS) {
316  if (objVisual) {
317  objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
318  }
319  }
320  }
321  }
322  return;
323  }
324  }
325  }
326 
327  if (obj) {
328  //obj->setFilename(atlas->getName());
331 
332  int isBlocking = 0;
333  root->QueryIntAttribute("blocking", &isBlocking);
334  obj->setBlocking(isBlocking!=0);
335 
336  int isStatic = 0;
337  root->QueryIntAttribute("static", &isStatic);
338  obj->setStatic(isStatic!=0);
339 
340  const std::string* pather = root->Attribute(std::string("pather"));
341 
342  if (pather) {
343  obj->setPather(m_model->getPather(*pather));
344  }
345  else {
346  obj->setPather(m_model->getPather("RoutePather"));
347  }
348 
349  const std::string* costId = root->Attribute(std::string("cost_id"));
350  if (costId) {
351  obj->setCostId(*costId);
352  double cost = 1.0;
353  int success = root->QueryDoubleAttribute("cost", &cost);
354  if (success == TIXML_SUCCESS) {
355  obj->setCost(cost);
356  }
357  }
358 
359  const std::string* areaId = root->Attribute(std::string("area_id"));
360  if (areaId) {
361  obj->setArea(*areaId);
362  }
363 
364  // loop over all walkable areas
365  for (TiXmlElement* walkableElement = root->FirstChildElement("walkable_area"); walkableElement; walkableElement = walkableElement->NextSiblingElement("walkable_area")) {
366  const std::string* walkableId = walkableElement->Attribute(std::string("id"));
367  if (walkableId) {
368  obj->addWalkableArea(*walkableId);
369  }
370  }
371 
372  int cellStack = 0;
373  root->QueryIntAttribute("cellstack", &cellStack);
374  obj->setCellStackPosition(cellStack);
375 
376  double ax = 0;
377  double ay = 0;
378  double az = 0;
379 
380  int xRetVal = root->QueryValueAttribute("anchor_x", &ax);
381  int yRetVal = root->QueryValueAttribute("anchor_y", &ay);
382  if (xRetVal == TIXML_SUCCESS && yRetVal == TIXML_SUCCESS) {
383  obj->setRotationAnchor(ExactModelCoordinate(ax, ay, az));
384  }
385 
386  int isRestrictedRotation = 0;
387  root->QueryIntAttribute("restricted_rotation", &isRestrictedRotation);
388  obj->setRestrictedRotation(isRestrictedRotation!=0);
389 
390  int zStep = 0;
391  int zRetVal = root->QueryIntAttribute("z_step_limit", &zStep);
392  if (zRetVal == TIXML_SUCCESS) {
393  obj->setZStepRange(zStep);
394  }
395 
396  // loop over all multi parts
397  for (TiXmlElement* multiElement = root->FirstChildElement("multipart"); multiElement; multiElement = multiElement->NextSiblingElement("multipart")) {
398  const std::string* partId = multiElement->Attribute(std::string("id"));
399  if (partId) {
400  obj->addMultiPartId(*partId);
401  }
402  for (TiXmlElement* multiRotation = multiElement->FirstChildElement("rotation"); multiRotation; multiRotation = multiRotation->NextSiblingElement("rotation")) {
403  int rotation = 0;
404  multiRotation->QueryIntAttribute("rot", &rotation);
405  // relative coordinates which are used to position the object
406  for (TiXmlElement* multiCoordinate = multiRotation->FirstChildElement("occupied_coord"); multiCoordinate; multiCoordinate = multiCoordinate->NextSiblingElement("occupied_coord")) {
407  int x = 0;
408  int y = 0;
409  xRetVal = multiCoordinate->QueryValueAttribute("x", &x);
410  yRetVal = multiCoordinate->QueryValueAttribute("y", &y);
411  if (xRetVal == TIXML_SUCCESS && yRetVal == TIXML_SUCCESS) {
412  int z = 0;
413  multiCoordinate->QueryIntAttribute("z", &z);
414  obj->addMultiPartCoordinate(rotation, ModelCoordinate(x, y, z));
415  }
416  }
417  }
418  }
419  // loop over all image tags
420  for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
421  const std::string* sourceId = imageElement->Attribute(std::string("source"));
422 
423  if (sourceId) {
424  std::string source = *namespaceId + ":" + *sourceId;
425  if(!m_imageManager->exists(source)) {
426  throw NotFound(source + " couldn't be found.");
427  }
428  ImagePtr imagePtr = m_imageManager->getPtr(source);
429  int xOffset = 0;
430  int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
431 
432  if (success == TIXML_SUCCESS) {
433  imagePtr->setXShift(xOffset);
434  }
435 
436  int yOffset = 0;
437  success = imageElement->QueryIntAttribute("y_offset", &yOffset);
438 
439  if (success == TIXML_SUCCESS) {
440  imagePtr->setYShift(yOffset);
441  }
442 
443  int direction = 0;
444  success = imageElement->QueryIntAttribute("direction", &direction);
445 
446  if (success == TIXML_SUCCESS) {
447  ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
448 
449  if (objVisual) {
450  objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
451  }
452  }
453  }
454  }
455  }
456  }
457 
459  return new AtlasLoader(model, vfs, imageManager);
460  }
461 }
virtual ImagePtr create(IResourceLoader *loader=0)
Creates a blank Image but does not load it immediately.
virtual ~AtlasLoader()
Definition: atlasloader.cpp:91
T * get() const
allows direct access to underlying pointer
Definition: sharedptr.h:155
ImagePtr m_image
Definition: atlasloader.h:88
virtual bool exists(const std::string &name)
Checks to see if an Image exists.
uint32_t getDataLength() const
get the complete datalength
Definition: rawdata.cpp:75
void setXShift(int32_t xshift)
Definition: image.h:114
ImageManager.
Definition: imagemanager.h:54
void setArea(const std::string &id)
Sets the area id that the instances of this object adds to their cells.
Definition: object.cpp:330
T h
Height of the rectangle.
Definition: rect.h:93
Object class.
Definition: object.h:51
ImagePtr & getPackedImage()
Returns an (packed) Image for this atlas.
Definition: atlasloader.cpp:55
T x
The X Coordinate.
Definition: rect.h:84
void reset(T *ptr=0)
reset this pointer to a null shared pointer this can be used to lower the reference count of the shar...
Definition: sharedptr.h:164
void setRotationAnchor(const ExactModelCoordinate &anchor)
Sets the rotation anchor for this multi object.
Definition: object.cpp:296
virtual bool isLoadable(const std::string &filename)
Definition: atlasloader.cpp:94
Object * createObject(const std::string &identifier, const std::string &name_space, Object *parent=0)
Add an object to the metamodel.
Definition: model.cpp:149
void setCellStackPosition(uint8_t position)
Sets the cell stack position.
Definition: object.cpp:169
AtlasLoader(Model *model, VFS *vfs, ImageManager *imageManager)
Definition: atlasloader.cpp:87
RawData * open(const std::string &path)
Open a file.
Definition: vfs.cpp:157
static Logger _log(LM_AUDIO)
void setZStepRange(int32_t zRange)
Sets z-step range for object.
Definition: object.cpp:322
void setFilename(const std::string &file)
Definition: object.cpp:161
SharedPtr< Image > ImagePtr
Definition: image.h:42
virtual ImagePtr getPtr(const std::string &name)
#define FL_ERR(logger, msg)
Definition: logger.h:73
AtlasLoader * createDefaultAtlasLoader(Model *model, VFS *vfs, ImageManager *imageManager)
convenience function for creating the default fife atlas loader deleting the object returned from thi...
bool HasParentPath(const bfs::path &path)
Helper function to determine if a path object has a parent path.
ImageManager * m_imageManager
Definition: atlasloader.h:113
bfs::path GetParentPath(const bfs::path &path)
Helper function to retrieve a parent path object from a path object.
T * getVisual() const
Gets used visualization.
Definition: object.h:122
Point3D ModelCoordinate
Definition: modelcoords.h:37
void parseObject(Atlas *atlas, TiXmlElement *root, bool exists)
virtual AtlasPtr load(const std::string &filename)
void setRestrictedRotation(bool restrict)
Sets the rotation to restricted.
Definition: object.cpp:304
void addMultiPartCoordinate(int32_t rotation, ModelCoordinate coord)
Adds rotationally dependent coordinates for this object part.
Definition: object.cpp:248
void setPackedImage(const ImagePtr &image)
Sets the image for atlas to use it for rendering.
Definition: atlasloader.cpp:79
std::string m_name
Definition: atlasloader.h:91
A model is a facade for everything in the model.
Definition: model.h:53
T y
The Y Coordinate.
Definition: rect.h:87
SubimageMap m_subimages
Definition: atlasloader.h:87
void setCost(double cost)
Sets the cost.
Definition: object.cpp:189
const std::string & getName() const
Definition: atlasloader.cpp:83
Object visual contains data that is needed for visualizing objects.
Definition: visual.h:65
std::string readString(size_t len)
read a string with len bytes, not assuming a terminating 0 Appends a null terminator character to the...
Definition: rawdata.cpp:128
DoublePoint3D ExactModelCoordinate
Definition: modelcoords.h:36
void addMultiPartId(const std::string &partId)
Adds a multi part identifier.
Definition: object.cpp:201
static ObjectVisual * create(Object *object)
Constructs and assigns it to the passed item.
Definition: visual.cpp:55
void addStaticImage(uint32_t angle, int32_t image_index)
Adds new static image with given angle (degrees) Static images are used in case there are no actions ...
Definition: visual.cpp:67
void setStatic(bool stat)
Set to true, if object is such that it doesn&#39;t move.
Definition: object.h:134
the main VFS (virtual file system) class
Definition: vfs.h:58
std::string m_atlasFilename
Definition: atlasloader.h:114
IPather * getPather(const std::string &pathername)
Returns pather corresponding given name.
Definition: model.cpp:81
ImagePtr getImage(const std::string &id)
Return an Image of given id.
Definition: atlasloader.cpp:59
virtual void useSharedImage(const ImagePtr &shared, const Rect &region)=0
After this call all image data will be taken from the given image and its subregion.
void addWalkableArea(const std::string &id)
Adds an area id to walkable area.
Definition: object.cpp:338
Object * getObject(const std::string &id, const std::string &name_space)
Get an object by its id.
Definition: model.cpp:224
void setPather(IPather *pather)
Sets pather used by instances created out of this object.
Definition: object.cpp:137
void setBlocking(bool blocking)
Sets if object blocks movement.
Definition: object.h:126
unsigned int uint32_t
Definition: core.h:40
void setYShift(int32_t yshift)
Definition: image.h:120
ResourceHandle getHandle()
Definition: resource.h:68
size_t getImageCount() const
Returns the number of subimages that belongs to this atlas.
Definition: atlasloader.cpp:51
T w
Width of the rectangle.
Definition: rect.h:90
void setCostId(const std::string &cost)
Sets the cost id.
Definition: object.cpp:181
bool addImage(const std::string &imagename, const AtlasData &data)
Adds new information about subimage that belongs to this atlas.
Definition: atlasloader.cpp:75
Used to access diffrent kinds of data.
Definition: rawdata.h:48