1 /*************************************************************************** 2 * Copyright (C) 2005-2019 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 #include <tinyxml.h> 26 27 // FIFE includes 28 // These includes are split up in two parts, separated by one empty line 29 // First block: files included from the FIFE root src directory 30 // Second block: files included from the same folder 31 #include "vfs/fife_boost_filesystem.h" 32 #include "vfs/vfs.h" 33 #include "vfs/raw/rawdata.h" 34 #include "video/imagemanager.h" 35 #include "video/animationmanager.h" 36 #include "video/image.h" 37 #include "video/animation.h" 38 #include "util/base/exception.h" 39 #include "util/log/logger.h" 40 #include "util/resource/resource.h" 41 #include "util/resource/resourcemanager.h" 42 43 #include "animationloader.h" 44 45 namespace FIFE { 46 /** Logger to use for this source file. 47 * @relates Logger 48 */ 49 static Logger _log(LM_NATIVE_LOADERS); 50 AnimationLoader(VFS * vfs,ImageManager * imageManager,AnimationManager * animationManager)51 AnimationLoader::AnimationLoader(VFS* vfs, ImageManager* imageManager, AnimationManager* animationManager) 52 : m_vfs(vfs), m_imageManager(imageManager), m_animationManager(animationManager) { 53 54 } 55 isLoadable(const std::string & filename)56 bool AnimationLoader::isLoadable(const std::string& filename) { 57 bfs::path animPath(filename); 58 59 std::string animationFilename = animPath.string(); 60 TiXmlDocument animFile; 61 62 try { 63 RawData* data = m_vfs->open(animationFilename); 64 65 if (data) { 66 if (data->getDataLength() != 0) { 67 // TODO - this could be expanded to do more checks 68 animFile.Parse(data->readString(data->getDataLength()).c_str()); 69 70 if (animFile.Error()) { 71 return false; 72 } 73 } 74 75 // done with data delete resource 76 delete data; 77 data = 0; 78 } 79 } 80 catch (NotFound&) { 81 return false; 82 } 83 84 // if we get here then loading the file went well 85 TiXmlElement* root = animFile.RootElement(); 86 87 if (root && root->ValueStr() == "assets") { 88 if (root->FirstChildElement("animation")) { 89 return true; 90 } 91 } 92 93 return false; 94 } 95 load(const std::string & filename)96 AnimationPtr AnimationLoader::load(const std::string& filename) { 97 bfs::path animPath(filename); 98 99 std::string animationFilename = animPath.string(); 100 101 TiXmlDocument doc; 102 103 AnimationPtr animation; 104 105 try { 106 RawData* data = m_vfs->open(animationFilename); 107 108 if (data) { 109 if (data->getDataLength() != 0) { 110 doc.Parse(data->readString(data->getDataLength()).c_str()); 111 112 if (doc.Error()) { 113 return animation; 114 } 115 116 // done with data delete resource 117 delete data; 118 data = 0; 119 } 120 } 121 } 122 catch (NotFound& e) { 123 FL_ERR(_log, e.what()); 124 125 // TODO - should we abort here 126 // or rethrow the exception 127 // or just keep going 128 129 return animation; 130 } 131 132 // if we get here then everything loaded properly 133 // so we can just parse out the contents 134 TiXmlElement* root = doc.RootElement(); 135 136 if (root && root->ValueStr() == "assets") { 137 animation = loadAnimation(filename, root->FirstChildElement("animation")); 138 } 139 140 return animation; 141 } 142 loadMultiple(const std::string & filename)143 std::vector<AnimationPtr> AnimationLoader::loadMultiple(const std::string& filename) { 144 bfs::path animPath(filename); 145 146 std::string animationFilename = animPath.string(); 147 148 TiXmlDocument doc; 149 150 std::vector<AnimationPtr> animationVector; 151 152 try { 153 RawData* data = m_vfs->open(animationFilename); 154 155 if (data) { 156 if (data->getDataLength() != 0) { 157 doc.Parse(data->readString(data->getDataLength()).c_str()); 158 159 if (doc.Error()) { 160 return animationVector; 161 } 162 163 // done with data delete resource 164 delete data; 165 data = 0; 166 } 167 } 168 } 169 catch (NotFound& e) { 170 FL_ERR(_log, e.what()); 171 172 // TODO - should we abort here 173 // or rethrow the exception 174 // or just keep going 175 176 return animationVector; 177 } 178 179 // if we get here then everything loaded properly 180 // so we can just parse out the contents 181 TiXmlElement* root = doc.RootElement(); 182 183 if (root && root->ValueStr() == "assets") { 184 for (TiXmlElement* animationElem = root->FirstChildElement("animation"); animationElem; animationElem = animationElem->NextSiblingElement("animation")) { 185 AnimationPtr animation = loadAnimation(filename, animationElem); 186 if (animation) { 187 animationVector.push_back(animation); 188 } 189 } 190 } 191 192 return animationVector; 193 } 194 loadAnimation(const std::string & filename,TiXmlElement * animationElem)195 AnimationPtr AnimationLoader::loadAnimation(const std::string& filename, TiXmlElement* animationElem) { 196 AnimationPtr animation; 197 if (!animationElem) { 198 return animation; 199 } 200 201 bfs::path animPath(filename); 202 std::string animationFilename = animPath.string(); 203 204 bool alreadyLoaded = false; 205 // first try to use the id, if no id exists it use the filename as fallback 206 const std::string* animationId = animationElem->Attribute(std::string("id")); 207 if (animationId) { 208 if (!m_animationManager->exists(*animationId)) { 209 animation = m_animationManager->create(*animationId); 210 } else { 211 animation = m_animationManager->getPtr(*animationId); 212 alreadyLoaded = animation->getFrameCount() != 0; 213 } 214 } else { 215 if (HasParentPath(animPath)) { 216 animPath= GetParentPath(animPath) / animationFilename; 217 } else { 218 animPath = bfs::path(animationFilename); 219 } 220 if (!m_animationManager->exists(animPath.string())) { 221 animation = m_animationManager->create(animPath.string()); 222 } else { 223 animation = m_animationManager->getPtr(animPath.string()); 224 alreadyLoaded = animation->getFrameCount() != 0; 225 } 226 } 227 228 if (alreadyLoaded) { 229 return animation; 230 } 231 232 int direction = 0; 233 int actionFrame = -1; 234 int animDelay = 0; 235 int animXoffset = 0; 236 int animYoffset = 0; 237 238 int success = animationElem->QueryValueAttribute("direction", &direction); 239 if (success == TIXML_SUCCESS) { 240 animation->setDirection(direction); 241 } 242 success = animationElem->QueryValueAttribute("action_frame", &actionFrame); 243 if (success == TIXML_SUCCESS) { 244 animation->setActionFrame(actionFrame); 245 } 246 animationElem->QueryValueAttribute("delay", &animDelay); 247 animationElem->QueryValueAttribute("x_offset", &animXoffset); 248 animationElem->QueryValueAttribute("y_offset", &animYoffset); 249 250 for (TiXmlElement* frameElement = animationElem->FirstChildElement("frame"); frameElement; frameElement = frameElement->NextSiblingElement("frame")) { 251 const std::string* sourceId = frameElement->Attribute(std::string("source")); 252 if (sourceId) { 253 bfs::path framePath(filename); 254 255 if (HasParentPath(framePath)) { 256 framePath = GetParentPath(framePath) / *sourceId; 257 if (!bfs::exists(framePath)) { 258 framePath = bfs::path(*sourceId); 259 } 260 } else { 261 framePath = bfs::path(*sourceId); 262 } 263 264 ImagePtr imagePtr; 265 if (!m_imageManager->exists(framePath.string())) { 266 imagePtr = m_imageManager->create(framePath.string()); 267 } else { 268 imagePtr = m_imageManager->getPtr(framePath.string()); 269 } 270 271 if (imagePtr) { 272 int frameXoffset = 0; 273 success = frameElement->QueryValueAttribute("x_offset", &frameXoffset); 274 if (success == TIXML_SUCCESS) { 275 imagePtr->setXShift(frameXoffset); 276 } else { 277 imagePtr->setXShift(animXoffset); 278 } 279 280 int frameYoffset = 0; 281 success = frameElement->QueryValueAttribute("y_offset", &frameYoffset); 282 if (success == TIXML_SUCCESS) { 283 imagePtr->setYShift(frameYoffset); 284 } else { 285 imagePtr->setYShift(animYoffset); 286 } 287 288 int frameDelay = 0; 289 success = frameElement->QueryValueAttribute("delay", &frameDelay); 290 if (success == TIXML_SUCCESS) { 291 animation->addFrame(imagePtr, frameDelay); 292 } else { 293 animation->addFrame(imagePtr, animDelay); 294 } 295 } 296 } 297 } 298 299 return animation; 300 } 301 } 302