6d2d2a558df4618291634184e637dfb4d2bd7a40
[supertux.git] / src / sprite / sprite_data.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "sprite/sprite_data.hpp"
18
19 #include <stdexcept>
20 #include <sstream>
21
22 #include "lisp/list_iterator.hpp"
23 #include "util/log.hpp"
24
25 SpriteData::Action::Action() :
26   name(),
27   x_offset(),
28   y_offset(),
29   hitbox_w(),
30   hitbox_h(),
31   z_order(),
32   fps(),
33   surfaces()
34 {
35   x_offset = 0;
36   y_offset = 0;
37   hitbox_w = 0;
38   hitbox_h = 0;
39   z_order = 0;
40   fps = 10;
41 }
42
43 SpriteData::Action::~Action()
44 {
45   for(std::vector<Surface*>::iterator i = surfaces.begin();
46       i != surfaces.end(); ++i)
47     delete *i;
48 }
49
50 SpriteData::SpriteData(const lisp::Lisp* lisp, const std::string& basedir) :
51   actions(),
52   name()
53 {
54   lisp::ListIterator iter(lisp);
55   while(iter.next()) {
56     if(iter.item() == "name") {
57       iter.value()->get(name);
58     } else if(iter.item() == "action") {
59       parse_action(iter.lisp(), basedir);
60     } else {
61       log_warning << "Unknown sprite field: " << iter.item() << std::endl;
62     }
63   }
64   if(actions.empty())
65     throw std::runtime_error("Error: Sprite without actions.");
66 }
67
68 SpriteData::~SpriteData()
69 {
70   for(Actions::iterator i=actions.begin(); i != actions.end(); ++i)
71     delete i->second;
72 }
73
74 void
75 SpriteData::parse_action(const lisp::Lisp* lisp, const std::string& basedir)
76 {
77   Action* action = new Action;
78
79   if(!lisp->get("name", action->name)) {
80     if(!actions.empty())
81       throw std::runtime_error(
82         "If there are more than one action, they need names!");
83   }
84   std::vector<float> hitbox;
85   if (lisp->get("hitbox", hitbox)) {
86     if (hitbox.size() != 4) throw std::runtime_error("hitbox must specify exactly 4 coordinates");
87     action->x_offset = hitbox[0];
88     action->y_offset = hitbox[1];
89     action->hitbox_w = hitbox[2];
90     action->hitbox_h = hitbox[3];
91   }
92   lisp->get("z-order", action->z_order);
93   lisp->get("fps", action->fps);
94
95   std::string mirror_action;
96   lisp->get("mirror-action", mirror_action);
97   if(!mirror_action.empty()) {
98     Action* act_tmp = get_action(mirror_action);
99     if(act_tmp == NULL) {
100       throw std::runtime_error("Could not mirror action. Action not found\n"
101                                "Mirror actions must be defined after the real one!");
102     } else {
103       float max_w = 0;
104       float max_h = 0;
105       for(int i = 0; static_cast<unsigned int>(i) < act_tmp->surfaces.size(); i++) {
106         Surface* surface = new Surface(*(act_tmp->surfaces[i]));
107         surface->hflip();
108         max_w = std::max(max_w, (float) surface->get_width());
109         max_h = std::max(max_h, (float) surface->get_height());
110         action->surfaces.push_back(surface);
111       }
112       if (action->hitbox_w < 1) action->hitbox_w = max_w;
113       if (action->hitbox_h < 1) action->hitbox_h = max_h;
114     }
115   } else { // Load images
116     std::vector<std::string> images;
117     if(!lisp->get("images", images)) {
118       std::stringstream msg;
119       msg << "Sprite '" << name << "' contains no images in action '"
120           << action->name << "'.";
121       throw std::runtime_error(msg.str());
122     }
123
124     float max_w = 0;
125     float max_h = 0;
126     for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) {
127       Surface* surface = new Surface(basedir + images[i]);
128       max_w = std::max(max_w, (float) surface->get_width());
129       max_h = std::max(max_h, (float) surface->get_height());
130       action->surfaces.push_back(surface);
131     }
132     if (action->hitbox_w < 1) action->hitbox_w = max_w;
133     if (action->hitbox_h < 1) action->hitbox_h = max_h;
134   }
135   actions[action->name] = action;
136 }
137
138 SpriteData::Action*
139 SpriteData::get_action(std::string act)
140 {
141   Actions::iterator i = actions.find(act);
142   if(i == actions.end()) {
143     return 0;
144   }
145   return i->second;
146 }
147
148 /* EOF */