1 /*
2  * Copyright (C) 2006-2019 Christopho, Solarus - http://www.solarus-games.org
3  *
4  * Solarus 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  * Solarus 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 along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include "solarus/core/Debug.h"
18 #include "solarus/core/System.h"
19 #include "solarus/entities/AnimatedTilePattern.h"
20 #include "solarus/entities/ParallaxScrollingTilePattern.h"
21 #include "solarus/entities/Tileset.h"
22 #include "solarus/graphics/Surface.h"
23 
24 namespace Solarus {
25 
26 /**
27  * \brief Creates a multi-frame tile pattern.
28  * \param ground Kind of ground of the tile pattern.
29  * \param frames Rectangles in the tileset image.
30  * \param frame_delay Delay in milliseconds between each frame.
31  * \param mirror_loop Whether to play the animation backwards when it loops.
32  * \param parallax \c true to also set parallax scrolling to the tile pattern.
33  */
AnimatedTilePattern(Ground ground,const std::vector<Rectangle> & frames,uint32_t frame_delay,bool mirror_loop,bool parallax)34 AnimatedTilePattern::AnimatedTilePattern(
35     Ground ground,
36     const std::vector<Rectangle>& frames,
37     uint32_t frame_delay,
38     bool mirror_loop,
39     bool parallax
40 ):
41   TilePattern(ground, frames[0].get_size()),
42   frames(frames),
43   frame_delay(frame_delay),
44   mirror_loop(mirror_loop),
45   parallax(parallax),
46   frame_index(0),
47   next_frame_date(System::now() + frame_delay) {
48 
49   Debug::check_assertion(!this->frames.empty(), "Missing frames for animated pattern");
50 }
51 
52 /**
53  * \copydoc TilePattern::update
54  */
update()55 void AnimatedTilePattern::update() {
56 
57   uint32_t now = System::now();
58   while (now >= next_frame_date) {
59     if (!mirror_loop) {
60       frame_index = (frame_index + 1) % frames.size();
61     }
62     else {
63       frame_index = (frame_index + 1) % (2 * frames.size() - 2);
64     }
65     next_frame_date += frame_delay;
66   }
67 }
68 
69 /**
70  * \copydoc TilePattern::draw
71  */
draw(const SurfacePtr & dst_surface,const Point & dst_position,const Tileset & tileset,const Point & viewport) const72 void AnimatedTilePattern::draw(
73     const SurfacePtr& dst_surface,
74     const Point& dst_position,
75     const Tileset& tileset,
76     const Point& viewport
77 ) const {
78   const SurfacePtr& tileset_image = tileset.get_tiles_image();
79 
80   int final_frame_index = frame_index;
81   int num_frames = frames.size();
82   if (mirror_loop && frame_index >= num_frames) {
83     final_frame_index = (2 * frames.size() - 2) - frame_index;
84   }
85   Debug::check_assertion(final_frame_index >= 0 && final_frame_index < num_frames, "Wrong frame index");
86   const Rectangle& src = frames[final_frame_index];
87   Point dst = dst_position;
88 
89   if (parallax) {
90     dst += viewport / ParallaxScrollingTilePattern::ratio;
91   }
92 
93   tileset_image->draw_region(src, dst_surface, dst);
94 }
95 
96 /**
97  * \brief Returns whether tiles having this tile pattern are drawn at their
98  * position.
99  *
100  * Usually, this function returns true, and when it is the case, draw() is
101  * called only for tiles that are located in the current viewport.
102  *
103  * However, some tile patterns may want to be drawn even when they are not
104  * in the viewport, typically to make an illusion of movement like parallax
105  * scrolling.
106  *
107  * \return true to if this tile pattern is always drawn at its coordinates
108  */
is_drawn_at_its_position() const109 bool AnimatedTilePattern::is_drawn_at_its_position() const {
110   return !parallax;
111 }
112 
113 }
114 
115