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