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 | |
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_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 | |
41 | Sprite::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 | |
54 | Sprite::~Sprite() |
55 | { |
56 | } |
57 | |
58 | SpritePtr |
59 | Sprite::clone() const |
60 | { |
61 | return SpritePtr(new Sprite(*this)); |
62 | } |
63 | |
64 | void |
65 | Sprite::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 | |
84 | void |
85 | Sprite::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 | |
100 | bool |
101 | Sprite::animation_done() const |
102 | { |
103 | return m_animation_loops == 0; |
104 | } |
105 | |
106 | void |
107 | Sprite::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 | |
135 | void |
136 | Sprite::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 | |
158 | int |
159 | Sprite::get_width() const |
160 | { |
161 | assert(m_frameidx < get_frames()); |
162 | return static_cast<int>(m_action->surfaces[m_frameidx]->get_width()); |
163 | } |
164 | |
165 | int |
166 | Sprite::get_height() const |
167 | { |
168 | assert(m_frameidx < get_frames()); |
169 | return static_cast<int>(m_action->surfaces[m_frameidx]->get_height()); |
170 | } |
171 | |
172 | float |
173 | Sprite::get_current_hitbox_x_offset() const |
174 | { |
175 | return m_action->x_offset; |
176 | } |
177 | |
178 | float |
179 | Sprite::get_current_hitbox_y_offset() const |
180 | { |
181 | return m_action->y_offset; |
182 | } |
183 | |
184 | float |
185 | Sprite::get_current_hitbox_width() const |
186 | { |
187 | return m_action->hitbox_w; |
188 | } |
189 | |
190 | float |
191 | Sprite::get_current_hitbox_height() const |
192 | { |
193 | return m_action->hitbox_h; |
194 | } |
195 | |
196 | Rectf |
197 | Sprite::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 | |
202 | void |
203 | Sprite::set_angle(float a) |
204 | { |
205 | m_angle = a; |
206 | } |
207 | |
208 | float |
209 | Sprite::get_angle() const |
210 | { |
211 | return m_angle; |
212 | } |
213 | |
214 | void |
215 | Sprite::set_color(const Color& c) |
216 | { |
217 | m_color = c; |
218 | } |
219 | |
220 | Color |
221 | Sprite::get_color() const |
222 | { |
223 | return m_color; |
224 | } |
225 | |
226 | void |
227 | Sprite::set_blend(const Blend& b) |
228 | { |
229 | m_blend = b; |
230 | } |
231 | |
232 | Blend |
233 | Sprite::get_blend() const |
234 | { |
235 | return m_blend; |
236 | } |
237 | |
238 | /* EOF */ |
239 | |