updating Nolok contrib templates
[supertux.git] / lib / special / sprite_data.cpp
1 //  $Id$
2 //
3 //  SuperTux
4 //  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.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 #include <config.h>
20
21 #include <iostream>
22 #include <cmath>
23 #include <sstream>
24 #include <stdexcept>
25
26 #include "sprite_data.h"
27 #include "app/globals.h"
28 #include "app/setup.h"
29 #include "video/drawing_context.h"
30 #include "lisp/list_iterator.h"
31
32 namespace SuperTux
33 {
34
35 SpriteData::Action::Action()
36 {
37   x_offset = 0;
38   y_offset = 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)
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());
58     } else {
59       std::cerr << "Unknown sprite field: " << iter.item() << "\n";
60     }
61   }
62   if(name.empty())
63     throw std::runtime_error("Error: Sprite wihtout name.");
64   if(actions.empty())
65     throw std::runtime_error("Error: Sprite wihtout 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)
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   lisp->get("x-offset", action->x_offset);
85   lisp->get("y-offset", action->y_offset);
86   lisp->get("z-order", action->z_order);
87   lisp->get("fps", action->fps);
88
89   std::string mirror_action;
90   lisp->get("mirror-action", mirror_action);
91   if(!mirror_action.empty()) {
92     Action* act_tmp = get_action(mirror_action);
93     if(act_tmp == NULL) {
94       throw std::runtime_error("Could not mirror action. Action not found\n"
95                    "Mirror actions must be defined after the real one!");
96     } else {
97       for(int i = 0; static_cast<unsigned int>(i) < act_tmp->surfaces.size();
98           i++) {
99         Surface* surface = new Surface(sdl_surface_from_sdl_surface(
100               act_tmp->surfaces[i]->impl->get_sdl_surface(), true), true);
101         surface->apply_filter(HORIZONTAL_FLIP_FILTER);
102         action->surfaces.push_back(surface);
103       }
104     }
105   } else { // Load images
106     std::vector<std::string> images;
107     if(!lisp->get_vector("images", images)) {
108       std::stringstream msg;
109       msg << "Sprite '" << name << "' contains no images in action '"
110           << action->name << "'.";
111       throw std::runtime_error(msg.str());
112     }
113
114     for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) {
115       action->surfaces.push_back(
116           new Surface(datadir + "/images/" + images[i], true));
117     }
118   }
119   actions[action->name] = action;
120 }
121
122 SpriteData::Action*
123 SpriteData::get_action(std::string act)
124 {
125   Actions::iterator i = actions.find(act);
126   if(i == actions.end()) {
127     return 0;
128   }
129   return i->second;
130 }
131
132 }