atlasloader.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2005-2011 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 
00024 // 3rd party library includes
00025 
00026 // FIFE includes
00027 // These includes are split up in two parts, separated by one empty line
00028 // First block: files included from the FIFE root src directory
00029 // Second block: files included from the same folder
00030 #include "ext/tinyxml/fife_tinyxml.h"
00031 #include "model/model.h"
00032 #include "model/structures/layer.h"
00033 #include "vfs/fife_boost_filesystem.h"
00034 #include "vfs/vfs.h"
00035 #include "vfs/raw/rawdata.h"
00036 #include "util/base/exception.h"
00037 #include "util/log/logger.h"
00038 #include "util/resource/resource.h"
00039 #include "util/resource/resourcemanager.h"
00040 #include "view/visual.h"
00041 
00042 #include "atlasloader.h"
00043 
00044 namespace FIFE {
00045     static Logger _log(LM_NATIVE_LOADERS);
00046 
00047 
00048     size_t Atlas::getImageCount() const {
00049         return m_subimages.size();
00050     }
00051 
00052     ImagePtr& Atlas::getPackedImage() {
00053         return m_image;
00054     }
00055 
00056     ImagePtr Atlas::getImage(const std::string& id) {
00057         SubimageMap::iterator iter = m_subimages.find(id);
00058         if(iter == m_subimages.end())
00059             return ImagePtr();
00060         return iter->second.image;
00061     }
00062 
00063     ImagePtr Atlas::getImage(uint32_t index) {
00064         if(index > getImageCount())
00065             return ImagePtr();
00066 
00067         SubimageMap::iterator iter = m_subimages.begin();
00068         for(uint32_t i = 0; i < index; ++i, ++iter);
00069         return iter->second.image;
00070     }
00071 
00072     bool Atlas::addImage(const std::string& imagename, const AtlasData& data) {
00073         return m_subimages.insert(std::pair<std::string, AtlasData>(imagename, data)).second;
00074     }
00075 
00076     void Atlas::setPackedImage(const ImagePtr& image) {
00077         m_image = image;
00078     }
00079 
00080     const std::string& Atlas::getName() const {
00081         return m_name;
00082     }
00083 
00084     AtlasLoader::AtlasLoader(Model* model, VFS* vfs, ImageManager* imageManager)
00085     : m_model(model), m_vfs(vfs), m_imageManager(imageManager) {
00086     }
00087 
00088     AtlasLoader::~AtlasLoader() {
00089     }
00090 
00091     bool AtlasLoader::isLoadable(const std::string& filename) {
00092         bfs::path atlasPath(filename);
00093         std::string atlasFilename = atlasPath.string();
00094         TiXmlDocument atlasFile;
00095 
00096         try {
00097             RawData* data = m_vfs->open(atlasFilename);
00098 
00099             if (data) {
00100                 if (data->getDataLength() != 0) {
00101                     atlasFile.Parse(data->readString(data->getDataLength()).c_str());
00102 
00103                     if (atlasFile.Error()) {
00104                         return false;
00105                     }
00106                 } else {
00107                     return false;
00108                 }
00109 
00110                 // done with data delete resource
00111                 delete data;
00112                 data = 0;
00113             }
00114         } catch (NotFound&) {
00115             return false;
00116         }
00117 
00118         // if we get here then loading the file went well
00119         TiXmlElement* root = atlasFile.RootElement();
00120 
00121         if (root && root->ValueStr() == "atlas") {
00122             return true;
00123         }
00124         else {
00125             return false;
00126         }
00127     }
00128 
00129     AtlasPtr AtlasLoader::load(const std::string& filename) {
00130         bfs::path atlasPath(filename);
00131         bfs::path atlasPathDirectory;
00132         m_atlasFilename = atlasPath.string();
00133 
00134         if (HasParentPath(atlasPath)) {
00135             // save the directory where the atlas file is located
00136             atlasPathDirectory = GetParentPath(atlasPath);
00137         }
00138 
00139         TiXmlDocument doc;
00140         AtlasPtr atlas;
00141 
00142         try {
00143             RawData* data = m_vfs->open(m_atlasFilename);
00144 
00145             if (data) {
00146                 if (data->getDataLength() != 0) {
00147                     doc.Parse(data->readString(data->getDataLength()).c_str());
00148 
00149                     if (doc.Error()) {
00150                         return atlas;
00151                     }
00152 
00153                     // done with data delete resource
00154                     delete data;
00155                     data = 0;
00156                 }
00157             }
00158         }
00159         catch (NotFound& e) {
00160             FL_ERR(_log, e.what());
00161 
00162             // TODO - should we abort here
00163             //        or rethrow the exception
00164             //        or just keep going
00165 
00166             return atlas;
00167         }
00168 
00169         // if we get here then everything loaded properly
00170         // so we can just parse out the contents
00171         TiXmlElement* root = doc.RootElement();
00172 
00173         if (root && root->ValueStr() == "atlas") {
00174             const std::string* atlasName = root->Attribute(std::string("name"));
00175             if(atlasName) {
00176                 const std::string* namespaceId = root->Attribute(std::string("namespace"));
00177                 if(!namespaceId) {
00178                     namespaceId = atlasName;
00179                 }
00180 
00181                 // Atlas itself doesn't have appended namespace
00182                 bfs::path atlasImagePath = atlasPathDirectory / *atlasName;
00183                 atlas.reset(new Atlas(atlasImagePath.string()));
00184 
00185                 // End-user could create the same atlas for the second time.
00186                 // Since we don't hold any data for Atlases like ImageManager we need to recreate
00187                 // atlas parameters (to return proper AtlasPtr) but don't reload pixel data (they are held by ImageManager).
00188 
00189                 bool atlasExists = m_imageManager->exists(atlas->getName());
00190 
00191                 if(!atlasExists) {
00192                     atlas->setPackedImage(m_imageManager->create(atlas->getName()));
00193                 }
00194                 else {
00195                     atlas->setPackedImage(m_imageManager->getPtr(atlas->getName()));
00196                 }
00197 
00198                 // We don't really need this now, though we could use it to assert if the loaded atlas is the same sized as these
00199                 //int atlasWidth, atlasHeight;
00200                 //root->QueryValueAttribute("width", &atlasWidth);
00201                 //root->QueryValueAttribute("height", &atlasHeight);
00202                 bool subsExists = true;
00203                 for (TiXmlElement* imageElem = root->FirstChildElement("image");
00204                     imageElem != 0; imageElem = imageElem->NextSiblingElement("image")) {
00205 
00206                     Rect region;
00207                     imageElem->QueryValueAttribute("xpos", &region.x);
00208                     imageElem->QueryValueAttribute("ypos", &region.y);
00209                     imageElem->QueryValueAttribute("width", &region.w);
00210                     imageElem->QueryValueAttribute("height", &region.h);
00211 
00212                     const std::string* subimageName = imageElem->Attribute(std::string("source"));
00213 
00214                     if (subimageName) {
00215                         std::string finalname = *namespaceId + ":" +*subimageName;
00216                         ImagePtr subImage;
00217 
00218                         bool subExists = m_imageManager->exists(finalname);
00219                         if (!subExists) {
00220                             subsExists = false;
00221                             subImage = m_imageManager->create(finalname);
00222                         }
00223                         else {
00224                             subImage = m_imageManager->getPtr(finalname);
00225                         }
00226                         subImage->useSharedImage(atlas->getPackedImage(), region);
00227 
00228                         AtlasData atlas_data = {region, subImage};
00229                         atlas->addImage(finalname, atlas_data);
00230                     }
00231                 }
00232                 subsExists = subsExists && atlasExists;
00233 
00234                 // Now parse object definition
00235                 for(TiXmlElement* objElem = root->NextSiblingElement("object");
00236                     objElem != 0; objElem = objElem->NextSiblingElement("object"))
00237                 {
00238                     // sanity check
00239                     if(objElem->ValueStr() == "object") {
00240                         parseObject(atlas.get(), objElem, subsExists);
00241                     }
00242                 }
00243             }
00244         }
00245 
00246         return atlas;
00247     }
00248 
00249     void AtlasLoader::parseObject(Atlas* atlas, TiXmlElement* root, bool exists) {
00250         const std::string* objectId = root->Attribute(std::string("id"));
00251         const std::string* namespaceId = root->Attribute(std::string("namespace"));
00252 
00253         Object* obj = NULL;
00254         if (objectId && namespaceId) {
00255             const std::string* parentId = root->Attribute(std::string("parent"));
00256 
00257             if (parentId) {
00258                 Object* parent = m_model->getObject(*parentId, *namespaceId);
00259                 if (parent) {
00260                     try {
00261                         obj = m_model->createObject(*objectId, *namespaceId, parent);
00262                     }
00263                     catch  (NameClash&) {
00264                         // TODO - handle exception
00265                         assert(false);
00266                     }
00267                 }
00268             }
00269             else {
00270                 // this will make sure the object has not already been loaded
00271                 if (m_model->getObject(*objectId, *namespaceId) == NULL) {
00272                     try {
00273                         obj = m_model->createObject(*objectId, *namespaceId);
00274                     }
00275                     catch (NameClash&) {
00276                         // TODO - handle exception
00277                         assert(false);
00278                     }
00279                 // if atlas or subimage was recreated then we have to update the ObjectVisual
00280                 } else if (!exists) {
00281                     obj = m_model->getObject(*objectId, *namespaceId);
00282                     ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
00283                     // make sure obj have visual
00284                     if (!objVisual) {
00285                         objVisual = ObjectVisual::create(obj);
00286                     }
00287 
00288                     for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
00289                         const std::string* sourceId = imageElement->Attribute(std::string("source"));
00290 
00291                         if (sourceId) {
00292                             std::string source = *namespaceId + ":" + *sourceId;
00293                             if(!m_imageManager->exists(source)) {
00294                                 throw NotFound(source + " couldn't be found.");
00295                             }
00296                             ImagePtr imagePtr = m_imageManager->getPtr(source);
00297 
00298                             int xOffset = 0;
00299                             int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
00300                             if (success == TIXML_SUCCESS) {
00301                                 imagePtr->setXShift(xOffset);
00302                             }
00303 
00304                             int yOffset = 0;
00305                             success = imageElement->QueryIntAttribute("y_offset", &yOffset);
00306                             if (success == TIXML_SUCCESS) {
00307                                 imagePtr->setYShift(yOffset);
00308                             }
00309 
00310                             int direction = 0;
00311                             success = imageElement->QueryIntAttribute("direction", &direction);
00312                             if (success == TIXML_SUCCESS) {
00313                                 if (objVisual) {
00314                                     objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
00315                                 }
00316                             }
00317                         }
00318                     }
00319                     return;
00320                 }
00321             }
00322         }
00323 
00324         if (obj) {
00325             //obj->setFilename(atlas->getName());
00326             obj->setFilename(m_atlasFilename);
00327             ObjectVisual::create(obj);
00328 
00329             int isBlocking = 0;
00330             root->QueryIntAttribute("blocking", &isBlocking);
00331             obj->setBlocking(isBlocking!=0);
00332 
00333             int isStatic = 0;
00334             root->QueryIntAttribute("static", &isStatic);
00335             obj->setStatic(isStatic!=0);
00336 
00337             const std::string* pather = root->Attribute(std::string("pather"));
00338 
00339             if (pather) {
00340                 obj->setPather(m_model->getPather(*pather));
00341             }
00342             else {
00343                 obj->setPather(m_model->getPather("RoutePather"));
00344             }
00345 
00346             // loop over all image tags
00347             for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
00348                 const std::string* sourceId = imageElement->Attribute(std::string("source"));
00349 
00350                 if (sourceId) {
00351                     std::string source = *namespaceId + ":" + *sourceId;
00352                     if(!m_imageManager->exists(source)) {
00353                         throw NotFound(source + " couldn't be found.");
00354                     }
00355                     ImagePtr imagePtr = m_imageManager->getPtr(source);
00356                     int xOffset = 0;
00357                     int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
00358 
00359                     if (success == TIXML_SUCCESS) {
00360                         imagePtr->setXShift(xOffset);
00361                     }
00362 
00363                     int yOffset = 0;
00364                     success = imageElement->QueryIntAttribute("y_offset", &yOffset);
00365 
00366                     if (success == TIXML_SUCCESS) {
00367                         imagePtr->setYShift(yOffset);
00368                     }
00369 
00370                     int direction = 0;
00371                     success = imageElement->QueryIntAttribute("direction", &direction);
00372 
00373                     if (success == TIXML_SUCCESS) {
00374                         ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
00375 
00376                         if (objVisual) {
00377                             objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
00378                         }
00379                     }
00380                 }
00381             }
00382         }
00383     }
00384 
00385     AtlasLoader* createDefaultAtlasLoader(Model* model, VFS* vfs, ImageManager* imageManager) {
00386         return new AtlasLoader(model, vfs, imageManager);
00387     }
00388 }