FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
objectloader.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 "util/log/logger.h"
32 #include "model/model.h"
33 #include "model/metamodel/object.h"
34 #include "model/metamodel/action.h"
35 #include "vfs/fife_boost_filesystem.h"
36 #include "vfs/vfs.h"
37 #include "vfs/raw/rawdata.h"
38 #include "view/visual.h"
39 #include "video/imagemanager.h"
40 
41 #include "objectloader.h"
42 #include "animationloader.h"
43 
44 namespace FIFE {
45  static Logger _log(LM_NATIVE_LOADERS);
46 
47  ObjectLoader::ObjectLoader(Model* model, VFS* vfs, ImageManager* imageManager, const AnimationLoaderPtr& animationLoader)
48  : m_model(model), m_vfs(vfs), m_imageManager(imageManager) {
49  assert(m_model && m_vfs && m_imageManager);
50 
51  if (animationLoader) {
52  m_animationLoader = animationLoader;
53  }
54  else {
55  m_animationLoader.reset(new AnimationLoader(m_vfs, m_imageManager));
56  }
57  }
58 
59  ObjectLoader::~ObjectLoader() {
60 
61  }
62 
63  void ObjectLoader::setAnimationLoader(const AnimationLoaderPtr& animationLoader) {
64  assert(animationLoader);
65 
66  m_animationLoader = animationLoader;
67  }
68 
69  bool ObjectLoader::isLoadable(const std::string& filename) const {
70  bfs::path objectPath(filename);
71 
72  TiXmlDocument objectFile;
73 
74  try {
75  RawData* data = m_vfs->open(objectPath.string());
76 
77  if (data) {
78  if (data->getDataLength() != 0) {
79  objectFile.Parse(data->readString(data->getDataLength()).c_str());
80 
81  if (objectFile.Error()) {
82  std::ostringstream oss;
83  oss << " Failed to load"
84  << objectPath.string()
85  << " : " << __FILE__
86  << " [" << __LINE__ << "]"
87  << std::endl;
88  FL_ERR(_log, oss.str());
89 
90  return false;
91  }
92  }
93  else {
94  std::ostringstream oss;
95  oss << " Failed to load"
96  << objectPath.string()
97  << " : " << __FILE__
98  << " [" << __LINE__ << "]"
99  << std::endl;
100  FL_ERR(_log, oss.str());
101 
102  return false;
103  }
104 
105  // done with data delete resource
106  delete data;
107  data = 0;
108  }
109  else {
110  std::ostringstream oss;
111  oss << " Failed to load"
112  << objectPath.string()
113  << " : " << __FILE__
114  << " [" << __LINE__ << "]"
115  << std::endl;
116  FL_ERR(_log, oss.str());
117 
118  return false;
119  }
120  }
121  catch (NotFound&) {
122  std::ostringstream oss;
123  oss << " Failed to load"
124  << objectPath.string()
125  << " : " << __FILE__
126  << " [" << __LINE__ << "]"
127  << std::endl;
128  FL_ERR(_log, oss.str());
129 
130  // TODO - should we abort here
131  // or rethrow the exception
132  // or just keep going
133 
134  return false;
135  }
136 
137  // if we get here then loading the file went well
138  TiXmlElement* root = objectFile.RootElement();
139 
140  if (root && root->ValueStr() == "object") {
141  return true;
142  }
143  else {
144  return false;
145  }
146  }
147 
148  void ObjectLoader::load(const std::string& filename) {
149  bfs::path objectPath(filename);
150 
151  TiXmlDocument objectFile;
152 
153  try {
154  RawData* data = m_vfs->open(objectPath.string());
155 
156  if (data) {
157  if (data->getDataLength() != 0) {
158  objectFile.Parse(data->readString(data->getDataLength()).c_str());
159 
160  if (objectFile.Error()) {
161  return;
162  }
163  }
164 
165  // done with data delete resource
166  delete data;
167  data = 0;
168  }
169  }
170  catch (NotFound&) {
171  std::ostringstream oss;
172  oss << " Failed to load"
173  << objectPath.string()
174  << " : " << __FILE__
175  << " [" << __LINE__ << "]"
176  << std::endl;
177  FL_ERR(_log, oss.str());
178 
179  // TODO - should we abort here
180  // or rethrow the exception
181  // or just keep going
182 
183  return;
184  }
185 
186  // if we get here then loading the file went well
187  TiXmlElement* root = objectFile.RootElement();
188 
189  if (root && root->ValueStr() == "object") {
190  const std::string* objectId = root->Attribute(std::string("id"));
191  const std::string* namespaceId = root->Attribute(std::string("namespace"));
192 
193  Object* obj = NULL;
194  if (objectId && namespaceId) {
195  const std::string* parentId = root->Attribute(std::string("parent"));
196 
197  if (parentId) {
198  Object* parent = m_model->getObject(*parentId, *namespaceId);
199  if (parent) {
200  try {
201  obj = m_model->createObject(*objectId, *namespaceId, parent);
202  }
203  catch (NameClash&) {
204  // TODO - handle exception
205  assert(false);
206  }
207  }
208  }
209  else {
210  // this will make sure the object has not already been loaded
211  if (m_model->getObject(*objectId, *namespaceId) == NULL) {
212  try {
213  obj = m_model->createObject(*objectId, *namespaceId);
214  }
215  catch (NameClash &e) {
216  FL_ERR(_log, e.what());
217 
218  // TODO - handle exception
219  assert(false);
220  }
221  }
222  }
223  }
224 
225  if (obj) {
226  obj->setFilename(objectPath.string());
227  ObjectVisual::create(obj);
228 
229  int isBlocking = 0;
230  root->QueryIntAttribute("blocking", &isBlocking);
231  obj->setBlocking(isBlocking!=0);
232 
233  int isStatic = 0;
234  root->QueryIntAttribute("static", &isStatic);
235  obj->setStatic(isStatic!=0);
236 
237  const std::string* pather = root->Attribute(std::string("pather"));
238 
239  if (pather) {
240  obj->setPather(m_model->getPather(*pather));
241  }
242  else {
243  obj->setPather(m_model->getPather("RoutePather"));
244  }
245 
246  // loop over all image tags
247  for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
248  const std::string* sourceId = imageElement->Attribute(std::string("source"));
249 
250  if (sourceId) {
251  bfs::path imagePath(filename);
252 
253  if (HasParentPath(imagePath)) {
254  imagePath = GetParentPath(imagePath) / *sourceId;
255  } else {
256  imagePath = bfs::path(*sourceId);
257  }
258 
259  ImagePtr imagePtr;
260  if(!m_imageManager->exists(imagePath.string())) {
261  imagePtr = m_imageManager->create(imagePath.string());
262  }
263  else {
264  imagePtr = m_imageManager->getPtr(imagePath.string());
265  }
266 
267  if (imagePtr) {
268  int xOffset = 0;
269  int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
270 
271  if (success == TIXML_SUCCESS) {
272  imagePtr->setXShift(xOffset);
273  }
274 
275  int yOffset = 0;
276  success = imageElement->QueryIntAttribute("y_offset", &yOffset);
277 
278  if (success == TIXML_SUCCESS) {
279  imagePtr->setYShift(yOffset);
280  }
281 
282  int direction = 0;
283  success = imageElement->QueryIntAttribute("direction", &direction);
284 
285  if (success == TIXML_SUCCESS) {
286  ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
287 
288  if (objVisual) {
289  objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
290  }
291  }
292  }
293  }
294  }
295 
296  for (TiXmlElement* actionElement = root->FirstChildElement("action"); actionElement; actionElement = actionElement->NextSiblingElement("action")) {
297  const std::string* actionId = actionElement->Attribute(std::string("id"));
298 
299  if (actionId) {
300  Action* action = obj->createAction(*actionId);
301  ActionVisual::create(action);
302 
303  for (TiXmlElement* animElement = actionElement->FirstChildElement("animation"); animElement; animElement = animElement->NextSiblingElement("animation")) {
304  const std::string* sourceId = animElement->Attribute(std::string("atlas"));
305  if(sourceId) {
306  bfs::path atlasPath(filename);
307 
308  if (HasParentPath(atlasPath)) {
309  atlasPath = GetParentPath(atlasPath) / *sourceId;
310  } else {
311  atlasPath = bfs::path(*sourceId);
312  }
313 
314  ImagePtr atlasImgPtr;
315  // we need to load this since its shared image
316  if(!m_imageManager->exists(atlasPath.string())) {
317  atlasImgPtr = m_imageManager->create(atlasPath.string());
318  }
319  else {
320  atlasImgPtr = m_imageManager->getPtr(atlasPath.string());
321  }
322 
323  int animFrames = 0;
324  int animDelay = 0;
325  int animXoffset = 0;
326  int animYoffset = 0;
327  int frameWidth = 0;
328  int frameHeight = 0;
329 
330  animElement->QueryValueAttribute("width", &frameWidth);
331  animElement->QueryValueAttribute("height", &frameHeight);
332  animElement->QueryValueAttribute("frames", &animFrames);
333  animElement->QueryValueAttribute("delay", &animDelay);
334  animElement->QueryValueAttribute("x_offset", &animXoffset);
335  animElement->QueryValueAttribute("y_offset", &animYoffset);
336  int nDir = 0;
337 
338  for (TiXmlElement* dirElement = animElement->FirstChildElement("direction");
339  dirElement; dirElement = dirElement->NextSiblingElement("direction")) {
340  AnimationPtr animation(new Animation);
341 
342  int dir;
343  dirElement->QueryIntAttribute("dir", &dir);
344 
345  int frames;
346  int success;
347 
348  success = dirElement->QueryValueAttribute("frames", &frames);
349  if(success != TIXML_SUCCESS) {
350  frames = animFrames;
351  }
352 
353  int delay;
354  success = dirElement->QueryValueAttribute("delay", &delay);
355  if(success != TIXML_SUCCESS) {
356  delay = animDelay;
357  }
358 
359  int xoffset;
360  success = dirElement->QueryValueAttribute("x_offset", &xoffset);
361  if(success != TIXML_SUCCESS) {
362  xoffset = animXoffset;
363  }
364 
365  int yoffset;
366  success = dirElement->QueryValueAttribute("y_offset", &yoffset);
367  if(success != TIXML_SUCCESS) {
368  yoffset = animYoffset;
369  }
370 
371  int action_frame;
372  success = dirElement->QueryValueAttribute("action", &action_frame);
373  if(success == TIXML_SUCCESS) {
374  animation->setActionFrame(action_frame);
375  }
376 
377  for (int iframe = 0; iframe < frames; ++iframe) {
378  static char tmpBuf[64];
379  sprintf(tmpBuf, "%03d:%04d", dir, iframe);
380 
381  std::string frameId = *objectId + ":" + *actionId + ":" + std::string(tmpBuf);
382 
383  ImagePtr framePtr;
384  if (!m_imageManager->exists(frameId)) {
385  framePtr = m_imageManager->create(frameId);
386  Rect region(
387  frameWidth * iframe, frameHeight * nDir, frameWidth, frameHeight
388  );
389  framePtr->useSharedImage(atlasImgPtr, region);
390  framePtr->setXShift(xoffset);
391  framePtr->setYShift(yoffset);
392  }
393  else {
394  framePtr = m_imageManager->getPtr(frameId);
395  }
396  animation->addFrame(framePtr, delay);
397  }
398 
399  ActionVisual* actionVisual = action->getVisual<ActionVisual>();
400  if(actionVisual) {
401  actionVisual->addAnimation(dir, animation);
402  action->setDuration(animation->getDuration());
403  }
404  ++nDir;
405  }
406 
407  } else {
408  sourceId = animElement->Attribute(std::string("source"));
409  if (sourceId) {
410  bfs::path animPath(filename);
411 
412  if (HasParentPath(animPath)) {
413  animPath = GetParentPath(animPath) / *sourceId;
414  } else {
415  animPath = bfs::path(*sourceId);
416  }
417 
418  AnimationPtr animation;
419  if (m_animationLoader && m_animationLoader->isLoadable(animPath.string())) {
420  animation = m_animationLoader->load(animPath.string());
421  }
422 
423  int direction = 0;
424  int success = animElement->QueryIntAttribute("direction", &direction);
425 
426  if (action && animation) {
427  ActionVisual* actionVisual = action->getVisual<ActionVisual>();
428 
429  if (actionVisual) {
430  actionVisual->addAnimation(direction, animation);
431  action->setDuration(animation->getDuration());
432  }
433  }
434  }
435  }
436  }
437  }
438  }
439  }
440  }
441  }
442 
443 }