sftools  2.0 dev
Bunch of tools for SFML application development
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
LoopFrameStream.hpp
Go to the documentation of this file.
1 /*
2 
3  sftools - Copyright (c) 2012-2013 Marco Antognini <antognini.marco@gmail.com>
4 
5  This software is provided 'as-is', without any express or implied warranty. In
6  no event will the authors be held liable for any damages arising from the use
7  of this software.
8 
9  Permission is granted to anyone to use this software for any purpose, including
10  commercial applications, and to alter it and redistribute it freely, subject to
11  the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not claim
14  that you wrote the original software. If you use this software in a product,
15  an acknowledgment in the product documentation would be appreciated but is
16  not required.
17 
18  2. Altered source versions must be plainly marked as such, and must not be
19  misrepresented as being the original software.
20 
21  3. This notice may not be removed or altered from any source distribution.
22 
23  */
24 
30 #ifndef __SFTOOLS_LOOPFRAMESTREAM_HPP__
31 #define __SFTOOLS_LOOPFRAMESTREAM_HPP__
32 
33 #include <SFML/System/Time.hpp>
34 
36 
37 #include <vector>
38 #include <algorithm>
39 #include <stdexcept>
40 
45 namespace sftools
46 {
47 
71  {
72  public:
84  {
85  FromLeft = 0,
87  };
88 
100  {
101  FromTop = 0,
103  };
104 
116  {
119  };
120 
130  struct Settings
131  {
145  {
146  // That's it
147  }
148 
152  };
153 
154  public:
164  : m_count(0)
165  {
166  // We don't care about setting all default values
167  // because create will be called
168  }
169 
176  : m_count(stream.m_count)
177  , m_frameTime(stream.m_frameTime)
178  , m_loop(stream.m_loop)
179  , m_frames(stream.m_frames)
180  {
181  // That's it
182  }
183 
201  LoopFrameStream(sf::Texture const& texture,
202  sf::Vector2i frameSize,
203  sf::Vector2u frameCount,
204  sf::Time frameTime,
205  bool loop = true,
206  Settings const& settings = Settings())
207  {
208  create(texture, frameSize, frameCount, frameTime, loop, settings);
209  }
210 
218  {
219  m_count = rhs.m_count;
220  m_frameTime = rhs.m_frameTime;
221  m_loop = rhs.m_loop;
222  m_frames = rhs.m_frames;
223 
224  return *this;
225  }
226 
240  void create(sf::Texture const& texture,
241  sf::Vector2i frameSize,
242  sf::Vector2u frameCount,
243  sf::Time frameTime,
244  bool loop = true,
245  Settings const& settings = Settings())
246  {
247  // First, check some assertions
248  if (frameCount == sf::Vector2u(0, 0)) throw std::invalid_argument("frameCount can't be 0");
249  if (frameTime == sf::Time::Zero) throw std::invalid_argument("frameTime can't be 0");
250 
251  // Then copy some stuff
252  m_count = frameCount.x * frameCount.y;
253  m_frameTime = frameTime;
254  m_loop = loop;
255 
256  // And initialize some other stuff
257  m_frames.clear();
258  m_frames.reserve(m_count);
259 
260  // Now we can create the frames
261 
262  // Define the first point according to the choosen policies
263  int const initX = settings.horizontalPolicy == FromLeft ? 0 : texture.getSize().x - frameSize.x;
264  int const initY = settings.verticalPolicy == FromTop ? 0 : texture.getSize().y - frameSize.y;
265  int const stepX = settings.horizontalPolicy == FromLeft ? frameSize.x : -frameSize.x;
266  int const stepY = settings.verticalPolicy == FromTop ? frameSize.y : -frameSize.y;
267  int const endX = initX + frameCount.x * stepX;
268  int const endY = initY + frameCount.y * stepY;
269 
270  // Create the invariants
271  int x = 0;
272  int y = 0;
273 
274  // Set up the loop order (X or Y first ?) according to the choosen policy
275  int& first = settings.precedencePolicy == HorizontalFirst ? x : y;
276  int& second = settings.precedencePolicy == HorizontalFirst ? y : x;
277  int const& init1st = settings.precedencePolicy == HorizontalFirst ? initX : initY;
278  int const& init2nd = settings.precedencePolicy == HorizontalFirst ? initY : initX;
279  int const step1st = settings.precedencePolicy == HorizontalFirst ? stepX : stepY;
280  int const step2nd = settings.precedencePolicy == HorizontalFirst ? stepY : stepX;
281  int const end1st = settings.precedencePolicy == HorizontalFirst ? endX : endY;
282  int const end2nd = settings.precedencePolicy == HorizontalFirst ? endY : endX;
283 
284  // Finally we can go through the process of creating the frames
285  for (first = init1st; first < end1st; first += step1st)
286  {
287  for (second = init2nd; second < end2nd; second += step2nd)
288  {
289  sf::Vector2i point(x, y);
290  sf::IntRect area(point, frameSize);
291  m_frames.push_back(Frame(texture, area));
292  }
293  }
294  }
295 
308  virtual Frame getFrameAt(sf::Time time) const
309  {
310  if (m_count == 0) throw std::runtime_error("the stream was not properly initialized");
311 
312  unsigned int frameIndex = time.asMilliseconds() / m_frameTime.asMilliseconds();
313 
314  if (m_loop) frameIndex %= m_count;
315  else frameIndex = std::min(frameIndex, m_count - 1);
316 
317  return m_frames[frameIndex];
318  }
319 
320  private:
321  /* Setting variables */
322  unsigned int m_count;
323  sf::Time m_frameTime;
324  bool m_loop;
325 
326  /* State */
327  std::vector<Frame> m_frames;
328  };
329 
330 }
331 
332 #endif // __SFTOOLS_LOOPFRAMESTREAM_HPP__