ManaPlus
animatedsprite.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2017 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
24 
26 
27 #include "render/graphics.h"
28 
29 #include "resources/action.h"
31 
33 
34 #include "resources/image/image.h"
35 
37 
39 
41 
42 #include "utils/delete2.h"
43 #include "utils/likely.h"
44 #include "utils/mrand.h"
45 
46 #include "debug.h"
47 
48 bool AnimatedSprite::mEnableCache = false;
49 
51  mDirection(SpriteDirection::DOWN),
52  mLastTime(0),
53  mFrameIndex(0),
54  mFrameTime(0),
55  mSprite(sprite),
56  mAction(nullptr),
57  mAnimation(nullptr),
58  mFrame(nullptr),
59  mNumber(100),
60  mNumber1(100),
61  mDelayLoad(nullptr),
62  mTerminated(false)
63 {
64  mAlpha = 1.0F;
65 
66  // Take possession of the sprite
67  if (mSprite != nullptr)
68  mSprite->incRef();
69 }
70 
71 AnimatedSprite *AnimatedSprite::load(const std::string &restrict filename,
72  const int variant)
73 {
75  filename, variant);
76  if (s == nullptr)
77  return nullptr;
78  AnimatedSprite *restrict const as = new AnimatedSprite(s);
79 #ifdef DEBUG_ANIMATIONS
80  as->setSpriteName(filename);
81 #endif // DEBUG_ANIMATIONS
82 
83  as->play(SpriteAction::STAND);
84  s->decRef();
85  return as;
86 }
87 
89  filename,
90  const int variant)
91 {
92  if (!mEnableCache)
93  return load(filename, variant);
95  filename, variant);
96  if (res != nullptr)
97  {
98  res->decRef();
99  return load(filename, variant);
100  }
101 
102  AnimatedSprite *restrict const as = new AnimatedSprite(nullptr);
103 #ifdef DEBUG_ANIMATIONS
104  as->setSpriteName(filename);
105 #endif // DEBUG_ANIMATIONS
106 
107  as->play(SpriteAction::STAND);
108  as->setDelayLoad(filename, variant);
109  return as;
110 }
111 
113  anim)
114 {
115  if (anim == nullptr)
116  return nullptr;
117  AnimatedSprite *restrict const sprite = new AnimatedSprite(anim->mSprite);
118 #ifdef DEBUG_ANIMATIONS
119  sprite->setSpriteName(anim->getSpriteName());
120 #endif // DEBUG_ANIMATIONS
121 
122  sprite->play(SpriteAction::STAND);
123  return sprite;
124 }
125 
127 {
128  if (mSprite != nullptr)
129  {
130  mSprite->decRef();
131  mSprite = nullptr;
132  }
133  if (mDelayLoad != nullptr)
134  {
138  }
139 }
140 
142 {
143  const bool ret = mFrameIndex !=0 ||
144  mFrameTime != 0 ||
145  mLastTime != 0;
146 
147  mFrameIndex = 0;
148  mFrameTime = 0;
149  mLastTime = 0;
150 
151  if (mAnimation != nullptr)
152  mFrame = &mAnimation->mFrames[0];
153  else
154  mFrame = nullptr;
155  return ret;
156 }
157 
158 bool AnimatedSprite::play(const std::string &restrict spriteAction) restrict2
159 {
160  if (mSprite == nullptr)
161  {
162  if (mDelayLoad == nullptr)
163  return false;
164  mDelayLoad->setAction(spriteAction);
165  return true;
166  }
167 
168  const Action *const action = mSprite->getAction(spriteAction, mNumber);
169  if (action == nullptr)
170  return false;
171 
172  mAction = action;
173  const Animation *const animation = mAction->getAnimation(mDirection);
174 
175  if ((animation != nullptr) &&
176  animation != mAnimation &&
177  animation->getLength() > 0)
178  {
179  mAnimation = animation;
180  reset();
181 
182  return true;
183  }
184 
185  return false;
186 }
187 
189 {
190  // Avoid freaking out at first frame or when tick_time overflows
191  if (A_UNLIKELY(time < mLastTime || mLastTime == 0))
192  mLastTime = time;
193 
194  // If not enough time has passed yet, do nothing
195  if (time <= mLastTime || (mAnimation == nullptr))
196  return false;
197 
198  const unsigned int dt = time - mLastTime;
199  mLastTime = time;
200 
201  const Animation *restrict const animation = mAnimation;
202  const Frame *restrict const frame = mFrame;
203 
205  {
206  // Animation finished, reset to default
208  mTerminated = true;
209  }
210 
211  // Make sure something actually changed
212  return animation != mAnimation || frame != mFrame;
213 }
214 
216 {
217  // move code from Animation::isTerminator(*mFrame)
218  if (mFrame == nullptr ||
219  mAnimation == nullptr ||
220  (mFrame->image == nullptr && mFrame->type == FrameType::ANIMATION))
221  {
222  return false;
223  }
224 
225  mFrameTime += time;
226 
227  while ((mFrameTime > CAST_U32(mFrame->delay) &&
228  mFrame->delay > 0) ||
231  {
232  bool fail(true);
234  mFrameIndex++;
235 
237  mFrameIndex = 0;
238 
240  if (mFrame->type == FrameType::LABEL &&
241  !mFrame->nextAction.empty())
242  {
243  fail = false;
244  }
245  else if (mFrame->type == FrameType::GOTO &&
246  !mFrame->nextAction.empty())
247  {
248  const int rand = mFrame->rand;
249  if (rand == 100 ||
250  ((rand != 0) && rand >= mrand() % 100))
251  {
252  for (size_t i = 0; i < mAnimation->getLength(); i ++)
253  {
254  const Frame *restrict const frame =
255  &mAnimation->mFrames[i];
256  if (frame->type == FrameType::LABEL &&
257  mFrame->nextAction == frame->nextAction)
258  {
259  mFrameIndex = CAST_U32(i);
260  if (mFrameIndex >= CAST_U32(
261  mAnimation->getLength()))
262  {
263  mFrameIndex = 0;
264  }
265 
267 
268  fail = false;
269  break;
270  }
271  }
272  }
273  else
274  {
275  fail = false;
276  }
277  }
278  else if (mFrame->type == FrameType::JUMP &&
279  !mFrame->nextAction.empty())
280  {
281  const int rand = mFrame->rand;
282  if (rand == 100 ||
283  ((rand != 0) && rand >= mrand() % 100))
284  {
286  return true;
287  }
288  }
289  // copy code from Animation::isTerminator(*mFrame)
290  else if ((mFrame->image == nullptr) &&
292  {
293  const int rand = mFrame->rand;
294  if (rand == 100 ||
295  ((rand != 0) && rand >= mrand() % 100))
296  {
297  mAnimation = nullptr;
298  mFrame = nullptr;
299  return false;
300  }
301  }
302  else
303  {
304  const int rand = mFrame->rand;
305  if (rand == 100 ||
307  {
308  fail = false;
309  }
310  else
311  {
312  if ((rand != 0) && mrand() % 100 <= rand)
313  fail = false;
314  }
315  }
316  if (fail)
317  {
318  if (mFrame != nullptr)
319  mFrameTime = mFrame->delay + 1;
320  else
321  mFrameTime ++;
322  }
323  }
324  return true;
325 }
326 
328  const int posX,
329  const int posY) const restrict2
330 {
331  FUNC_BLOCK("AnimatedSprite::draw", 1)
332  if ((mFrame == nullptr) || (mFrame->image == nullptr))
333  return;
334 
335  Image *restrict const image = mFrame->image;
336  image->setAlpha(mAlpha);
337  graphics->drawImage(image,
338  posX + mFrame->offsetX, posY + mFrame->offsetY);
339 }
340 
342  const int posX,
343  const int posY,
344  const int dx,
345  const int dy) const restrict2
346 {
347  if (mFrame == nullptr ||
348  mFrame->image == nullptr)
349  {
350  return;
351  }
352 
353  Image *restrict const image = mFrame->image;
354  image->setAlpha(mAlpha);
355  graphics->drawRescaledImage(image,
356  posX + mFrame->offsetX,
357  posY + mFrame->offsetY,
358  dx,
359  dy);
360 }
361 
363  const int posX,
364  const int posY) const restrict2
365 {
366  if ((mFrame == nullptr) || (mFrame->image == nullptr))
367  return;
368 
369  Image *restrict const image = mFrame->image;
370  image->setAlpha(mAlpha);
371  graphics->drawImage(image,
372  posX,
373  posY);
374 }
375 
377  restrict2
378 {
379  if (mDirection != direction)
380  {
381  mDirection = direction;
382 
383  if (mAction == nullptr)
384  return false;
385 
386  const Animation *restrict const animation =
388 
389  if ((animation != nullptr) &&
390  animation != mAnimation &&
391  animation->getLength() > 0)
392  {
393  mAnimation = animation;
394  reset();
395  }
396 
397  return true;
398  }
399 
400  return false;
401 }
402 
404 {
405  if (mAnimation != nullptr)
406  return CAST_U32(mAnimation->getLength());
407  return 0;
408 }
409 
411 {
412  if ((mFrame != nullptr) && (mFrame->image != nullptr))
413  return mFrame->image->mBounds.w;
414  return 0;
415 }
416 
418 {
419  if ((mFrame != nullptr) && (mFrame->image != nullptr))
420  return mFrame->image->mBounds.h;
421  return 0;
422 }
423 
425 {
426  if (mSprite == nullptr)
427  return "";
428  return mSprite->mIdPath;
429 }
430 
432 {
433  return mFrame != nullptr ? mFrame->image : nullptr;
434 }
435 
437 {
438  mAlpha = alpha;
439 
440  if (mFrame != nullptr)
441  {
442  Image *restrict const image = mFrame->image;
443  if (image != nullptr)
444  image->setAlpha(mAlpha);
445  }
446 }
447 
449 {
450  if (mFrame != nullptr)
451  return mFrame;
452  return this;
453 }
454 
455 bool AnimatedSprite::updateNumber(const unsigned num) restrict2
456 {
457  if (mSprite == nullptr)
458  return false;
459 
460  if (mNumber1 != num)
461  {
462  mNumber1 = num;
463  mNumber = mSprite->findNumber(num);
464  if (mNumber == 0u)
465  {
466  mNumber = 100;
467  return false;
468  }
469  return true;
470  }
471  return false;
472 }
473 
474 void AnimatedSprite::setDelayLoad(const std::string &restrict filename,
475  const int variant) restrict2
476 {
477  if (mDelayLoad != nullptr)
478  {
481  delete mDelayLoad;
482  }
483  mDelayLoad = new AnimationDelayLoad(filename, variant, this);
485 }
#define CAST_U32
Definition: cast.h:30
unsigned int getFrameCount() const
std::string nextAction
Definition: frame.h:47
const Action * mAction
void setAction(const std::string &action)
int offsetX
Definition: frame.h:43
static void removeDelayLoad(const AnimationDelayLoad *const delayedLoad)
virtual void decRef()
Definition: resource.cpp:49
Definition: frame.h:37
void draw(Graphics *const graphics, const int posX, const int posY) const
const Animation * getAnimation(SpriteDirection::Type direction) const
Definition: action.cpp:45
static const std::string STAND("stand")
#define delete2(var)
Definition: delete2.h:24
#define A_UNLIKELY(x)
Definition: likely.h:29
const Animation * mAnimation
static AnimatedSprite * load(const std::string &filename, const int variant=0)
Definition: action.h:39
SpriteDef * getSprite(const std::string &path, const int variant=0)
bool setSpriteDirection(const SpriteDirection::Type direction)
const Action * getAction(const std::string &action, const unsigned num) const
Definition: spritedef.cpp:51
virtual void setAlpha(const float alpha)
Definition: image.cpp:285
static AnimatedSprite * clone(const AnimatedSprite *const anim)
static bool mEnableCache
int getHeight() const
static AnimatedSprite * delayedLoad(const std::string &filename, const int variant=0)
void drawRescaled(Graphics *const graphics, const int posX, const int posY, const int dx, const int dy) const
unsigned int mFrameIndex
bool updateNumber(const unsigned num)
AnimationDelayLoad * mDelayLoad
int delay
Definition: frame.h:42
std::string getIdPath() const
size_t getLength() const
Definition: animation.h:69
#define nullptr
Definition: localconsts.h:44
SpriteDef * mSprite
void drawRaw(Graphics *const graphics, const int posX, const int posY) const
#define FUNC_BLOCK(name, id)
Definition: perfomance.h:80
int offsetY
Definition: frame.h:44
virtual void incRef()
Definition: resource.cpp:37
Frames mFrames
Definition: animation.h:98
static void addDelayedAnimation(AnimationDelayLoad *const animation)
SpriteDirection::Type mDirection
void setAlpha(float alpha)
int getWidth() const
bool updateCurrentAnimation(const unsigned int dt)
int mrand()
Definition: mrand.cpp:40
unsigned int mFrameTime
AnimatedSprite(SpriteDef *const sprite)
Definition: image.h:61
const void * getHash() const
#define restrict
Definition: localconsts.h:176
void setDelayLoad(const std::string &filename, const int variant)
float mAlpha
Definition: sprite.h:129
int rand
Definition: frame.h:45
SDL_Rect mBounds
Definition: image.h:210
Resource * getFromCache(const std::string &filename, const int variant)
std::string mIdPath
Definition: resource.h:83
bool play(const std::string &spriteAction)
bool update(const int time)
const Image * getImage() const
unsigned findNumber(const unsigned num) const
Definition: spritedef.cpp:75
Image * image
Definition: frame.h:41
const Frame * mFrame
#define noexcept2
Definition: localconsts.h:49
#define restrict2
Definition: localconsts.h:177
FrameTypeT type
Definition: frame.h:46