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 "sprite/sprite.hpp"
18 
19 #include <assert.h>
20 
21 #include "supertux/globals.hpp"
22 #include "util/log.hpp"
23 #include "video/surface.hpp"
24 
Sprite(SpriteData & newdata)25 Sprite::Sprite(SpriteData& newdata) :
26   m_data(newdata),
27   m_frame(0),
28   m_frameidx(0),
29   m_animation_loops(-1),
30   m_last_ticks(),
31   m_angle(0.0f),
32   m_alpha(1.0f),
33   m_color(1.0f, 1.0f, 1.0f, 1.0f),
34   m_blend(),
35   m_action(m_data.get_action("normal"))
36 {
37   if (!m_action)
38     m_action = m_data.actions.begin()->second.get();
39   m_last_ticks = g_game_time;
40 }
41 
Sprite(const Sprite & other)42 Sprite::Sprite(const Sprite& other) :
43   m_data(other.m_data),
44   m_frame(other.m_frame),
45   m_frameidx(other.m_frameidx),
46   m_animation_loops(other.m_animation_loops),
47   m_last_ticks(g_game_time),
48   m_angle(0.0f), // FIXME: this can't be right
49   m_alpha(1.0f),
50   m_color(1.0f, 1.0f, 1.0f, 1.0f),
51   m_blend(),
52   m_action(other.m_action)
53 {
54 }
55 
~Sprite()56 Sprite::~Sprite()
57 {
58 }
59 
60 SpritePtr
clone() const61 Sprite::clone() const
62 {
63   return SpritePtr(new Sprite(*this));
64 }
65 
66 void
set_action(const std::string & name,int loops)67 Sprite::set_action(const std::string& name, int loops)
68 {
69   if (m_action && m_action->name == name)
70     return;
71 
72   const SpriteData::Action* newaction = m_data.get_action(name);
73   if (!newaction) {
74     log_debug << "Action '" << name << "' not found." << std::endl;
75     return;
76   }
77 
78   // If the new action has a loops property,
79   // we prefer that over the parameter.
80   m_animation_loops = newaction->has_custom_loops ? newaction->loops : loops;
81 
82   if (!m_action || m_action->family_name != newaction->family_name)
83   {
84     m_frame = 0;
85     m_frameidx = 0;
86   }
87 
88   m_action = newaction;
89 }
90 
91 void
set_action_continued(const std::string & name)92 Sprite::set_action_continued(const std::string& name)
93 {
94   if (m_action && m_action->name == name)
95     return;
96 
97   const SpriteData::Action* newaction = m_data.get_action(name);
98   if (!newaction) {
99     log_debug << "Action '" << name << "' not found." << std::endl;
100     return;
101   }
102 
103   m_action = newaction;
104   update();
105 }
106 
107 bool
animation_done() const108 Sprite::animation_done() const
109 {
110   return m_animation_loops == 0;
111 }
112 
113 void
update()114 Sprite::update()
115 {
116   float frame_inc = m_action->fps * (g_game_time - m_last_ticks);
117   m_last_ticks = g_game_time;
118 
119   m_frame += frame_inc;
120 
121   while (m_frame >= 1.0f) {
122     m_frame -= 1.0f;
123     m_frameidx++;
124   }
125 
126   while (m_frameidx >= get_frames() && !animation_done()) {
127     m_frameidx -= get_frames();
128     m_animation_loops--;
129   }
130 
131   if (animation_done()) {
132     m_frame = 0;
133     m_frameidx = get_frames() - 1;
134   }
135 
136   assert(m_frameidx < get_frames());
137 }
138 
139 void
draw(Canvas & canvas,const Vector & pos,int layer,Flip flip)140 Sprite::draw(Canvas& canvas, const Vector& pos, int layer,
141              Flip flip)
142 {
143   assert(m_action != nullptr);
144   update();
145 
146 
147   DrawingContext& context = canvas.get_context();
148   context.push_transform();
149 
150   context.set_flip(context.get_flip() ^ flip);
151   context.set_alpha(context.get_alpha() * m_alpha);
152 
153   canvas.draw_surface(m_action->surfaces[m_frameidx],
154                       pos - Vector(m_action->x_offset, m_action->y_offset),
155                       m_angle,
156                       m_color,
157                       m_blend,
158                       layer);
159 
160   context.pop_transform();
161 }
162 
163 int
get_width() const164 Sprite::get_width() const
165 {
166   assert(m_frameidx < get_frames());
167   return static_cast<int>(m_action->surfaces[m_frameidx]->get_width());
168 }
169 
170 int
get_height() const171 Sprite::get_height() const
172 {
173   assert(m_frameidx < get_frames());
174   return static_cast<int>(m_action->surfaces[m_frameidx]->get_height());
175 }
176 
177 float
get_current_hitbox_x_offset() const178 Sprite::get_current_hitbox_x_offset() const
179 {
180   return m_action->x_offset;
181 }
182 
183 float
get_current_hitbox_y_offset() const184 Sprite::get_current_hitbox_y_offset() const
185 {
186   return m_action->y_offset;
187 }
188 
189 float
get_current_hitbox_width() const190 Sprite::get_current_hitbox_width() const
191 {
192   return m_action->hitbox_w;
193 }
194 
195 float
get_current_hitbox_height() const196 Sprite::get_current_hitbox_height() const
197 {
198   return m_action->hitbox_h;
199 }
200 
201 Rectf
get_current_hitbox() const202 Sprite::get_current_hitbox() const
203 {
204   return Rectf(m_action->x_offset, m_action->y_offset, m_action->x_offset + m_action->hitbox_w, m_action->y_offset + m_action->hitbox_h);
205 }
206 
207 void
set_angle(float a)208 Sprite::set_angle(float a)
209 {
210   m_angle = a;
211 }
212 
213 float
get_angle() const214 Sprite::get_angle() const
215 {
216   return m_angle;
217 }
218 
219 void
set_alpha(float a)220 Sprite::set_alpha(float a)
221 {
222   m_alpha = a;
223 }
224 
225 float
get_alpha() const226 Sprite::get_alpha() const
227 {
228   return m_alpha;
229 }
230 
231 void
set_color(const Color & c)232 Sprite::set_color(const Color& c)
233 {
234   m_color = c;
235 }
236 
237 Color
get_color() const238 Sprite::get_color() const
239 {
240   return m_color;
241 }
242 
243 void
set_blend(const Blend & b)244 Sprite::set_blend(const Blend& b)
245 {
246   m_blend = b;
247 }
248 
249 Blend
get_blend() const250 Sprite::get_blend() const
251 {
252   return m_blend;
253 }
254 
255 /* EOF */
256