197b7c52b520d34b96762ffc7a0a53561898772b
[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
31 namespace SuperTux
32 {
33
34 SpriteData::Action::Action()
35 {
36   x_offset = 0;
37   y_offset = 0;
38   z_order = 0;   
39   fps = 10;
40 }
41
42 SpriteData::Action::~Action()
43 {
44   for(std::vector<Surface*>::iterator i = surfaces.begin();
45       i != surfaces.end(); ++i)
46     delete *i;
47 }
48
49 SpriteData::SpriteData(lisp_object_t* cur)
50 {
51   for(; !lisp_nil_p(cur); cur = lisp_cdr(cur)) {
52     std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
53     lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
54     LispReader reader(lisp_cdr(lisp_car(cur)));
55
56     if(token == "name")
57       name = lisp_string(data);
58     else if(token == "action")
59       parse_action(reader);
60     else
61       std::cerr << "Warning: Unknown sprite field: " << token << std::endl;
62   }
63
64   if(name.empty())
65     throw std::runtime_error("Error: Sprite wihtout name.");
66   if(actions.empty())
67     throw std::runtime_error("Error: Sprite wihtout actions.");
68 }
69
70 SpriteData::~SpriteData()
71 {
72   for(Actions::iterator i=actions.begin(); i != actions.end(); ++i)
73     delete i->second;
74 }
75
76 void
77 SpriteData::parse_action(LispReader& lispreader)
78 {
79   Action* action = new Action;
80
81   if(!lispreader.read_string("name", action->name)) {
82     if(!actions.empty())
83       throw std::runtime_error(
84           "If there are more than one action, they need names!");
85   }
86   lispreader.read_int("x-offset", action->x_offset);
87   lispreader.read_int("y-offset", action->y_offset);
88   lispreader.read_int("z-order", action->z_order);
89   lispreader.read_float("fps",     action->fps);
90
91   /* TODO: add a top filter entry */
92   std::vector <int> mask_color;
93   lispreader.read_int_vector("apply-mask", mask_color);
94   if(mask_color.size() == 4) {
95     for(std::vector<Surface*>::iterator i = action->surfaces.begin();
96         i < action->surfaces.end(); i++) {
97       (*i)->apply_filter(MASK_FILTER, Color(mask_color));
98     }
99   }
100
101   std::string mirror_action;
102   lispreader.read_string("mirror-action", mirror_action);
103   if(!mirror_action.empty()) {
104     Action* act_tmp = get_action(mirror_action);
105     if(act_tmp == NULL) {
106       throw std::runtime_error("Could not mirror action. Action not found\n"
107                    "Mirror actions must be defined after the real one!");
108     } else {
109       for(int i = 0; static_cast<unsigned int>(i) < act_tmp->surfaces.size();
110           i++) {
111         Surface* surface = new Surface(sdl_surface_from_sdl_surface(
112               act_tmp->surfaces[i]->impl->get_sdl_surface(), true), true);
113         surface->apply_filter(HORIZONTAL_FLIP_FILTER);
114         action->surfaces.push_back(surface);
115       }
116     }
117   } else { // Load images
118     std::vector<std::string> images;
119     if(!lispreader.read_string_vector("images", images)) {
120       std::stringstream msg;
121       msg << "Sprite '" << name << "' contains no images in action '"
122           << action->name << "'.";
123       throw std::runtime_error(msg.str());
124     }
125
126     for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) {
127       action->surfaces.push_back(
128           new Surface(datadir + "/images/" + images[i], true));
129     }
130   }
131   actions[action->name] = action;
132 }
133
134 SpriteData::Action*
135 SpriteData::get_action(std::string act)
136 {
137   Actions::iterator i = actions.find(act);
138   if(i == actions.end()) {
139     std::cerr << "Warning: Action '" << act <<
140       "' not found on Sprite '" << name << "'\n";
141     return 0;
142   }
143   return i->second;
144 }
145
146 }