--- /dev/null
+#ifndef __RECTANGLE_H__
+#define __RECTANGLE_H__
+
+#include <assert.h>
+#include "vector.h"
+
+namespace SuperTux
+{
+
+/** This class represents a rectangle.
+ * (Implementation Note) We're using upper left and lower right point instead of
+ * upper left and width/height here, because that makes the collision dectection
+ * a little bit efficienter.
+ */
+class Rectangle
+{
+public:
+ Rectangle()
+ { }
+
+ Rectangle(const Vector& np1, const Vector& np2)
+ : p1(np1), p2(np2)
+ {
+ }
+
+ Rectangle(float x1, float y1, float x2, float y2)
+ : p1(x1, y1), p2(x2, y2)
+ {
+ assert(p1.x <= p2.x && p1.y <= p2.y);
+ }
+
+ float get_width() const
+ { return p2.x - p1.x; }
+
+ float get_height() const
+ { return p2.y - p1.y; }
+
+ Vector get_middle() const
+ { return Vector((p1.x+p2.x)/2, (p1.y+p2.y)/2); }
+
+ void set_pos(const Vector& v)
+ {
+ move(v-p1);
+ }
+
+ void set_height(float height)
+ {
+ p2.y = p1.y + height;
+ }
+ void set_width(float width)
+ {
+ p2.x = p1.x + width;
+ }
+ void set_size(float width, float height)
+ {
+ set_width(width);
+ set_height(height);
+ }
+
+ void move(const Vector& v)
+ {
+ p1 += v;
+ p2 += v;
+ }
+
+ bool inside(const Vector& v) const
+ {
+ return v.x >= p1.x && v.y >= p1.y && v.x < p2.x && v.y < p2.y;
+ }
+ bool inside(const Rectangle& other) const
+ {
+ if(p1.x >= other.p2.x || other.p1.x >= p2.x)
+ return false;
+ if(p1.y >= other.p2.y || other.p1.y >= p2.y)
+ return false;
+
+ return true;
+ }
+
+ // leave these 2 public to safe the headaches of set/get functions for such
+ // simple things :)
+
+ /// upper left edge
+ Vector p1;
+ /// lower right edge
+ Vector p2;
+};
+
+}
+
+#endif
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include <config.h>
+
+#include <iostream>
+#include <cmath>
+#include <sstream>
+#include <stdexcept>
+
+#include "../app/globals.h"
+#include "../app/setup.h"
+#include "../special/sprite.h"
+#include "../video/drawing_context.h"
+
+namespace SuperTux
+{
+
+SpriteData::Action::Action()
+{
+ x_offset = 0;
+ y_offset = 0;
+ z_order = 0;
+ fps = 10;
+}
+
+SpriteData::Action::~Action()
+{
+ for(std::vector<Surface*>::iterator i = surfaces.begin();
+ i != surfaces.end(); ++i)
+ delete *i;
+}
+
+SpriteData::SpriteData(lisp_object_t* cur)
+{
+ for(; !lisp_nil_p(cur); cur = lisp_cdr(cur)) {
+ std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
+ lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
+ LispReader reader(lisp_cdr(lisp_car(cur)));
+
+ if(token == "name")
+ name = lisp_string(data);
+ else if(token == "action")
+ parse_action(reader);
+ else
+ std::cerr << "Warning: Unknown sprite field: " << token << std::endl;
+ }
+
+ if(name.empty())
+ throw std::runtime_error("Error: Sprite wihtout name.");
+ if(actions.empty())
+ throw std::runtime_error("Error: Sprite wihtout actions.");
+}
+
+SpriteData::~SpriteData()
+{
+ for(Actions::iterator i=actions.begin(); i != actions.end(); ++i)
+ delete i->second;
+}
+
+void
+SpriteData::parse_action(LispReader& lispreader)
+{
+ Action* action = new Action;
+
+ if(!lispreader.read_string("name", action->name)) {
+ if(!actions.empty())
+ throw std::runtime_error(
+ "If there are more than one action, they need names!");
+ }
+ lispreader.read_int("x-offset", action->x_offset);
+ lispreader.read_int("y-offset", action->y_offset);
+ lispreader.read_int("z-order", action->z_order);
+ lispreader.read_float("fps", action->fps);
+
+ /* TODO: add a top filter entry */
+ std::vector <int> mask_color;
+ lispreader.read_int_vector("apply-mask", mask_color);
+ if(mask_color.size() == 4) {
+ for(std::vector<Surface*>::iterator i = action->surfaces.begin();
+ i < action->surfaces.end(); i++) {
+ (*i)->apply_filter(MASK_FILTER, Color(mask_color));
+ }
+ }
+
+ std::string mirror_action;
+ lispreader.read_string("mirror-action", mirror_action);
+ if(!mirror_action.empty()) {
+ Action* act_tmp = get_action(mirror_action);
+ if(act_tmp == NULL) {
+ throw std::runtime_error("Could not mirror action. Action not found\n"
+ "Mirror actions must be defined after the real one!");
+ } else {
+ for(int i = 0; static_cast<unsigned int>(i) < act_tmp->surfaces.size();
+ i++) {
+ Surface* surface = new Surface(sdl_surface_from_sdl_surface(
+ act_tmp->surfaces[i]->impl->get_sdl_surface(), true), true);
+ surface->apply_filter(HORIZONTAL_FLIP_FILTER);
+ action->surfaces.push_back(surface);
+ }
+ }
+ } else { // Load images
+ std::vector<std::string> images;
+ if(!lispreader.read_string_vector("images", images)) {
+ std::stringstream msg;
+ msg << "Sprite '" << name << "' contains no images in action '"
+ << action->name << "'.";
+ throw std::runtime_error(msg.str());
+ }
+
+ for(std::vector<std::string>::size_type i = 0; i < images.size(); i++) {
+ action->surfaces.push_back(
+ new Surface(datadir + "/images/" + images[i], true));
+ }
+ }
+ actions[action->name] = action;
+}
+
+SpriteData::Action*
+SpriteData::get_action(std::string act)
+{
+ Actions::iterator i = actions.find(act);
+ if(i == actions.end()) {
+ std::cerr << "Warning: Action '" << act <<
+ "' not found on Sprite '" << name << "'\n";
+ return 0;
+ }
+ return i->second;
+}
+
+}