fix cr/lfs and remove trailing whitespaces...
[supertux.git] / src / sprite / sprite_data.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program 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
14 //  GNU General Public License for more details.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 #include <config.h>
21
22 #include <iostream>
23 #include <cmath>
24 #include <sstream>
25 #include <stdexcept>
26
27 #include "sprite_data.hpp"
28 #include "resources.hpp"
29 #include "video/drawing_context.hpp"
30 #include "lisp/list_iterator.hpp"
31 #include "log.hpp"
32
33 SpriteData::Action::Action()
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 {
52   lisp::ListIterator iter(lisp);
53   while(iter.next()) {
54     if(iter.item() == "name") {
55       iter.value()->get(name);
56     } else if(iter.item() == "action") {
57       parse_action(iter.lisp(), basedir);
58     } else {
59       log_warning << "Unknown sprite field: " << iter.item() << std::endl;
60     }
61   }
62   if(actions.empty())
63     throw std::runtime_error("Error: Sprite wihtout actions.");
64 }
65
66 SpriteData::~SpriteData()
67 {
68   for(Actions::iterator i=actions.begin(); i != actions.end(); ++i)
69     delete i->second;
70 }
71
72 void
73 SpriteData::parse_action(const lisp::Lisp* lisp, const std::string& basedir)
74 {
75   Action* action = new Action;
76
77   if(!lisp->get("name", action->name)) {
78     if(!actions.empty())
79       throw std::runtime_error(
80           "If there are more than one action, they need names!");
81   }
82   std::vector<float> hitbox;
83   if (lisp->get_vector("hitbox", hitbox)) {
84     if (hitbox.size() != 4) throw std::runtime_error("hitbox must specify exactly 4 coordinates");
85     action->x_offset = hitbox[0];
86     action->y_offset = hitbox[1];
87     action->hitbox_w = hitbox[2];
88     action->hitbox_h = hitbox[3];
89   }
90   lisp->get("z-order", action->z_order);
91   lisp->get("fps", action->fps);
92
93   std::string mirror_action;
94   lisp->get("mirror-action", mirror_action);
95   if(!mirror_action.empty()) {
96     Action* act_tmp = get_action(mirror_action);
97     if(act_tmp == NULL) {
98       throw std::runtime_error("Could not mirror action. Action not found\n"
99                    "Mirror actions must be defined after the real one!");
100     } else {
101       float max_w = 0;
102       float max_h = 0;
103       for(int i = 0; static_cast<unsigned int>(i) < act_tmp->surfaces.size();
104           i++) {
105         Surface* surface = new Surface(*(act_tmp->surfaces[i]));
106         surface->hflip();
107         max_w = std::max(max_w, surface->get_width());
108         max_h = std::max(max_h, surface->get_height());
109         action->surfaces.push_back(surface);
110       }
111       if (action->hitbox_w < 1) action->hitbox_w = max_w;
112       if (action->hitbox_h < 1) action->hitbox_h = max_h;
113     }
114   } else { // Load images
115     std::vector<std::string> images;
116     if(!lisp->get_vector("images", images)) {
117       std::stringstream msg;
118       msg << "Sprite '" << name << "' contains no images in action '"
119           << action->name << "'.";
120       throw std::runtime_error(msg.str());
121     }
122
123     float max_w = 0;
124     float max_h = 0;
125     for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) {
126       Surface* surface = new Surface(basedir + images[i]);
127       max_w = std::max(max_w, surface->get_width());
128       max_h = std::max(max_h, surface->get_height());
129       action->surfaces.push_back(surface);
130     }
131     if (action->hitbox_w < 1) action->hitbox_w = max_w;
132     if (action->hitbox_h < 1) action->hitbox_h = max_h;
133   }
134   actions[action->name] = action;
135 }
136
137 SpriteData::Action*
138 SpriteData::get_action(std::string act)
139 {
140   Actions::iterator i = actions.find(act);
141   if(i == actions.end()) {
142     return 0;
143   }
144   return i->second;
145 }