objectloader.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 "util/log/logger.h"
00032 #include "model/model.h"
00033 #include "model/metamodel/object.h"
00034 #include "model/metamodel/action.h"
00035 #include "vfs/fife_boost_filesystem.h"
00036 #include "vfs/vfs.h"
00037 #include "vfs/raw/rawdata.h"
00038 #include "view/visual.h"
00039 #include "video/imagemanager.h"
00040 
00041 #include "objectloader.h"
00042 #include "animationloader.h"
00043 
00044 namespace FIFE {
00045     static Logger _log(LM_NATIVE_LOADERS);
00046 
00047     ObjectLoader::ObjectLoader(Model* model, VFS* vfs, ImageManager* imageManager, const AnimationLoaderPtr& animationLoader)
00048     : m_model(model), m_vfs(vfs), m_imageManager(imageManager) {
00049         assert(m_model && m_vfs && m_imageManager);
00050 
00051         if (animationLoader) {
00052             m_animationLoader = animationLoader;
00053         }
00054         else {
00055             m_animationLoader.reset(new AnimationLoader(m_vfs, m_imageManager));
00056         }
00057     }
00058 
00059     ObjectLoader::~ObjectLoader() {
00060 
00061     }
00062 
00063     void ObjectLoader::setAnimationLoader(const AnimationLoaderPtr& animationLoader) {
00064         assert(animationLoader);
00065 
00066         m_animationLoader = animationLoader;
00067     }
00068 
00069     bool ObjectLoader::isLoadable(const std::string& filename) const {
00070         bfs::path objectPath(filename);
00071 
00072         TiXmlDocument objectFile;
00073 
00074         try {
00075             RawData* data = m_vfs->open(objectPath.string());
00076 
00077             if (data) {
00078                 if (data->getDataLength() != 0) {
00079                     objectFile.Parse(data->readString(data->getDataLength()).c_str());
00080 
00081                     if (objectFile.Error()) {
00082                          std::ostringstream oss;
00083                         oss << " Failed to load"
00084                             << objectPath.string()
00085                             << " : " << __FILE__
00086                             << " [" << __LINE__ << "]"
00087                             << std::endl;
00088                         FL_ERR(_log, oss.str());
00089 
00090                         return false;
00091                     }
00092                 }
00093                 else {
00094                     std::ostringstream oss;
00095                     oss << " Failed to load"
00096                         << objectPath.string()
00097                         << " : " << __FILE__
00098                         << " [" << __LINE__ << "]"
00099                         << std::endl;
00100                     FL_ERR(_log, oss.str());
00101 
00102                     return false;
00103                 }
00104 
00105                 // done with data delete resource
00106                 delete data;
00107                 data = 0;
00108             }
00109             else {
00110                 std::ostringstream oss;
00111                 oss << " Failed to load"
00112                     << objectPath.string()
00113                     << " : " << __FILE__
00114                     << " [" << __LINE__ << "]"
00115                     << std::endl;
00116                 FL_ERR(_log, oss.str());
00117 
00118                 return false;
00119             }
00120         }
00121         catch (NotFound&) {
00122             std::ostringstream oss;
00123             oss << " Failed to load"
00124                 << objectPath.string()
00125                 << " : " << __FILE__
00126                 << " [" << __LINE__ << "]"
00127                 << std::endl;
00128             FL_ERR(_log, oss.str());
00129 
00130             // TODO - should we abort here
00131             //        or rethrow the exception
00132             //        or just keep going
00133 
00134             return false;
00135         }
00136 
00137         // if we get here then loading the file went well
00138         TiXmlElement* root = objectFile.RootElement();
00139 
00140         if (root && root->ValueStr() == "object") {
00141             return true;
00142         }
00143         else {
00144             return false;
00145         }
00146     }
00147 
00148     void ObjectLoader::load(const std::string& filename) {
00149         bfs::path objectPath(filename);
00150 
00151         TiXmlDocument objectFile;
00152 
00153         try {
00154             RawData* data = m_vfs->open(objectPath.string());
00155 
00156             if (data) {
00157                 if (data->getDataLength() != 0) {
00158                     objectFile.Parse(data->readString(data->getDataLength()).c_str());
00159 
00160                     if (objectFile.Error()) {
00161                         return;
00162                     }
00163                 }
00164 
00165                 // done with data delete resource
00166                 delete data;
00167                 data = 0;
00168             }
00169         }
00170         catch (NotFound&) {
00171             std::ostringstream oss;
00172             oss << " Failed to load"
00173                 << objectPath.string()
00174                 << " : " << __FILE__
00175                 << " [" << __LINE__ << "]"
00176                 << std::endl;
00177             FL_ERR(_log, oss.str());
00178 
00179             // TODO - should we abort here
00180             //        or rethrow the exception
00181             //        or just keep going
00182 
00183             return;
00184         }
00185 
00186         // if we get here then loading the file went well
00187         TiXmlElement* root = objectFile.RootElement();
00188 
00189         if (root && root->ValueStr() == "object") {
00190             const std::string* objectId = root->Attribute(std::string("id"));
00191             const std::string* namespaceId = root->Attribute(std::string("namespace"));
00192 
00193             Object* obj = NULL;
00194             if (objectId && namespaceId) {
00195                 const std::string* parentId = root->Attribute(std::string("parent"));
00196 
00197                 if (parentId) {
00198                     Object* parent = m_model->getObject(*parentId, *namespaceId);
00199                     if (parent) {
00200                         try {
00201                             obj = m_model->createObject(*objectId, *namespaceId, parent);
00202                         }
00203                         catch  (NameClash&) {
00204                             // TODO - handle exception
00205                             assert(false);
00206                         }
00207                     }
00208                 }
00209                 else {
00210                     // this will make sure the object has not already been loaded
00211                     if (m_model->getObject(*objectId, *namespaceId) == NULL) {
00212                         try {
00213                             obj = m_model->createObject(*objectId, *namespaceId);
00214                         }
00215                         catch (NameClash &e) {
00216                             FL_ERR(_log, e.what());
00217 
00218                             // TODO - handle exception
00219                             assert(false);
00220                         }
00221                     }
00222                 }
00223             }
00224 
00225             if (obj) {
00226                 obj->setFilename(objectPath.string());
00227                 ObjectVisual::create(obj);
00228 
00229                 int isBlocking = 0;
00230                 root->QueryIntAttribute("blocking", &isBlocking);
00231                 obj->setBlocking(isBlocking!=0);
00232 
00233                 int isStatic = 0;
00234                 root->QueryIntAttribute("static", &isStatic);
00235                 obj->setStatic(isStatic!=0);
00236 
00237                 const std::string* pather = root->Attribute(std::string("pather"));
00238 
00239                 if (pather) {
00240                     obj->setPather(m_model->getPather(*pather));
00241                 }
00242                 else {
00243                     obj->setPather(m_model->getPather("RoutePather"));
00244                 }
00245 
00246                 // loop over all image tags
00247                 for (TiXmlElement* imageElement = root->FirstChildElement("image"); imageElement; imageElement = imageElement->NextSiblingElement("image")) {
00248                     const std::string* sourceId = imageElement->Attribute(std::string("source"));
00249 
00250                     if (sourceId) {
00251                         bfs::path imagePath(filename);
00252 
00253                         if (HasParentPath(imagePath)) {
00254                             imagePath = GetParentPath(imagePath) / *sourceId;
00255                         } else {
00256                             imagePath = bfs::path(*sourceId);
00257                         }
00258 
00259                         ImagePtr imagePtr;
00260                         if(!m_imageManager->exists(imagePath.string())) {
00261                             imagePtr = m_imageManager->create(imagePath.string());
00262                         }
00263                         else {
00264                             imagePtr = m_imageManager->getPtr(imagePath.string());
00265                         }
00266 
00267                         if (imagePtr) {
00268                             int xOffset = 0;
00269                             int success = imageElement->QueryIntAttribute("x_offset", &xOffset);
00270 
00271                             if (success == TIXML_SUCCESS) {
00272                                 imagePtr->setXShift(xOffset);
00273                             }
00274 
00275                             int yOffset = 0;
00276                             success = imageElement->QueryIntAttribute("y_offset", &yOffset);
00277 
00278                             if (success == TIXML_SUCCESS) {
00279                                 imagePtr->setYShift(yOffset);
00280                             }
00281 
00282                             int direction = 0;
00283                             success = imageElement->QueryIntAttribute("direction", &direction);
00284 
00285                             if (success == TIXML_SUCCESS) {
00286                                 ObjectVisual* objVisual = obj->getVisual<ObjectVisual>();
00287 
00288                                 if (objVisual) {
00289                                     objVisual->addStaticImage(direction, static_cast<int32_t>(imagePtr->getHandle()));
00290                                 }
00291                             }
00292                         }
00293                     }
00294                 }
00295 
00296                 for (TiXmlElement* actionElement = root->FirstChildElement("action"); actionElement; actionElement = actionElement->NextSiblingElement("action")) {
00297                     const std::string* actionId = actionElement->Attribute(std::string("id"));
00298 
00299                     if (actionId) {
00300                         Action* action = obj->createAction(*actionId);
00301                         ActionVisual::create(action);
00302 
00303                         for (TiXmlElement* animElement = actionElement->FirstChildElement("animation"); animElement; animElement = animElement->NextSiblingElement("animation")) {
00304                             const std::string* sourceId = animElement->Attribute(std::string("atlas"));
00305                             if(sourceId) {
00306                                 bfs::path atlasPath(filename);
00307 
00308                                 if (HasParentPath(atlasPath)) {
00309                                     atlasPath = GetParentPath(atlasPath) / *sourceId;
00310                                 } else {
00311                                     atlasPath = bfs::path(*sourceId);
00312                                 }
00313 
00314                                 ImagePtr atlasImgPtr;
00315                                 // we need to load this since its shared image
00316                                 if(!m_imageManager->exists(atlasPath.string())) {
00317                                     atlasImgPtr = m_imageManager->create(atlasPath.string());
00318                                 }
00319                                 else {
00320                                     atlasImgPtr = m_imageManager->getPtr(atlasPath.string());
00321                                 }
00322 
00323                                 int animFrames = 0;
00324                                 int animDelay = 0;
00325                                 int animXoffset = 0;
00326                                 int animYoffset = 0;
00327                                 int frameWidth = 0;
00328                                 int frameHeight = 0;
00329 
00330                                 animElement->QueryValueAttribute("width", &frameWidth);
00331                                 animElement->QueryValueAttribute("height", &frameHeight);
00332                                 animElement->QueryValueAttribute("frames", &animFrames);
00333                                 animElement->QueryValueAttribute("delay", &animDelay);
00334                                 animElement->QueryValueAttribute("x_offset", &animXoffset);
00335                                 animElement->QueryValueAttribute("y_offset", &animYoffset);
00336                                 int nDir = 0;
00337 
00338                                 for (TiXmlElement* dirElement = animElement->FirstChildElement("direction");
00339                                     dirElement; dirElement = dirElement->NextSiblingElement("direction")) {
00340                                         AnimationPtr animation(new Animation);
00341 
00342                                         int dir;
00343                                         dirElement->QueryIntAttribute("dir", &dir);
00344 
00345                                         int frames;
00346                                         int success;
00347 
00348                                         success = dirElement->QueryValueAttribute("frames", &frames);
00349                                         if(success != TIXML_SUCCESS) {
00350                                             frames = animFrames;
00351                                         }
00352 
00353                                         int delay;
00354                                         success = dirElement->QueryValueAttribute("delay", &delay);
00355                                         if(success != TIXML_SUCCESS) {
00356                                             delay = animDelay;
00357                                         }
00358 
00359                                         int xoffset;
00360                                         success = dirElement->QueryValueAttribute("x_offset", &xoffset);
00361                                         if(success != TIXML_SUCCESS) {
00362                                             xoffset = animXoffset;
00363                                         }
00364 
00365                                         int yoffset;
00366                                         success = dirElement->QueryValueAttribute("y_offset", &yoffset);
00367                                         if(success != TIXML_SUCCESS) {
00368                                             yoffset = animYoffset;
00369                                         }
00370 
00371                                         int action_frame;
00372                                         success = dirElement->QueryValueAttribute("action", &action_frame);
00373                                         if(success == TIXML_SUCCESS) {
00374                                             animation->setActionFrame(action_frame);
00375                                         }
00376 
00377                                         for (int iframe = 0; iframe < frames; ++iframe) {
00378                                             static char tmpBuf[64];
00379                                             sprintf(tmpBuf, "%03d:%04d", dir, iframe);
00380 
00381                                             std::string frameId = *objectId + ":" + *actionId + ":" + std::string(tmpBuf);
00382 
00383                                             ImagePtr framePtr;
00384                                             if (!m_imageManager->exists(frameId)) {
00385                                                 framePtr = m_imageManager->create(frameId);
00386                                                 Rect region(
00387                                                     frameWidth * iframe, frameHeight * nDir, frameWidth, frameHeight
00388                                                 );
00389                                                 framePtr->useSharedImage(atlasImgPtr, region);
00390                                                 framePtr->setXShift(xoffset);
00391                                                 framePtr->setYShift(yoffset);
00392                                             }
00393                                             else {
00394                                                 framePtr = m_imageManager->getPtr(frameId);
00395                                             }
00396                                             animation->addFrame(framePtr, delay);
00397                                         }
00398 
00399                                         ActionVisual* actionVisual = action->getVisual<ActionVisual>();
00400                                         if(actionVisual) {
00401                                             actionVisual->addAnimation(dir, animation);
00402                                             action->setDuration(animation->getDuration());
00403                                         }
00404                                         ++nDir;
00405                                 }
00406 
00407                             } else {
00408                                 sourceId = animElement->Attribute(std::string("source"));
00409                                 if (sourceId) {
00410                                     bfs::path animPath(filename);
00411 
00412                                     if (HasParentPath(animPath)) {
00413                                         animPath = GetParentPath(animPath) / *sourceId;
00414                                     } else {
00415                                         animPath = bfs::path(*sourceId);
00416                                     }
00417 
00418                                     AnimationPtr animation;
00419                                     if (m_animationLoader && m_animationLoader->isLoadable(animPath.string())) {
00420                                         animation = m_animationLoader->load(animPath.string());
00421                                     }
00422 
00423                                     int direction = 0;
00424                                     int success = animElement->QueryIntAttribute("direction", &direction);
00425 
00426                                     if (action && animation) {
00427                                         ActionVisual* actionVisual = action->getVisual<ActionVisual>();
00428 
00429                                         if (actionVisual) {
00430                                             actionVisual->addAnimation(direction, animation);
00431                                             action->setDuration(animation->getDuration());
00432                                         }
00433                                     }
00434                                 }
00435                             }
00436                         }
00437                     }
00438                 }
00439             }
00440         }
00441     }
00442 
00443 }