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