Removed trailing whitespace from all *.?pp files
[supertux.git] / src / object / background.cpp
index a8c5edc..f49e05c 100644 (file)
@@ -1,12 +1,10 @@
-//  $Id$
+//  SuperTux
+//  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
 //
-//  SuperTux -  A Jump'n Run
-//  Copyright (C) 2004 Matthias Braun <matze@braunis.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 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 3 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
 //  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.
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+#include "object/background.hpp"
 
-#include <config.h>
+#include <iostream>
+#include <math.h>
+#include <stdexcept>
 
-#include "background.h"
-#include "app/globals.h"
-#include "camera.h"
-#include "video/drawing_context.h"
-#include "lisp/lisp.h"
-#include "lisp/writer.h"
-#include "object_factory.h"
+#include "math/sizef.hpp"
+#include "supertux/globals.hpp"
+#include "supertux/object_factory.hpp"
+#include "supertux/sector.hpp"
+#include "util/log.hpp"
+#include "util/reader.hpp"
 
-Background::Background()
-  : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
+Background::Background() :
+  alignment(NO_ALIGNMENT),
+  layer(LAYER_BACKGROUND0),
+  imagefile_top(),
+  imagefile(),
+  imagefile_bottom(),
+  pos(),
+  speed(),
+  speed_y(),
+  scroll_speed(),
+  scroll_offset(),
+  image_top(),
+  image(),
+  image_bottom()
 {
 }
 
