FIFE  be64c707dea6b3250bd4355bf5c825d25920087d
atlasloader.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2019 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 #include <tinyxml.h>
26 
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
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 "video/animationmanager.h"
41 #include "view/visual.h"
42 
43 #include "atlasloader.h"
44 
45 namespace FIFE {
49  static Logger _log(LM_NATIVE_LOADERS);
50 
51 
52  size_t Atlas::getImageCount() const {
53  return m_subimages.size();
54  }
55 
57  return m_image;
58  }
59 
60  ImagePtr Atlas::getImage(const std::string& id) {
61  SubimageMap::iterator iter = m_subimages.find(id);
62  if(iter == m_subimages.end())
63  return ImagePtr();
64  return iter->second.image;
65  }
66 
68  if(index > getImageCount())
69  return ImagePtr();
70 
71  SubimageMap::iterator iter = m_subimages.begin();
72  for(uint32_t i = 0; i < index; ++i, ++iter);
73  return iter->second.image;
74  }
75 
76  bool Atlas::addImage(const std::string& imagename, const AtlasData& data) {
77  return m_subimages.insert(std::pair<std::string, AtlasData>(imagename, data)).second;
78  }
79 
80  void Atlas::setPackedImage(const ImagePtr& image) {
81  m_image = image;
82  }
83 
84  const std::string& Atlas::getName() const {
85  return m_name;
86  }
87 
88  AtlasLoader::AtlasLoader(Model* model, VFS* vfs, ImageManager* imageManager, AnimationManager* animationManager)
89  : m_model(model), m_vfs(vfs), m_imageManager(imageManager), m_animationManager(animationManager) {
90  }
91 
93  }
94 
95  bool AtlasLoader::isLoadable(const std::string& filename) {
96  bfs::path atlasPath(filename);
97  std::string atlasFilename = atlasPath.string();
98  TiXmlDocument atlasFile;
99 
100  try {
101  RawData* data = m_vfs->open(atlasFilename);
102 
103  if (data) {
104  if (data->getDataLength() != 0) {
105  atlasFile.Parse(data->readString(data->getDataLength()).c_str());
106 
107  if (atlasFile.Error()) {
108  return false;
109  }
110  } else {
111  return false;
112  }
113 
114  // done with data delete resource
115  delete data;
116  data = 0;
117  }
118  } catch (NotFound&) {
119  return false;
120  }
121 
122  // if we get here then loading the file went well
123  TiXmlElement* root = atlasFile.RootElement();
124 
125  if (root && root->ValueStr() == "assets") {
126  if (root->FirstChildElement("atlas")) {
127  return true;
128  }
129  }
130 
131  return false;
132  }
133 
134  AtlasPtr AtlasLoader::load(const std::string& filename) {
135  bfs::path atlasPath(filename);
136  bfs::path atlasPathDirectory;
137  std::string atlasFilename = atlasPath.string();
138 
139  if (HasParentPath(atlasPath)) {
140  // save the directory where the atlas file is located
141  atlasPathDirectory = GetParentPath(atlasPath);
142  }
143 
144  TiXmlDocument doc;
145  AtlasPtr atlas;
146 
147  try {
148  RawData* data = m_vfs->open(atlasFilename);
149 
150  if (data) {
151  if (data->getDataLength() != 0) {
152  doc.Parse(data->readString(data->getDataLength()).c_str());
153 
154  if (doc.Error()) {
155  return atlas;
156  }
157 
158  // done with data delete resource
159  delete data;
160  data = 0;
161  }
162  }
163  }
164  catch (NotFound& e) {
165  FL_ERR(_log, e.what());
166 
167  // TODO - should we abort here
168  // or rethrow the exception
169  // or just keep going
170 
171  return atlas;
172  }
173 
174  // if we get here then everything loaded properly
175  // so we can just parse out the contents
176  TiXmlElement* root = doc.RootElement();
177 
178  if (root && root->ValueStr() == "assets") {
179  atlas = loadAtlas(filename, root->FirstChildElement("atlas"));
180  }
181 
182  return atlas;
183  }
184 
185  std::vector<AtlasPtr> AtlasLoader::loadMultiple(const std::string& filename) {
186  bfs::path atlasPath(filename);
187  bfs::path atlasPathDirectory;
188  std::string atlasFilename = atlasPath.string();
189 
190  if (HasParentPath(atlasPath)) {
191  // save the directory where the atlas file is located
192  atlasPathDirectory = GetParentPath(atlasPath);
193  }
194 
195  TiXmlDocument doc;
196  std::vector<AtlasPtr> atlasVector;
197 
198  try {
199  RawData* data = m_vfs->open(atlasFilename);
200 
201  if (data) {
202  if (data->getDataLength() != 0) {
203  doc.Parse(data->readString(data->getDataLength()).c_str());
204 
205  if (doc.Error()) {
206  return atlasVector;
207  }
208 
209  // done with data delete resource
210  delete data;
211  data = 0;
212  }
213  }
214  }
215  catch (NotFound& e) {
216  FL_ERR(_log, e.what());
217 
218  // TODO - should we abort here
219  // or rethrow the exception
220  // or just keep going
221 
222  return atlasVector;
223  }
224 
225  // if we get here then everything loaded properly
226  // so we can just parse out the contents
227  TiXmlElement* root = doc.RootElement();
228 
229  if (root && root->ValueStr() == "assets") {
230  for (TiXmlElement* atlasElem = root->FirstChildElement("atlas"); atlasElem; atlasElem = atlasElem->NextSiblingElement("atlas")) {
231  AtlasPtr atlas = loadAtlas(filename, atlasElem);
232  if (atlas) {
233  atlasVector.push_back(atlas);
234  }
235  }
236  }
237 
238  return atlasVector;
239  }
240 
241  AtlasPtr AtlasLoader::loadAtlas(const std::string& filename, TiXmlElement* atlasElem) {
242  AtlasPtr atlas;
243  if (!atlasElem) {
244  return atlas;
245  }
246 
247  const std::string* atlasSource = atlasElem->Attribute(std::string("source"));
248  if (atlasSource) {
249  const std::string* atlasId = atlasElem->Attribute(std::string("id"));
250 
251  bfs::path atlasPath(filename);
252  bfs::path atlasPathDirectory;
253  if (HasParentPath(atlasPath)) {
254  // save the directory where the atlas file is located
255  atlasPathDirectory = GetParentPath(atlasPath);
256  }
257 
258  // Atlas itself doesn't have appended id
259  bfs::path atlasImagePath = atlasPathDirectory / *atlasSource;
260  atlas.reset(new Atlas(atlasImagePath.string()));
261 
262  // End-user could create the same atlas for the second time.
263  // Since we don't hold any data for Atlases like ImageManager we need to recreate
264  // atlas parameters (to return proper AtlasPtr) but don't reload pixel data (they are held by ImageManager).
265  if (!m_imageManager->exists(atlas->getName())) {
266  atlas->setPackedImage(m_imageManager->create(atlas->getName()));
267  } else {
268  atlas->setPackedImage(m_imageManager->getPtr(atlas->getName()));
269  }
270  // Create subimages with given id and individual position and size
271  if (atlasElem->FirstChildElement("subimage")) {
272  for (TiXmlElement* imageElem = atlasElem->FirstChildElement("subimage");
273  imageElem != 0; imageElem = imageElem->NextSiblingElement("subimage")) {
274 
275  const std::string* subimageId = imageElem->Attribute(std::string("id"));
276  if (subimageId) {
277  Rect region;
278  imageElem->QueryValueAttribute("xpos", &region.x);
279  imageElem->QueryValueAttribute("ypos", &region.y);
280  imageElem->QueryValueAttribute("width", &region.w);
281  imageElem->QueryValueAttribute("height", &region.h);
282 
283  std::string finalname;
284  // atlas id is optional here
285  if (atlasId) {
286  finalname = *atlasId + ":" + *subimageId;
287  } else {
288  finalname = *subimageId;
289  }
290  ImagePtr subImage;
291 
292  if (!m_imageManager->exists(finalname)) {
293  subImage = m_imageManager->create(finalname);
294  } else {
295  subImage = m_imageManager->getPtr(finalname);
296  }
297  subImage->useSharedImage(atlas->getPackedImage(), region);
298 
299  AtlasData atlasData = {region, subImage};
300  atlas->addImage(finalname, atlasData);
301  }
302  }
303  } else {
304  // Create subimages with automatic id and same size
305  int frame = 0;
306  int atlasWidth = 0;
307  int atlasHeight = 0;
308  int subimageWidth = 0;
309  int subimageHeight = 0;
310  atlasElem->QueryValueAttribute("atlas_width", &atlasWidth);
311  atlasElem->QueryValueAttribute("atlas_height", &atlasHeight);
312  atlasElem->QueryValueAttribute("subimage_width", &subimageWidth);
313  atlasElem->QueryValueAttribute("subimage_height", &subimageHeight);
314  // file extension of the atlas is also used as subimage extension
315  std::string extension = bfs::extension(*atlasSource);
316  // we need an atlas id
317  if (!atlasId) {
318  atlasId = atlasSource;
319  }
320 
321  if (atlasWidth != 0 && atlasHeight != 0 && subimageWidth != 0 && subimageHeight != 0) {
322  int x_rows = atlasWidth / subimageWidth;
323  int y_rows = atlasHeight / subimageHeight;
324  Rect region(0, 0, subimageWidth, subimageHeight);
325  for (int y = 0; y < y_rows; ++y) {
326  region.y = y * subimageHeight;
327  for (int x = 0; x < x_rows; ++x) {
328  region.x = x * subimageWidth;
329 
330  static char tmp[64];
331  snprintf(tmp, 64, "%04d", frame);
332  std::ostringstream finalname;
333  finalname << *atlasId << ":" << std::string(tmp) << extension;
334 
335  ImagePtr subImage;
336  if (!m_imageManager->exists(finalname.str())) {
337  subImage = m_imageManager->create(finalname.str());
338  } else {
339  subImage = m_imageManager->getPtr(finalname.str());
340  }
341  subImage->useSharedImage(atlas->getPackedImage(), region);
342 
343  AtlasData atlasData = {region, subImage};
344  atlas->addImage(finalname.str(), atlasData);
345 
346  ++frame;
347  }
348  }
349  }
350  }
351  }
352 
353  return atlas;
354  }
355 
356  AtlasLoader* createDefaultAtlasLoader(Model* model, VFS* vfs, ImageManager* imageManager, AnimationManager* animationManager) {
357  return new AtlasLoader(model, vfs, imageManager, animationManager);
358  }
359 }
virtual ImagePtr create(IResourceLoader *loader=0)
Creates a blank Image but does not load it immediately.
size_t getImageCount() const
Returns the number of subimages that belongs to this atlas.
Definition: atlasloader.cpp:52
virtual ~AtlasLoader()
Definition: atlasloader.cpp:92
ImagePtr m_image
Definition: atlasloader.h:89
virtual bool exists(const std::string &name)
Checks to see if an Image exists.
ImageManager.
Definition: imagemanager.h:54
T h
Height of the rectangle.
Definition: rect.h:93
ImagePtr & getPackedImage()
Returns an (packed) Image for this atlas.
Definition: atlasloader.cpp:56
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
AtlasLoader * createDefaultAtlasLoader(Model *model, VFS *vfs, ImageManager *imageManager, AnimationManager *animationManager)
convenience function for creating the default fife atlas loader deleting the object returned from thi...
virtual bool isLoadable(const std::string &filename)
Definition: atlasloader.cpp:95
RawData * open(const std::string &path)
Open a file.
Definition: vfs.cpp:172
static Logger _log(LM_AUDIO)
SharedPtr< Image > ImagePtr
Definition: image.h:43
virtual ImagePtr getPtr(const std::string &name)
#define FL_ERR(logger, msg)
Definition: logger.h:73
uint32_t getDataLength() const
get the complete datalength
Definition: rawdata.cpp:75
AnimationManager.
bool HasParentPath(const bfs::path &path)
Helper function to determine if a path object has a parent path.
ImageManager * m_imageManager
Definition: atlasloader.h:121
bfs::path GetParentPath(const bfs::path &path)
Helper function to retrieve a parent path object from a path object.
const std::string & getName() const
Definition: atlasloader.cpp:84
virtual AtlasPtr load(const std::string &filename)
void setPackedImage(const ImagePtr &image)
Sets the image for atlas to use it for rendering.
Definition: atlasloader.cpp:80
AtlasLoader(Model *model, VFS *vfs, ImageManager *imageManager, AnimationManager *animationManager)
Definition: atlasloader.cpp:88
std::string m_name
Definition: atlasloader.h:92
A model is a facade for everything in the model.
Definition: model.h:54
T y
The Y Coordinate.
Definition: rect.h:87
SubimageMap m_subimages
Definition: atlasloader.h:88
AtlasPtr loadAtlas(const std::string &filename, TiXmlElement *atlasElem)
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
the main VFS (virtual file system) class
Definition: vfs.h:58
ImagePtr getImage(const std::string &id)
Return an Image of given id.
Definition: atlasloader.cpp:60
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.
unsigned int uint32_t
Definition: core.h:40
virtual std::vector< AtlasPtr > loadMultiple(const std::string &filename)
T w
Width of the rectangle.
Definition: rect.h:90
bool addImage(const std::string &imagename, const AtlasData &data)
Adds new information about subimage that belongs to this atlas.
Definition: atlasloader.cpp:76
Used to access diffrent kinds of data.
Definition: rawdata.h:48