00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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 {
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