maploader.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2009 by the FIFE team                              *
00003  *   http://www.fifengine.net                                              *
00004  *   This file is part of FIFE.                                            *
00005  *                                                                         *
00006  *   FIFE is free software; you can redistribute it and/or                 *
00007  *   modify it under the terms of the GNU Lesser General Public            *
00008  *   License as published by the Free Software Foundation; either          *
00009  *   version 2.1 of the License, or (at your option) any later version.    *
00010  *                                                                         *
00011  *   This library is distributed in the hope that it will be useful,       *
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00014  *   Lesser General Public License for more details.                       *
00015  *                                                                         *
00016  *   You should have received a copy of the GNU Lesser General Public      *
00017  *   License along with this library; if not, write to the                 *
00018  *   Free Software Foundation, Inc.,                                       *
00019  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
00020  ***************************************************************************/
00021 
00022 // Standard C++ library includes
00023 #include <string>
00024 #include <vector>
00025 
00026 // 3rd party includes
00027 
00028 // FIFE includes
00029 // These includes are split up in two parts, separated by one empty line
00030 // First block: files included from the FIFE root src directory
00031 // Second block: files included from the same folder
00032 #include "ext/tinyxml/fife_tinyxml.h"
00033 #include "model/model.h"
00034 #include "model/structures/layer.h"
00035 #include "model/structures/instance.h"
00036 #include "model/metamodel/grids/cellgrid.h"
00037 #include "model/metamodel/modelcoords.h"
00038 #include "model/metamodel/action.h"
00039 #include "vfs/fife_boost_filesystem.h"
00040 #include "vfs/vfs.h"
00041 #include "vfs/vfsdirectory.h"
00042 #include "vfs/raw/rawdata.h"
00043 #include "util/base/exception.h"
00044 #include "util/log/logger.h"
00045 #include "util/resource/resource.h"
00046 #include "util/structures/rect.h"
00047 #include "video/imagemanager.h"
00048 #include "video/image.h"
00049 #include "video/renderbackend.h"
00050 #include "view/visual.h"
00051 #include "view/camera.h"
00052 #include "view/renderers/instancerenderer.h"
00053 #include "util/base/stringutils.h"
00054 
00055 #include "atlasloader.h"
00056 #include "maploader.h"
00057 #include "animationloader.h"
00058 #include "objectloader.h"
00059 
00060 namespace FIFE {
00061     static Logger _log(LM_NATIVE_LOADERS);
00062 
00063     MapLoader::MapLoader(Model* model, VFS* vfs, ImageManager* imageManager, RenderBackend* renderBackend)
00064     : m_model(model), m_vfs(vfs), m_imageManager(imageManager), m_renderBackend(renderBackend),
00065       m_loaderName("fife"), m_mapDirectory("") {
00066         AnimationLoaderPtr animationLoader(new AnimationLoader(m_vfs, m_imageManager));
00067         m_objectLoader.reset(new ObjectLoader(m_model, m_vfs, m_imageManager, animationLoader));
00068         m_atlasLoader.reset(new AtlasLoader(m_model, m_vfs, m_imageManager));
00069     }
00070 
00071     MapLoader::~MapLoader() {
00072 
00073     }
00074 
00075     Map* MapLoader::load(const std::string& filename) {
00076         Map* map = NULL;
00077 
00078         // reset percent done listener just in case
00079         // it has residual data from last load
00080         m_percentDoneListener.reset();
00081 
00082         bfs::path mapPath(filename);
00083 
00084         if (HasParentPath(mapPath)) {
00085             if (GetParentPath(mapPath).string() != m_mapDirectory) {
00086                 // save the directory where the map file is located
00087                 m_mapDirectory = GetParentPath(mapPath).string();
00088             }
00089         }
00090 
00091         TiXmlDocument mapFile;
00092 
00093         std::string mapFilename = mapPath.string();
00094 
00095         try {
00096             RawData* data = m_vfs->open(mapFilename);
00097 
00098             if (data) {
00099                 if (data->getDataLength() != 0) {
00100                     mapFile.Parse(data->readString(data->getDataLength()).c_str());
00101 
00102                     if (mapFile.Error()) {
00103                         std::ostringstream oss;
00104                         oss << " Failed to load"
00105                             << mapFilename
00106                             << " : " << __FILE__
00107                             << " [" << __LINE__ << "]"
00108                             << std::endl;
00109                         FL_ERR(_log, oss.str());
00110 
00111                         return map;
00112                     }
00113                 }
00114 
00115                 // done with data delete resource
00116                 delete data;
00117                 data = 0;
00118             }
00119         }
00120         catch (NotFound& e)
00121         {
00122             FL_ERR(_log, e.what());
00123 
00124             // TODO - should we abort here
00125             //        or rethrow the exception
00126             //        or just keep going
00127 
00128             return map;
00129         }
00130 
00131         // if we get here then everything loaded properly
00132         // so we can just parse out the contents
00133         const TiXmlElement* root = mapFile.RootElement();
00134 
00135         if (root) {
00136             const std::string* loaderName = root->Attribute(std::string("loaderName"));
00137 
00138             if (loaderName) {
00139                 m_loaderName = *loaderName;
00140             }
00141 
00142             int numElements = 0;
00143             int numElementsRetVal = root->QueryValueAttribute("elements", &numElements);
00144             m_percentDoneListener.setTotalNumberOfElements(numElements);
00145 
00146             const std::string* mapName = root->Attribute(std::string("id"));
00147 
00148             if (mapName) {
00149                 try {
00150                     map = m_model->createMap(*mapName);
00151                 }
00152                 catch (NameClash& e) {
00153                     FL_ERR(_log, e.what());
00154 
00155                     // just rethrow to client
00156                     throw;
00157                 }
00158 
00159                 if (map) {
00160                     map->setFilename(mapFilename);
00161 
00162                     std::string ns = "";
00163                     for (const TiXmlElement *importElement = root->FirstChildElement("import"); importElement; importElement = importElement->NextSiblingElement("import")) {
00164                         const std::string* importDir = importElement->Attribute(std::string("dir"));
00165                         const std::string* importFile = importElement->Attribute(std::string("file"));
00166 
00167                         std::string directory = "";
00168                         if (importDir) {
00169                             directory = *importDir;
00170                         }
00171 
00172                         std::string file = "";
00173                         if (importFile) {
00174                             file = *importFile;
00175                         }
00176 
00177                         if (importDir && !importFile) {
00178                             bfs::path fullPath(m_mapDirectory);
00179                             fullPath /= directory;
00180                             loadImportDirectory(fullPath.string());
00181                         }
00182                         else if (importFile) {
00183                             bfs::path fullFilePath(file);
00184                             bfs::path fullDirPath(directory);
00185                             if (importDir) {
00186                                 fullDirPath = bfs::path(m_mapDirectory);
00187                                 fullDirPath /= directory;
00188                             }
00189                             else {
00190                                 fullFilePath = bfs::path(m_mapDirectory);
00191                                 fullFilePath /= file;
00192                             }
00193                             loadImportFile(fullFilePath.string(), fullDirPath.string());
00194                         }
00195                     }
00196 
00197                     // iterate over elements looking for layers
00198                     for (const TiXmlElement* layerElement = root->FirstChildElement("layer"); layerElement; layerElement = layerElement->NextSiblingElement("layer")) {
00199                         // defaults
00200                         double xOffset = 0.0;
00201                         double yOffset = 0.0;
00202                         double zOffset = 0.0;
00203                         double xScale = 1.0;
00204                         double yScale = 1.0;
00205                         double rotation = 0.0;
00206 
00207                         int xOffsetRetVal = layerElement->QueryValueAttribute("x_offset", &xOffset);
00208                         int yOffsetRetVal = layerElement->QueryValueAttribute("y_offset", &yOffset);
00209                         int zOffsetRetVal = layerElement->QueryValueAttribute("z_offset", &zOffset);
00210                         int xScaleRetVal = layerElement->QueryValueAttribute("x_scale", &xScale);
00211                         int yScaleRetVal = layerElement->QueryValueAttribute("y_scale", &yScale);
00212                         int rotationRetVal = layerElement->QueryValueAttribute("rotation", &rotation);
00213 
00214                         const std::string* layerName = layerElement->Attribute(std::string("id"));
00215                         const std::string* pathing = layerElement->Attribute(std::string("pathing"));
00216                         const std::string* gridType = layerElement->Attribute(std::string("grid_type"));
00217 
00218                         if (xOffsetRetVal == TIXML_SUCCESS &&
00219                             yOffsetRetVal == TIXML_SUCCESS &&
00220                             xScaleRetVal == TIXML_SUCCESS &&
00221                             yScaleRetVal == TIXML_SUCCESS &&
00222                             rotationRetVal == TIXML_SUCCESS &&
00223                             layerName &&
00224                             pathing &&
00225                             gridType) {
00226                             PathingStrategy pathStrategy = CELL_EDGES_ONLY;
00227 
00228                             if ("cell_edges_and_diagonals" == *pathing) {
00229                                 pathStrategy = CELL_EDGES_AND_DIAGONALS;
00230                             }
00231                             else if ("freeform" == *pathing) {
00232                                 pathStrategy = FREEFORM;
00233                             }
00234 
00235                             CellGrid* grid = NULL;
00236                             if (gridType) {
00237                                 grid = m_model->getCellGrid(*gridType);
00238                             }
00239                             else {
00240                                 grid = m_model->getCellGrid("square");
00241                             }
00242 
00243                             if (grid) {
00244                                 grid->setXShift(xOffset);
00245                                 grid->setXScale(xScale);
00246                                 grid->setYShift(yOffset);
00247                                 grid->setYScale(yScale);
00248                                 grid->setZShift(zOffset);
00249                                 grid->setRotation(rotation);
00250                                 grid->setAllowDiagonals(pathStrategy != CELL_EDGES_ONLY);
00251 
00252                                 Layer *layer = NULL;
00253                                 try {
00254                                     layer = map->createLayer(*layerName, grid);
00255                                 }
00256                                 catch (NameClash&) {
00257                                     // TODO - handle exception
00258                                     assert(false);
00259                                 }
00260 
00261                                 if (layer) {
00262                                     layer->setPathingStrategy(pathStrategy);
00263 
00264                                     double curr_x = 0;
00265                                     double curr_y = 0;
00266 
00267                                     for (const TiXmlElement* instances = layerElement->FirstChildElement("instances"); instances; instances = instances->NextSiblingElement("instances")) {
00268                                         for (const TiXmlElement* instance = instances->FirstChildElement("i"); instance; instance = instance->NextSiblingElement("i")) {
00269                                             double x = 0;
00270                                             double y = 0;
00271                                             double z = 0;
00272                                             int r = 0;
00273                                             int stackpos = 0;
00274 
00275                                             const std::string* instanceId = instance->Attribute(std::string("id"));
00276                                             const std::string* objectId = instance->Attribute(std::string("o"));
00277 
00278                                             if (!objectId) {
00279                                                 objectId = instance->Attribute(std::string("object"));
00280                                             }
00281 
00282                                             if (!objectId) {
00283                                                 objectId = instance->Attribute(std::string("obj"));
00284                                             }
00285 
00286                                             const std::string* namespaceId = instance->Attribute(std::string("ns"));
00287 
00288                                             if (!namespaceId) {
00289                                                 namespaceId = instance->Attribute(std::string("namespace"));
00290                                             }
00291 
00292                                             int xRetVal = instance->QueryValueAttribute("x", &x);
00293                                             int yRetVal = instance->QueryValueAttribute("y", &y);
00294                                             int zRetVal = instance->QueryValueAttribute("z", &z);
00295                                             int rRetVal = instance->QueryValueAttribute("r", &r);
00296 
00297                                             if (xRetVal == TIXML_SUCCESS) {
00298                                                 curr_x = x;
00299                                             }
00300                                             else {
00301                                                 x = ++curr_x;
00302                                             }
00303 
00304                                             if (yRetVal == TIXML_SUCCESS) {
00305                                                 curr_y = y;
00306                                             }
00307                                             else {
00308                                                 y = curr_y;
00309                                             }
00310 
00311                                             if (rRetVal != TIXML_SUCCESS) {
00312                                                 rRetVal = instance->QueryValueAttribute("rotation", &r);
00313                                             }
00314 
00315                                             int stackRetVal = instance->QueryValueAttribute("stackpos", &stackpos);
00316 
00317                                             if (objectId) {
00318                                                 if (namespaceId) {
00319                                                     ns = *namespaceId;
00320                                                 }
00321 
00322                                                 Object* object = m_model->getObject(*objectId, ns);
00323 
00324                                                 if (object) {
00325                                                     Instance* inst = NULL;
00326                                                     if (instanceId) {
00327                                                         inst = layer->createInstance(object, ExactModelCoordinate(x,y,z), *instanceId);
00328                                                     }
00329                                                     else {
00330                                                         inst = layer->createInstance(object, ExactModelCoordinate(x,y,z));
00331                                                     }
00332 
00333                                                     if (inst) {
00334                                                         if (rRetVal != TIXML_SUCCESS) {
00335                                                             ObjectVisual* objVisual = object->getVisual<ObjectVisual>();
00336                                                             std::vector<int> angles;
00337                                                             objVisual->getStaticImageAngles(angles);
00338                                                             if (!angles.empty()) {
00339                                                                 r = angles[0];
00340                                                             }
00341                                                         }
00342 
00343                                                         inst->setRotation(r);
00344 
00345                                                         InstanceVisual* instVisual = InstanceVisual::create(inst);
00346 
00347                                                         if  (instVisual && (stackRetVal == TIXML_SUCCESS)) {
00348                                                             instVisual->setStackPosition(stackpos);
00349                                                         }
00350 
00351                                                         if (object->getAction("default")) {
00352                                                             Location target(layer);
00353 
00354                                                             inst->act("default", target, true);
00355                                                         }
00356                                                     }
00357                                                     else
00358                                                     {
00359                                                         std::ostringstream oss;
00360                                                         oss << " Failed to create instance of object "
00361                                                             << *objectId
00362                                                             << " : " << __FILE__
00363                                                             << " [" << __LINE__ << "]"
00364                                                             << std::endl;
00365                                                         FL_ERR(_log, oss.str());
00366                                                     }
00367                                                 }
00368                                             }
00369 
00370                                             // increment % done counter
00371                                             m_percentDoneListener.incrementCount();
00372                                         }
00373                                     }
00374                                 }
00375                             }
00376                         }
00377 
00378                         // increment % done counter
00379                         m_percentDoneListener.incrementCount();
00380                     }
00381 
00382                     for (const TiXmlElement* cameraElement = root->FirstChildElement("camera"); cameraElement; cameraElement = cameraElement->NextSiblingElement("camera")) {
00383                         const std::string* cameraId = cameraElement->Attribute(std::string("id"));
00384                         const std::string* refLayerId = cameraElement->Attribute(std::string("ref_layer_id"));
00385 
00386                         int refCellWidth = 0;
00387                         int refCellHeight = 0;
00388                         int success = cameraElement->QueryIntAttribute("ref_cell_width", &refCellWidth);
00389                         success &= cameraElement->QueryIntAttribute("ref_cell_height", &refCellHeight);
00390 
00391                         if (cameraId && refLayerId && success == TIXML_SUCCESS) {
00392                             double tilt = 0.0;
00393                             double zoom = 1.0;
00394                             double rotation = 0.0;
00395                             cameraElement->QueryDoubleAttribute("tilt", &tilt);
00396                             cameraElement->QueryDoubleAttribute("zoom", &zoom);
00397                             cameraElement->QueryDoubleAttribute("rotation", &rotation);
00398 
00399                             const std::string* viewport = cameraElement->Attribute(std::string("viewport"));
00400 
00401                             Layer* layer = NULL;
00402                             try {
00403                                 layer = map->getLayer(*refLayerId);
00404                             }
00405                             catch (NotFound&) {
00406                                 // TODO - handle exception
00407                                 assert(false);
00408                             }
00409 
00410                             Camera* cam = NULL;
00411                             if (layer) {
00412                                 if (viewport) {
00413                                     // parse out the viewport parameters
00414                                     IntVector viewportParameters = tokenize(*viewport, ',');
00415 
00416                                     // make sure the right number of viewport parameters were parsed
00417                                     if (viewportParameters.size() == 4) {
00418                                         Rect rect(viewportParameters[0], viewportParameters[1],
00419                                                     viewportParameters[2], viewportParameters[3]);
00420 
00421                                         try {
00422                                             cam = map->addCamera(*cameraId, layer, rect);
00423                                         }
00424                                         catch (NameClash&) {
00425                                             // TODO - handle exception
00426                                             assert(false);
00427                                         }
00428                                     }
00429                                 }
00430                                 else {
00431                                     Rect rect(0, 0, m_renderBackend->getScreenWidth(), m_renderBackend->getScreenHeight());
00432 
00433                                     try {
00434                                         cam = map->addCamera(*cameraId, layer, rect);
00435                                     }
00436                                     catch (NameClash&) {
00437                                         // TODO - handle exception
00438                                         assert(false);
00439                                     }
00440                                 }
00441                             }
00442 
00443                             if (cam) {
00444                                 cam->setCellImageDimensions(refCellWidth, refCellHeight);
00445                                 cam->setRotation(rotation);
00446                                 cam->setTilt(tilt);
00447                                 cam->setZoom(zoom);
00448 
00449                                 // active instance renderer for camera
00450                                 InstanceRenderer* instanceRenderer = InstanceRenderer::getInstance(cam);
00451                                 if (instanceRenderer)
00452                                 {
00453                                     instanceRenderer->activateAllLayers(map);
00454                                 }
00455                             }
00456                         }
00457 
00458                         // increment % done counter
00459                         m_percentDoneListener.incrementCount();
00460                     }
00461                 }
00462             }
00463         }
00464 
00465         return map;
00466     }
00467 
00468     void MapLoader::setObjectLoader(const FIFE::ObjectLoaderPtr& objectLoader) {
00469         assert(objectLoader);
00470 
00471         m_objectLoader = objectLoader;
00472     }
00473 
00474 
00475     void MapLoader::setAnimationLoader(const FIFE::AnimationLoaderPtr& animationLoader) {
00476         assert(animationLoader);
00477 
00478         m_objectLoader->setAnimationLoader(animationLoader);
00479     }
00480 
00481     void MapLoader::setAtlasLoader(const FIFE::AtlasLoaderPtr& atlasLoader) {
00482         assert(atlasLoader);
00483 
00484         m_atlasLoader = atlasLoader;
00485     }
00486 
00487     bool MapLoader::isLoadable(const std::string& filename) const {
00488         bfs::path mapPath(filename);
00489 
00490         TiXmlDocument mapFile;
00491 
00492         std::string mapFilename = mapPath.string();
00493 
00494         try {
00495             RawData* data = m_vfs->open(mapFilename);
00496 
00497             if (data) {
00498                 if (data->getDataLength() != 0) {
00499                     mapFile.Parse(data->readString(data->getDataLength()).c_str());
00500 
00501                     if (mapFile.Error()) {
00502                         return false;
00503                     }
00504 
00505                     const TiXmlElement* root = mapFile.RootElement();
00506 
00507                     if (root) {
00508                         const std::string* loaderName = root->Attribute(std::string("loader"));
00509 
00510                         // if the file does not specify a loader but was opened and parsed
00511                         // correctly then we know we have a compatible extension so we will
00512                         // attempt to load it, if it does specify a loader then the loader
00513                         // name will be checked
00514                         if (!loaderName || (loaderName && *loaderName == getLoaderName())) {
00515                             return true;
00516                         }
00517                     }
00518                 }
00519 
00520                 // done with file delete the resource
00521                 delete data;
00522                 data = 0;
00523             }
00524         }
00525         catch (NotFound& e) {
00526             FL_ERR(_log, e.what());
00527 
00528             return false;
00529         }
00530 
00531         return false;
00532     }
00533 
00534     void MapLoader::loadImportFile(const std::string& file, const std::string& directory) {
00535         if (!file.empty()) {
00536             bfs::path importFilePath(directory);
00537             importFilePath /= file;
00538 
00539             std::string importFileString = importFilePath.string();
00540             if (m_objectLoader && m_objectLoader->isLoadable(importFileString)) {
00541                 m_objectLoader->load(importFileString);
00542             }
00543             else if (m_atlasLoader && m_atlasLoader->isLoadable(importFileString)) {
00544                 m_atlasLoader->load(importFileString);
00545             }
00546         }
00547     }
00548 
00549     void MapLoader::loadImportDirectory(const std::string& directory) {
00550         if (!directory.empty()) {
00551             bfs::path importDirectory(directory);
00552             std::string importDirectoryString = importDirectory.string();
00553 
00554             std::set<std::string> files = m_vfs->listFiles(importDirectoryString);
00555 
00556             // load all xml files in the directory
00557             std::set<std::string>::iterator iter;
00558             for (iter = files.begin(); iter != files.end(); ++iter) {
00559                 // TODO - vtchill - may need a way to allow clients to load things other
00560                 // than .xml and .zip files
00561                 std::string ext = bfs::extension(*iter);
00562                 if (ext == ".xml" || ext == ".zip") {
00563                     loadImportFile(*iter, importDirectoryString);
00564                 }
00565             }
00566 
00567             std::set<std::string> nestedDirectories = m_vfs->listDirectories(importDirectoryString);
00568             for (iter  = nestedDirectories.begin(); iter != nestedDirectories.end(); ++iter) {
00569                 // do not attempt to load anything from a .svn directory
00570                 if ((*iter).find(".svn") == std::string::npos) {
00571                     loadImportDirectory(importDirectoryString + "/" + *iter);
00572                 }
00573             }
00574         }
00575     }
00576 
00577     void MapLoader::addPercentDoneListener(PercentDoneListener* listener) {
00578         m_percentDoneListener.addListener(listener);
00579     }
00580 
00581     const std::string& MapLoader::getLoaderName() const {
00582         return m_loaderName;
00583 
00584     }
00585 
00586     MapLoader* createDefaultMapLoader(Model* model, VFS* vfs, ImageManager* imageManager, RenderBackend* renderBackend) {
00587         return (new MapLoader(model, vfs, imageManager, renderBackend));
00588     }
00589 }