src/sprite/sprite_data.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software: you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation, either version 3 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #include "sprite/sprite_data.hpp"
00018 
00019 #include <stdexcept>
00020 #include <sstream>
00021 
00022 #include "lisp/list_iterator.hpp"
00023 #include "util/log.hpp"
00024 #include "util/reader.hpp"
00025 
00026 SpriteData::Action::Action() :
00027   name(),
00028   x_offset(),
00029   y_offset(),
00030   hitbox_w(),
00031   hitbox_h(),
00032   z_order(),
00033   fps(),
00034   surfaces()
00035 {
00036   x_offset = 0;
00037   y_offset = 0;
00038   hitbox_w = 0;
00039   hitbox_h = 0;
00040   z_order = 0;
00041   fps = 10;
00042 }
00043 
00044 SpriteData::Action::~Action()
00045 {
00046 }
00047 
00048 SpriteData::SpriteData(const Reader& lisp, const std::string& basedir) :
00049   actions(),
00050   name()
00051 {
00052   lisp::ListIterator iter(&lisp);
00053   while(iter.next()) {
00054     if(iter.item() == "name") {
00055       iter.value()->get(name);
00056     } else if(iter.item() == "action") {
00057       parse_action(*iter.lisp(), basedir);
00058     } else {
00059       log_warning << "Unknown sprite field: " << iter.item() << std::endl;
00060     }
00061   }
00062   if(actions.empty())
00063     throw std::runtime_error("Error: Sprite without actions.");
00064 }
00065 
00066 SpriteData::~SpriteData()
00067 {
00068   for(Actions::iterator i=actions.begin(); i != actions.end(); ++i)
00069     delete i->second;
00070 }
00071 
00072 void
00073 SpriteData::parse_action(const Reader& lisp, const std::string& basedir)
00074 {
00075   Action* action = new Action;
00076 
00077   if(!lisp.get("name", action->name)) {
00078     if(!actions.empty())
00079       throw std::runtime_error(
00080         "If there are more than one action, they need names!");
00081   }
00082   std::vector<float> hitbox;
00083   if (lisp.get("hitbox", hitbox)) {
00084     switch(hitbox.size()) {
00085       case 4:
00086         action->hitbox_h = hitbox[3];
00087         action->hitbox_w = hitbox[2];
00088 
00089         //fall-through
00090       case 2:
00091         action->y_offset = hitbox[1];
00092         action->x_offset = hitbox[0];
00093         break;
00094 
00095       default:
00096         throw std::runtime_error("hitbox should specify 2/4 coordinates");
00097     }
00098   }
00099   lisp.get("z-order", action->z_order);
00100   lisp.get("fps", action->fps);
00101 
00102   std::string mirror_action;
00103   lisp.get("mirror-action", mirror_action);
00104   if(!mirror_action.empty()) {
00105     const Action* act_tmp = get_action(mirror_action);
00106     if(act_tmp == NULL) {
00107       throw std::runtime_error("Could not mirror action. Action not found.\n"
00108                                "Mirror actions must be defined after the real one!");
00109     } else {
00110       float max_w = 0;
00111       float max_h = 0;
00112       for(int i = 0; static_cast<unsigned int>(i) < act_tmp->surfaces.size(); i++) {
00113         SurfacePtr surface = act_tmp->surfaces[i]->clone();
00114         surface->hflip();
00115         max_w = std::max(max_w, (float) surface->get_width());
00116         max_h = std::max(max_h, (float) surface->get_height());
00117         action->surfaces.push_back(surface);
00118       }
00119       if (action->hitbox_w < 1) action->hitbox_w = max_w - action->x_offset;
00120       if (action->hitbox_h < 1) action->hitbox_h = max_h - action->y_offset;
00121     }
00122   } else { // Load images
00123     std::vector<std::string> images;
00124     if(!lisp.get("images", images)) {
00125       std::stringstream msg;
00126       msg << "Sprite '" << name << "' contains no images in action '"
00127           << action->name << "'.";
00128       throw std::runtime_error(msg.str());
00129     }
00130 
00131     float max_w = 0;
00132     float max_h = 0;
00133     for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) {
00134       SurfacePtr surface = Surface::create(basedir + images[i]);
00135       max_w = std::max(max_w, (float) surface->get_width());
00136       max_h = std::max(max_h, (float) surface->get_height());
00137       action->surfaces.push_back(surface);
00138     }
00139     if (action->hitbox_w < 1) action->hitbox_w = max_w - action->x_offset;
00140     if (action->hitbox_h < 1) action->hitbox_h = max_h - action->y_offset;
00141   }
00142   actions[action->name] = action;
00143 }
00144 
00145 const SpriteData::Action*
00146 SpriteData::get_action(const std::string act)
00147 {
00148   Actions::iterator i = actions.find(act);
00149   if(i == actions.end()) {
00150     return 0;
00151   }
00152   return i->second;
00153 }
00154 
00155 /* EOF */

Generated on Mon Jun 9 03:38:21 2014 for SuperTux by  doxygen 1.5.1