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