FIFE  2008.0
maploader.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2009 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 #include <string>
24 #include <vector>
25 
26 // 3rd party includes
27 
28 // FIFE includes
29 // These includes are split up in two parts, separated by one empty line
30 // First block: files included from the FIFE root src directory
31 // Second block: files included from the same folder
32 #include "ext/tinyxml/fife_tinyxml.h"
33 #include "model/model.h"
34 #include "model/structures/layer.h"
35 #include "model/structures/instance.h"
36 #include "model/metamodel/grids/cellgrid.h"
37 #include "model/metamodel/modelcoords.h"
38 #include "model/metamodel/action.h"
39 #include "vfs/fife_boost_filesystem.h"
40 #include "vfs/vfs.h"
41 #include "vfs/vfsdirectory.h"
42 #include "vfs/raw/rawdata.h"
43 #include "util/base/exception.h"
44 #include "util/log/logger.h"
45 #include "util/resource/resource.h"
46 #include "util/structures/rect.h"
47 #include "video/imagemanager.h"
48 #include "video/image.h"
49 #include "video/renderbackend.h"
50 #include "view/visual.h"
51 #include "view/camera.h"
52 #include "view/renderers/instancerenderer.h"
53 #include "util/base/stringutils.h"
54 
55 #include "atlasloader.h"
56 #include "maploader.h"
57 #include "animationloader.h"
58 #include "objectloader.h"
59 
60 namespace FIFE {
61  static Logger _log(LM_NATIVE_LOADERS);
62 
63  MapLoader::MapLoader(Model* model, VFS* vfs, ImageManager* imageManager, RenderBackend* renderBackend)
64  : m_model(model), m_vfs(vfs), m_imageManager(imageManager), m_renderBackend(renderBackend),
65  m_loaderName("fife"), m_mapDirectory("") {
66  AnimationLoaderPtr animationLoader(new AnimationLoader(m_vfs, m_imageManager));
67  m_objectLoader.reset(new ObjectLoader(m_model, m_vfs, m_imageManager, animationLoader));
68  m_atlasLoader.reset(new AtlasLoader(m_model, m_vfs, m_imageManager));
69  }
70 
71  MapLoader::~MapLoader() {
72 
73  }
74 
75  Map* MapLoader::load(const std::string& filename) {
76  Map* map = NULL;
77 
78  // reset percent done listener just in case
79  // it has residual data from last load
80  m_percentDoneListener.reset();
81 
82  bfs::path mapPath(filename);
83 
84  if (HasParentPath(mapPath)) {
85  if (GetParentPath(mapPath).string() != m_mapDirectory) {
86  // save the directory where the map file is located
87  m_mapDirectory = GetParentPath(mapPath).string();
88  }
89  }
90 
91  TiXmlDocument mapFile;
92 
93  std::string mapFilename = mapPath.string();
94 
95  try {
96  RawData* data = m_vfs->open(mapFilename);
97 
98  if (data) {
99  if (data->getDataLength() != 0) {
100  mapFile.Parse(data->readString(data->getDataLength()).c_str());
101 
102  if (mapFile.Error()) {
103  std::ostringstream oss;
104  oss << " Failed to load"
105  << mapFilename
106  << " : " << __FILE__
107  << " [" << __LINE__ << "]"
108  << std::endl;
109  FL_ERR(_log, oss.str());
110 
111  return map;
112  }
113  }
114 
115  // done with data delete resource
116  delete data;
117  data = 0;
118  }
119  }
120  catch (NotFound& e)
121  {
122  FL_ERR(_log, e.what());
123 
124  // TODO - should we abort here
125  // or rethrow the exception
126  // or just keep going
127 
128  return map;
129  }
130 
131  // if we get here then everything loaded properly
132  // so we can just parse out the contents
133  const TiXmlElement* root = mapFile.RootElement();
134 
135  if (root) {
136  const std::string* loaderName = root->Attribute(std::string("loaderName"));
137 
138  if (loaderName) {
139  m_loaderName = *loaderName;
140  }
141 
142  int numElements = 0;
143  int numElementsRetVal = root->QueryValueAttribute("elements", &numElements);
144  m_percentDoneListener.setTotalNumberOfElements(numElements);
145 
146  const std::string* mapName = root->Attribute(std::string("id"));
147 
148  if (mapName) {
149  try {
150  map = m_model->createMap(*mapName);
151  }
152  catch (NameClash& e) {
153  FL_ERR(_log, e.what());
154 
155  // just rethrow to client
156  throw;
157  }
158 
159  if (map) {
160  map->setFilename(mapFilename);
161 
162  std::string ns = "";
163  for (const TiXmlElement *importElement = root->FirstChildElement("import"); importElement; importElement = importElement->NextSiblingElement("import")) {
164  const std::string* importDir = importElement->Attribute(std::string("dir"));
165  const std::string* importFile = importElement->Attribute(std::string("file"));
166 
167  std::string directory = "";
168  if (importDir) {
169  directory = *importDir;
170  }
171 
172  std::string file = "";
173  if (importFile) {
174  file = *importFile;
175  }
176 
177  if (importDir && !importFile) {
178  bfs::path fullPath(m_mapDirectory);
179  fullPath /= directory;
180  loadImportDirectory(fullPath.string());
181  }
182  else if (importFile) {
183  bfs::path fullFilePath(file);
184  bfs::path fullDirPath(directory);
185  if (importDir) {
186  fullDirPath = bfs::path(m_mapDirectory);
187  fullDirPath /= directory;
188  }
189  else {
190  fullFilePath = bfs::path(m_mapDirectory);
191  fullFilePath /= file;
192  }
193  loadImportFile(fullFilePath.string(), fullDirPath.string());
194  }
195  }
196 
197  // iterate over elements looking for layers
198  for (const TiXmlElement* layerElement = root->FirstChildElement("layer"); layerElement; layerElement = layerElement->NextSiblingElement("layer")) {
199  // defaults
200  double xOffset = 0.0;
201  double yOffset = 0.0;
202  double zOffset = 0.0;
203  double xScale = 1.0;
204  double yScale = 1.0;
205  double rotation = 0.0;
206 
207  int xOffsetRetVal = layerElement->QueryValueAttribute("x_offset", &xOffset);
208  int yOffsetRetVal = layerElement->QueryValueAttribute("y_offset", &yOffset);
209  int zOffsetRetVal = layerElement->QueryValueAttribute("z_offset", &zOffset);
210  int xScaleRetVal = layerElement->QueryValueAttribute("x_scale", &xScale);
211  int yScaleRetVal = layerElement->QueryValueAttribute("y_scale", &yScale);
212  int rotationRetVal = layerElement->QueryValueAttribute("rotation", &rotation);
213 
214  const std::string* layerName = layerElement->Attribute(std::string("id"));
215  const std::string* pathing = layerElement->Attribute(std::string("pathing"));
216  const std::string* gridType = layerElement->Attribute(std::string("grid_type"));
217 
218  if (xOffsetRetVal == TIXML_SUCCESS &&
219  yOffsetRetVal == TIXML_SUCCESS &&
220  xScaleRetVal == TIXML_SUCCESS &&
221  yScaleRetVal == TIXML_SUCCESS &&
222  rotationRetVal == TIXML_SUCCESS &&
223  layerName &&
224  pathing &&
225  gridType) {
226  PathingStrategy pathStrategy = CELL_EDGES_ONLY;
227 
228  if ("cell_edges_and_diagonals" == *pathing) {
229  pathStrategy = CELL_EDGES_AND_DIAGONALS;
230  }
231  else if ("freeform" == *pathing) {
232  pathStrategy = FREEFORM;
233  }
234 
235  CellGrid* grid = NULL;
236  if (gridType) {
237  grid = m_model->getCellGrid(*gridType);
238  }
239  else {
240  grid = m_model->getCellGrid("square");
241  }
242 
243  if (grid) {
244  grid->setXShift(xOffset);
245  grid->setXScale(xScale);
246  grid->setYShift(yOffset);
247  grid->setYScale(yScale);
248  grid->setZShift(zOffset);
249  grid->setRotation(rotation);
250 
251  Layer *layer = NULL;
252  try {
253  layer = map->createLayer(*layerName, grid);
254  }
255  catch (NameClash&) {
256  // TODO - handle exception
257  assert(false);
258  }
259 
260  if (layer) {
261  layer->setPathingStrategy(pathStrategy);
262 
263  double curr_x = 0;
264  double curr_y = 0;
265 
266  for (const TiXmlElement* instances = layerElement->FirstChildElement("instances"); instances; instances = instances->NextSiblingElement("instances")) {
267  for (const TiXmlElement* instance = instances->FirstChildElement("i"); instance; instance = instance->NextSiblingElement("i")) {
268  double x = 0;
269  double y = 0;
270  double z = 0;
271  int r = 0;
272  int stackpos = 0;
273 
274  const std::string* instanceId = instance->Attribute(std::string("id"));
275  const std::string* objectId = instance->Attribute(std::string("o"));
276 
277  if (!objectId) {
278  objectId = instance->Attribute(std::string("object"));
279  }
280 
281  if (!objectId) {
282  objectId = instance->Attribute(std::string("obj"));
283  }
284 
285  const std::string* namespaceId = instance->Attribute(std::string("ns"));
286 
287  if (!namespaceId) {
288  namespaceId = instance->Attribute(std::string("namespace"));
289  }
290 
291  int xRetVal = instance->QueryValueAttribute("x", &x);
292  int yRetVal = instance->QueryValueAttribute("y", &y);
293  int zRetVal = instance->QueryValueAttribute("z", &z);
294  int rRetVal = instance->QueryValueAttribute("r", &r);
295 
296  if (xRetVal == TIXML_SUCCESS) {
297  curr_x = x;
298  }
299  else {
300  x = ++curr_x;
301  }
302 
303  if (yRetVal == TIXML_SUCCESS) {
304  curr_y = y;
305  }
306  else {
307  y = curr_y;
308  }
309 
310  if (rRetVal != TIXML_SUCCESS) {
311  rRetVal = instance->QueryValueAttribute("rotation", &r);
312  }
313 
314  int stackRetVal = instance->QueryValueAttribute("stackpos", &stackpos);
315 
316  if (objectId) {
317  if (namespaceId) {
318  ns = *namespaceId;
319  }
320 
321  Object* object = m_model->getObject(*objectId, ns);
322 
323  if (object) {
324  Instance* inst = NULL;
325  if (instanceId) {
326  inst = layer->createInstance(object, ExactModelCoordinate(x,y,z), *instanceId);
327  }
328  else {
329  inst = layer->createInstance(object, ExactModelCoordinate(x,y,z));
330  }
331 
332  if (inst) {
333  if (rRetVal != TIXML_SUCCESS) {
334  ObjectVisual* objVisual = object->getVisual<ObjectVisual>();
335  std::vector<int> angles;
336  objVisual->getStaticImageAngles(angles);
337  if (!angles.empty()) {
338  r = angles[0];
339  }
340  }
341 
342  inst->setRotation(r);
343 
344  InstanceVisual* instVisual = InstanceVisual::create(inst);
345 
346  if (instVisual && (stackRetVal == TIXML_SUCCESS)) {
347  instVisual->setStackPosition(stackpos);
348  }
349 
350  if (object->getAction("default")) {
351  Location target(layer);
352 
353  inst->act("default", target, true);
354  }
355  }
356  else
357  {
358  std::ostringstream oss;
359  oss << " Failed to create instance of object "
360  << *objectId
361  << " : " << __FILE__
362  << " [" << __LINE__ << "]"
363  << std::endl;
364  FL_ERR(_log, oss.str());
365  }
366  }
367  }
368 
369  // increment % done counter
370  m_percentDoneListener.incrementCount();
371  }
372  }
373  }
374  }
375  }
376 
377  // increment % done counter
378  m_percentDoneListener.incrementCount();
379  }
380 
381  for (const TiXmlElement* cameraElement = root->FirstChildElement("camera"); cameraElement; cameraElement = cameraElement->NextSiblingElement("camera")) {
382  const std::string* cameraId = cameraElement->Attribute(std::string("id"));
383  const std::string* refLayerId = cameraElement->Attribute(std::string("ref_layer_id"));
384 
385  int refCellWidth = 0;
386  int refCellHeight = 0;
387  int success = cameraElement->QueryIntAttribute("ref_cell_width", &refCellWidth);
388  success &= cameraElement->QueryIntAttribute("ref_cell_height", &refCellHeight);
389 
390  if (cameraId && refLayerId && success == TIXML_SUCCESS) {
391  double tilt = 0.0;
392  double zoom = 1.0;
393  double rotation = 0.0;
394  cameraElement->QueryDoubleAttribute("tilt", &tilt);
395  cameraElement->QueryDoubleAttribute("zoom", &zoom);
396  cameraElement->QueryDoubleAttribute("rotation", &rotation);
397 
398  const std::string* viewport = cameraElement->Attribute(std::string("viewport"));
399 
400  Layer* layer = NULL;
401  try {
402  layer = map->getLayer(*refLayerId);
403  }
404  catch (NotFound&) {
405  // TODO - handle exception
406  assert(false);
407  }
408 
409  Camera* cam = NULL;
410  if (layer) {
411  if (viewport) {
412  // parse out the viewport parameters
413  IntVector viewportParameters = tokenize(*viewport, ',');
414 
415  // make sure the right number of viewport parameters were parsed
416  if (viewportParameters.size() == 4) {
417  Rect rect(viewportParameters[0], viewportParameters[1],
418  viewportParameters[2], viewportParameters[3]);
419 
420  try {
421  cam = map->addCamera(*cameraId, layer, rect);
422  }
423  catch (NameClash&) {
424  // TODO - handle exception
425  assert(false);
426  }
427  }
428  }
429  else {
430  Rect rect(0, 0, m_renderBackend->getScreenWidth(), m_renderBackend->getScreenHeight());
431 
432  try {
433  cam = map->addCamera(*cameraId, layer, rect);
434  }
435  catch (NameClash&) {
436  // TODO - handle exception
437  assert(false);
438  }
439  }
440  }
441 
442  if (cam) {
443  cam->setCellImageDimensions(refCellWidth, refCellHeight);
444  cam->setRotation(rotation);
445  cam->setTilt(tilt);
446  cam->setZoom(zoom);
447 
448  // active instance renderer for camera
449  InstanceRenderer* instanceRenderer = InstanceRenderer::getInstance(cam);
450  if (instanceRenderer)
451  {
452  instanceRenderer->activateAllLayers(map);
453  }
454  }
455  }
456 
457  // increment % done counter
458  m_percentDoneListener.incrementCount();
459  }
460  }
461  }
462  }
463 
464  return map;
465  }
466 
467  void MapLoader::setObjectLoader(const FIFE::ObjectLoaderPtr& objectLoader) {
468  assert(objectLoader);
469 
470  m_objectLoader = objectLoader;
471  }
472 
473 
474  void MapLoader::setAnimationLoader(const FIFE::AnimationLoaderPtr& animationLoader) {
475  assert(animationLoader);
476 
477  m_objectLoader->setAnimationLoader(animationLoader);
478  }
479 
480  void MapLoader::setAtlasLoader(const FIFE::AtlasLoaderPtr& atlasLoader) {
481  assert(atlasLoader);
482 
483  m_atlasLoader = atlasLoader;
484  }
485 
486  bool MapLoader::isLoadable(const std::string& filename) const {
487  bfs::path mapPath(filename);
488 
489  TiXmlDocument mapFile;
490 
491  std::string mapFilename = mapPath.string();
492 
493  try {
494  RawData* data = m_vfs->open(mapFilename);
495 
496  if (data) {
497  if (data->getDataLength() != 0) {
498  mapFile.Parse(data->readString(data->getDataLength()).c_str());
499 
500  if (mapFile.Error()) {
501  return false;
502  }
503 
504  const TiXmlElement* root = mapFile.RootElement();
505 
506  if (root) {
507  const std::string* loaderName = root->Attribute(std::string("loader"));
508 
509  // if the file does not specify a loader but was opened and parsed
510  // correctly then we know we have a compatible extension so we will
511  // attempt to load it, if it does specify a loader then the loader
512  // name will be checked
513  if (!loaderName || (loaderName && *loaderName == getLoaderName())) {
514  return true;
515  }
516  }
517  }
518 
519  // done with file delete the resource
520  delete data;
521  data = 0;
522  }
523  }
524  catch (NotFound& e) {
525  FL_ERR(_log, e.what());
526 
527  return false;
528  }
529 
530  return false;
531  }
532 
533  void MapLoader::loadImportFile(const std::string& file, const std::string& directory) {
534  if (!file.empty()) {
535  bfs::path importFilePath(directory);
536  importFilePath /= file;
537 
538  std::string importFileString = importFilePath.string();
539  if (m_objectLoader && m_objectLoader->isLoadable(importFileString)) {
540  m_objectLoader->load(importFileString);
541  }
542  else if (m_atlasLoader && m_atlasLoader->isLoadable(importFileString)) {
543  m_atlasLoader->load(importFileString);
544  }
545  }
546  }
547 
548  void MapLoader::loadImportDirectory(const std::string& directory) {
549  if (!directory.empty()) {
550  bfs::path importDirectory(directory);
551  std::string importDirectoryString = importDirectory.string();
552 
553  std::set<std::string> files = m_vfs->listFiles(importDirectoryString);
554 
555  // load all xml files in the directory
556  std::set<std::string>::iterator iter;
557  for (iter = files.begin(); iter != files.end(); ++iter) {
558  // TODO - vtchill - may need a way to allow clients to load things other
559  // than .xml and .zip files
560  std::string ext = bfs::extension(*iter);
561  if (ext == ".xml" || ext == ".zip") {
562  loadImportFile(*iter, importDirectoryString);
563  }
564  }
565 
566  std::set<std::string> nestedDirectories = m_vfs->listDirectories(importDirectoryString);
567  for (iter = nestedDirectories.begin(); iter != nestedDirectories.end(); ++iter) {
568  // do not attempt to load anything from a .svn directory
569  if ((*iter).find(".svn") == std::string::npos) {
570  loadImportDirectory(importDirectoryString + "/" + *iter);
571  }
572  }
573  }
574  }
575 
576  void MapLoader::addPercentDoneListener(PercentDoneListener* listener) {
577  m_percentDoneListener.addListener(listener);
578  }
579 
580  const std::string& MapLoader::getLoaderName() const {
581  return m_loaderName;
582 
583  }
584 
585  MapLoader* createDefaultMapLoader(Model* model, VFS* vfs, ImageManager* imageManager, RenderBackend* renderBackend) {
586  return (new MapLoader(model, vfs, imageManager, renderBackend));
587  }
588 }
static InstanceVisual * create(Instance *instance)
Definition: visual.cpp:93
bool Error() const
Definition: tinyxml.h:1456
MapLoader * createDefaultMapLoader(Model *model, VFS *vfs, ImageManager *imageManager, RenderBackend *renderBackend)
Definition: maploader.cpp:585
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
PathingStrategy
Definition: layer.h:58
Definition: vfs.h:58
const TiXmlElement * RootElement() const
Definition: tinyxml.h:1448
const TiXmlElement * FirstChildElement() const
Convenience function to get through elements.
Definition: tinyxml.cpp:431
credit to phoku for his NodeDisplay example which the visitor code is adapted from ( he coded the qua...
Definition: soundclip.cpp:39