Removed trailing whitespace from all *.?pp files
[supertux.git] / src / object / background.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "object/background.hpp"
18
19 #include <iostream>
20 #include <math.h>
21 #include <stdexcept>
22
23 #include "math/sizef.hpp"
24 #include "supertux/globals.hpp"
25 #include "supertux/object_factory.hpp"
26 #include "supertux/sector.hpp"
27 #include "util/log.hpp"
28 #include "util/reader.hpp"
29
30 Background::Background() :
31   alignment(NO_ALIGNMENT),
32   layer(LAYER_BACKGROUND0),
33   imagefile_top(),
34   imagefile(),
35   imagefile_bottom(),
36   pos(),
37   speed(),
38   speed_y(),
39   scroll_speed(),
40   scroll_offset(),
41   image_top(),
42   image(),
43   image_bottom()
44 {
45 }
46
47 Background::Background(const Reader& reader) :
48   alignment(NO_ALIGNMENT),
49   layer(LAYER_BACKGROUND0),
50   imagefile_top(),
51   imagefile(),
52   imagefile_bottom(),
53   pos(),
54   speed(),
55   speed_y(),
56   scroll_speed(),
57   scroll_offset(),
58   image_top(),
59   image(),
60   image_bottom()
61 {
62   // read position, defaults to (0,0)
63   float px = 0;
64   float py = 0;
65   reader.get("x", px);
66   reader.get("y", py);
67   this->pos = Vector(px,py);
68
69   speed = 1.0;
70   speed_y = 1.0;
71
72   std::string alignment_str;
73   if (reader.get("alignment", alignment_str))
74   {
75     if (alignment_str == "left")
76     {
77       alignment = LEFT_ALIGNMENT;
78     }
79     else if (alignment_str == "right")
80     {
81       alignment = RIGHT_ALIGNMENT;
82     }
83     else if (alignment_str == "top")
84     {
85       alignment = TOP_ALIGNMENT;
86     }
87     else if (alignment_str == "bottom")
88     {
89       alignment = BOTTOM_ALIGNMENT;
90     }
91     else if (alignment_str == "none")
92     {
93       alignment = NO_ALIGNMENT;
94     }
95     else
96     {
97       log_warning << "Background: invalid alignment: '" << alignment_str << "'" << std::endl;
98       alignment = NO_ALIGNMENT;
99     }
100   }
101
102   reader.get("scroll-offset-x", scroll_offset.x);
103   reader.get("scroll-offset-y", scroll_offset.y);
104
105   reader.get("scroll-speed-x", scroll_speed.x);
106   reader.get("scroll-speed-y", scroll_speed.y);
107
108   layer = reader_get_layer (reader, /* default = */ LAYER_BACKGROUND0);
109
110   if(!reader.get("image", imagefile) || !reader.get("speed", speed))
111     throw std::runtime_error("Must specify image and speed for background");
112
113   set_image(imagefile, speed);
114   if (!reader.get("speed-y", speed_y))
115   {
116     speed_y = speed;
117   }
118
119   if (reader.get("image-top", imagefile_top)) {
120     image_top = Surface::create(imagefile_top);
121   }
122   if (reader.get("image-bottom", imagefile_bottom)) {
123     image_bottom = Surface::create(imagefile_bottom);
124   }
125 }
126
127 Background::~Background()
128 {
129 }
130
131 void
132 Background::update(float delta)
133 {
134   scroll_offset += scroll_speed * delta;
135 }
136
137 void
138 Background::set_image(const std::string& name, float speed)
139 {
140   this->imagefile = name;
141   this->speed = speed;
142
143   image = Surface::create(name);
144 }
145
146 void
147 Background::draw_image(DrawingContext& context, const Vector& pos)
148 {
149   Sizef level(Sector::current()->get_width(), Sector::current()->get_height());
150   Sizef screen(SCREEN_WIDTH, SCREEN_HEIGHT);
151   Sizef parallax_image_size = (1.0f - speed) * screen + level * speed;
152   Rectf cliprect = context.get_cliprect();
153
154   int start_x = static_cast<int>(floorf((cliprect.get_left()  - (pos.x - image->get_width() /2.0f)) / image->get_width()));
155   int end_x   = static_cast<int>(ceilf((cliprect.get_right()  - (pos.x + image->get_width() /2.0f)) / image->get_width()))+1;
156   int start_y = static_cast<int>(floorf((cliprect.get_top()   - (pos.y - image->get_height()/2.0f)) / image->get_height()));
157   int end_y   = static_cast<int>(ceilf((cliprect.get_bottom() - (pos.y + image->get_height()/2.0f)) / image->get_height()))+1;
158
159   switch(alignment)
160   {
161     case LEFT_ALIGNMENT:
162       for(int y = start_y; y < end_y; ++y)
163       {
164         Vector p(pos.x - parallax_image_size.width / 2.0f,
165                  pos.y + y * image->get_height()  - image->get_height() / 2.0f);
166         context.draw_surface(image, p, layer);
167       }
168       break;
169
170     case RIGHT_ALIGNMENT:
171       for(int y = start_y; y < end_y; ++y)
172       {
173         Vector p(pos.x + parallax_image_size.width / 2.0f - image->get_width(),
174                  pos.y + y * image->get_height() - image->get_height() / 2.0f);
175         context.draw_surface(image, p, layer);
176       }
177       break;
178
179     case TOP_ALIGNMENT:
180       for(int x = start_x; x < end_x; ++x)
181       {
182         Vector p(pos.x + x * image->get_width() - image->get_width() / 2.0f,
183                  pos.y - parallax_image_size.height / 2.0f);
184         context.draw_surface(image, p, layer);
185       }
186       break;
187
188     case BOTTOM_ALIGNMENT:
189       for(int x = start_x; x < end_x; ++x)
190       {
191         Vector p(pos.x + x * image->get_width()  - image->get_width() / 2.0f,
192                  pos.y - image->get_height() + parallax_image_size.height / 2.0f);
193         context.draw_surface(image, p, layer);
194       }
195       break;
196
197     case NO_ALIGNMENT:
198       for(int y = start_y; y < end_y; ++y)
199         for(int x = start_x; x < end_x; ++x)
200         {
201           Vector p(pos.x + x * image->get_width()  - image->get_width()/2,
202                    pos.y + y * image->get_height() - image->get_height()/2);
203
204           if (image_top.get() != NULL && (y < 0))
205           {
206             context.draw_surface(image_top, p, layer);
207           }
208           else if (image_bottom.get() != NULL && (y > 0))
209           {
210             context.draw_surface(image_bottom, p, layer);
211           }
212           else
213           {
214             context.draw_surface(image, p, layer);
215           }
216         }
217       break;
218   }
219 }
220
221 void
222 Background::draw(DrawingContext& context)
223 {
224   if(image.get() == NULL)
225     return;
226
227   Sizef level_size(Sector::current()->get_width(),
228                    Sector::current()->get_height());
229   Sizef screen(SCREEN_WIDTH, SCREEN_HEIGHT);
230   Sizef translation_range = level_size - screen;
231   Vector center_offset(context.get_translation().x - translation_range.width  / 2.0f,
232                        context.get_translation().y - translation_range.height / 2.0f);
233
234   // FIXME: We are not handling 'pos'
235   draw_image(context, Vector(level_size.width / 2.0f, level_size.height / 2.0f) + center_offset * (1.0f - speed));
236 }
237
238 /* EOF */