-Background::Background(const lisp::Lisp& reader)
-  : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
+Background::Background(const Reader& reader) :
+  alignment(NO_ALIGNMENT),
+  layer(LAYER_BACKGROUND0),
+  imagefile_top(),
+  imagefile(),
+  imagefile_bottom(),
+  pos(),
+  speed(),
+  speed_y(),
+  scroll_speed(),
+  scroll_offset(),
+  image_top(),
+  image(),
+  image_bottom()
 {
-  reader.get("layer", layer);
-  if(reader.get("image", imagefile) 
-      && reader.get("speed", speed)) {
-    set_image(imagefile, speed);
-  } else {
-    std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
-    if(reader.get_vector("top_color", bkgd_top_color) &&
-        reader.get_vector("bottom_color", bkgd_bottom_color))
-      set_gradient(Color(bkgd_top_color), Color(bkgd_bottom_color));
+  // read position, defaults to (0,0)
+  float px = 0;
+  float py = 0;
+  reader.get("x", px);
+  reader.get("y", py);
+  this->pos = Vector(px,py);
+
+  speed = 1.0;
+  speed_y = 1.0;
+
+  std::string alignment_str;
+  if (reader.get("alignment", alignment_str))
+  {
+    if (alignment_str == "left")
+    {
+      alignment = LEFT_ALIGNMENT;
+    }
+    else if (alignment_str == "right")
+    {
+      alignment = RIGHT_ALIGNMENT;
+    }
+    else if (alignment_str == "top")
+    {
+      alignment = TOP_ALIGNMENT;
+    }
+    else if (alignment_str == "bottom")
+    {
+      alignment = BOTTOM_ALIGNMENT;
+    }
+    else if (alignment_str == "none")
+    {
+      alignment = NO_ALIGNMENT;
+    }
+    else
+    {
+      log_warning << "Background: invalid alignment: '" << alignment_str << "'" << std::endl;
+      alignment = NO_ALIGNMENT;
+    }
   }
-}
 
-Background::~Background()
-{
-  delete image;
+  reader.get("scroll-offset-x", scroll_offset.x);
+  reader.get("scroll-offset-y", scroll_offset.y);
+
+  reader.get("scroll-speed-x", scroll_speed.x);
+  reader.get("scroll-speed-y", scroll_speed.y);
+
+  layer = reader_get_layer (reader, /* default = */ LAYER_BACKGROUND0);
+
+  if(!reader.get("image", imagefile) || !reader.get("speed", speed))
+    throw std::runtime_error("Must specify image and speed for background");
+
+  set_image(imagefile, speed);
+  if (!reader.get("speed-y", speed_y))
+  {
+    speed_y = speed;
+  }
+
+  if (reader.get("image-top", imagefile_top)) {
+    image_top = Surface::create(imagefile_top);
+  }
+  if (reader.get("image-bottom", imagefile_bottom)) {
+    image_bottom = Surface::create(imagefile_bottom);
+  }
 }
 
-void
-Background::write(lisp::Writer& writer)
+Background::~Background()
 {
-  if(type == INVALID)
-    return;
-    
-  writer.start_list("background");
-
-  if(type == IMAGE) {
-    writer.write_string("image", imagefile);
-    writer.write_float("speed", speed);
-  } else if(type == GRADIENT) {
-    std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
-    bkgd_top_color.push_back(gradient_top.red);
-    bkgd_top_color.push_back(gradient_top.green);
-    bkgd_top_color.push_back(gradient_top.blue);
-    bkgd_bottom_color.push_back(gradient_top.red);
-    bkgd_bottom_color.push_back(gradient_top.green);
-    bkgd_bottom_color.push_back(gradient_top.blue);
-    writer.write_int_vector("top_color", bkgd_top_color);
-    writer.write_int_vector("bottom_color", bkgd_bottom_color);
-  }
-  writer.write_int("layer", layer);
-  
-  writer.end_list("background");
 }
 
 void
-Background::action(float)
+Background::update(float delta)
 {
+  scroll_offset += scroll_speed * delta;
 }
 
 void
 Background::set_image(const std::string& name, float speed)
 {
-  this->type = IMAGE;
   this->imagefile = name;
   this->speed = speed;
 
-  delete image;
-  image = new Surface(datadir + "/images/background/" + name, false);
+  image = Surface::create(name);
 }
 
 void
-Background::set_gradient(Color top, Color bottom)
+Background::draw_image(DrawingContext& context, const Vector& pos)
 {
-  type = GRADIENT;
-  gradient_top = top;
-  gradient_bottom = bottom;
+  Sizef level(Sector::current()->get_width(), Sector::current()->get_height());
+  Sizef screen(SCREEN_WIDTH, SCREEN_HEIGHT);
+  Sizef parallax_image_size = (1.0f - speed) * screen + level * speed;
+  Rectf cliprect = context.get_cliprect();
+
+  int start_x = static_cast<int>(floorf((cliprect.get_left()  - (pos.x - image->get_width() /2.0f)) / image->get_width()));
+  int end_x   = static_cast<int>(ceilf((cliprect.get_right()  - (pos.x + image->get_width() /2.0f)) / image->get_width()))+1;
+  int start_y = static_cast<int>(floorf((cliprect.get_top()   - (pos.y - image->get_height()/2.0f)) / image->get_height()));
+  int end_y   = static_cast<int>(ceilf((cliprect.get_bottom() - (pos.y + image->get_height()/2.0f)) / image->get_height()))+1;
+
+  switch(alignment)
+  {
+    case LEFT_ALIGNMENT:
+      for(int y = start_y; y < end_y; ++y)
+      {
+        Vector p(pos.x - parallax_image_size.width / 2.0f,
+                 pos.y + y * image->get_height()  - image->get_height() / 2.0f);
+        context.draw_surface(image, p, layer);
+      }
+      break;
+
+    case RIGHT_ALIGNMENT:
+      for(int y = start_y; y < end_y; ++y)
+      {
+        Vector p(pos.x + parallax_image_size.width / 2.0f - image->get_width(),
+                 pos.y + y * image->get_height() - image->get_height() / 2.0f);
+        context.draw_surface(image, p, layer);
+      }
+      break;
+
+    case TOP_ALIGNMENT:
+      for(int x = start_x; x < end_x; ++x)
+      {
+        Vector p(pos.x + x * image->get_width() - image->get_width() / 2.0f,
+                 pos.y - parallax_image_size.height / 2.0f);
+        context.draw_surface(image, p, layer);
+      }
+      break;
 
-  delete image;
-  image = new Surface(top, bottom, SCREEN_WIDTH, SCREEN_HEIGHT);
+    case BOTTOM_ALIGNMENT:
+      for(int x = start_x; x < end_x; ++x)
+      {
+        Vector p(pos.x + x * image->get_width()  - image->get_width() / 2.0f,
+                 pos.y - image->get_height() + parallax_image_size.height / 2.0f);
+        context.draw_surface(image, p, layer);
+      }
+      break;
+
+    case NO_ALIGNMENT:
+      for(int y = start_y; y < end_y; ++y)
+        for(int x = start_x; x < end_x; ++x)
+        {
+          Vector p(pos.x + x * image->get_width()  - image->get_width()/2,
+                   pos.y + y * image->get_height() - image->get_height()/2);
+
+          if (image_top.get() != NULL && (y < 0))
+          {
+            context.draw_surface(image_top, p, layer);
+          }
+          else if (image_bottom.get() != NULL && (y > 0))
+          {
+            context.draw_surface(image_bottom, p, layer);
+          }
+          else
+          {
+            context.draw_surface(image, p, layer);
+          }
+        }
+      break;
+  }
 }
 
 void
 Background::draw(DrawingContext& context)
 {
-  if(type == GRADIENT) {
-    context.push_transform();
-    context.set_translation(Vector(0, 0));
-    context.draw_surface(image, Vector(0, 0), layer);
-    context.pop_transform();
-  } else if(type == IMAGE) {
-    if(!image)
-      return;
-    
-    int sx = int(-context.get_translation().x * speed) % image->w - image->w;
-    int sy = int(-context.get_translation().y * speed) % image->h - image->h;
-    context.push_transform();
-    context.set_translation(Vector(0, 0));
-    for(int x = sx; x < SCREEN_WIDTH; x += image->w)
-      for(int y = sy; y < SCREEN_HEIGHT; y += image->h)
-        context.draw_surface(image, Vector(x, y), layer);
-    context.pop_transform();
-  }
+  if(image.get() == NULL)
+    return;
+
+  Sizef level_size(Sector::current()->get_width(),
+                   Sector::current()->get_height());
+  Sizef screen(SCREEN_WIDTH, SCREEN_HEIGHT);
+  Sizef translation_range = level_size - screen;
+  Vector center_offset(context.get_translation().x - translation_range.width  / 2.0f,
+                       context.get_translation().y - translation_range.height / 2.0f);
+
+  // FIXME: We are not handling 'pos'
+  draw_image(context, Vector(level_size.width / 2.0f, level_size.height / 2.0f) + center_offset * (1.0f - speed));
 }
 
-IMPLEMENT_FACTORY(Background, "background");
+/* EOF */