Skip to content

Commit

Permalink
Added SPR_setAnimationLoop(..) method to enable/disable animation loop
Browse files Browse the repository at this point in the history
also added SPR_setAlwaysAtBottom(..) method because why not..
  • Loading branch information
Stephane-D committed Dec 1, 2023
1 parent 516c297 commit 2e37c3c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 17 deletions.
44 changes: 37 additions & 7 deletions inc/sprite_eng.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,14 @@
* Special flag to indicate that we want to add the sprite at position 0 (head / top) in the list<br>
* instead of adding it in last / bottom position (default)
*/
#define SPR_FLAG_INSERT_HEAD 0x2000
#define SPR_FLAG_INSERT_HEAD 0x4000
/**
* \brief
* Disable animation auto loop..<br>
* By default animation always restart fater the last frame has been played.
* This flag prevent the animation to restart and so the animation end on the last frame forever (see #SPR_getAnimationDone(..))
*/
#define SPR_FLAG_DISABLE_ANIMATION_LOOP 0x2000
/**
* \brief
* Disable delaying of frame update when we are running out of DMA capacity.<br>
Expand All @@ -68,7 +75,7 @@
* \brief
* Enable fast visibility calculation (only meaningful if SPR_FLAG_AUTO_VISIBILITY is used).<br>
* If you set this flag the automatic visibility calculation will be done globally for the (meta) sprite and not per internal
* hardware sprite. This result in faster visibility computation at the expense of some waste of hardware sprite.
* hardware sprite. This result in faster visibility computation at the expense of using extra (wasting) hardware sprites.
*/
#define SPR_FLAG_FAST_AUTO_VISIBILITY 0x0100

Expand Down Expand Up @@ -214,7 +221,7 @@ typedef struct
* \param tileset
* tileset containing tiles for this animation frame (ordered for sprite)
* \param collision
* collision structure
* collision structure (not used currently)
* \param frameSprites
* array of VDP sprites info composing the frame
*/
Expand Down Expand Up @@ -746,12 +753,21 @@ void SPR_setZ(Sprite* sprite, s16 value);
* Set sprite depth so it remains above others sprite - same as SPR_setDepth(SPR_MIN_DEPTH)
*
* \param sprite
* Sprite to set depth for
* Sprite to change depth for
*
* Sprite having lower depth are display in front of sprite with higher depth.<br>
* The sprite is *immediately* sorted when its depth value is changed.
* \see SPR_setDepth(Sprite*)
*/
void SPR_setAlwaysOnTop(Sprite* sprite);
/**
* \brief
* Set sprite depth so it remains behind others sprite - same as SPR_setDepth(SPR_MAX_DEPTH)
*
* \param sprite
* Sprite to change depth for
*
* \see SPR_setDepth(Sprite*)
*/
void SPR_setAlwaysAtBottom(Sprite* sprite);

/**
* \brief
Expand Down Expand Up @@ -793,13 +809,27 @@ void SPR_setFrame(Sprite* sprite, s16 frame);
* Sprite to pass to next frame for
*/
void SPR_nextFrame(Sprite* sprite);

/**
* \brief
* Enable/disable animation loop (default is on).<br>
* When disable the sprite will stay on the last animation frame forever when animation ended instead of restarting it.
*
* \param sprite
* Sprite we want to enable/disable animation loop for.
*
* \see SPR_FLAG_DISABLE_ANIMATION_LOOP
* \see #SPR_getAnimationDone(Sprite*)
*/
void SPR_setAnimationLoop(Sprite* sprite, bool value);
/**
* \brief
* Return TRUE if animation ended / looped.<br>
* This can be used with the frame change callback (see #SPR_setFrameChangeCallback(..)) to detect
* the end of sprite animation and do appropriate action if required.
*
* \see #SPR_setFrameChangeCallback(..)
* \see SPR_FLAG_DISABLE_ANIMATION_LOOP
* \see #SPR_setAnimationLoop(Sprite*)
*/
bool SPR_getAnimationDone(Sprite* sprite);

Expand Down
43 changes: 33 additions & 10 deletions src/sprite_eng.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

#define NEED_UPDATE 0x000F

#define STATE_LOOPED 0x0010
#define STATE_ANIMATION_DONE 0x0010


// shared from vdp_spr.c unit
Expand Down Expand Up @@ -401,9 +401,8 @@ Sprite* NO_INLINE SPR_addSpriteEx(const SpriteDefinition* spriteDef, s16 x, s16

sprite->x = x + 0x80;
sprite->y = y + 0x80;
// depending sprite position (first or last) we set its default depth
if (flag & SPR_FLAG_INSERT_HEAD) sprite->depth = SPR_MIN_DEPTH >> 1;
else sprite->depth = SPR_MAX_DEPTH >> 1;
// default depth
sprite->depth = 0;

// auto VRAM alloc enabled ?
if (flag & SPR_FLAG_AUTO_VRAM_ALLOC)
Expand Down Expand Up @@ -960,6 +959,11 @@ void SPR_setAlwaysOnTop(Sprite* sprite)
SPR_setDepth(sprite, SPR_MIN_DEPTH);
}

void SPR_setAlwaysAtBottom(Sprite* sprite)
{
SPR_setDepth(sprite, SPR_MAX_DEPTH);
}

void SPR_setAnimAndFrame(Sprite* sprite, s16 anim, s16 frame)
{
START_PROFIL
Expand Down Expand Up @@ -998,7 +1002,7 @@ void SPR_setAnimAndFrame(Sprite* sprite, s16 anim, s16 frame)
KLog_U3("SPR_setAnimAndFrame: #", getSpriteIndex(sprite), " anim=", anim, " frame=", frame);
#endif // SPR_DEBUG

sprite->status = (sprite->status & ~STATE_LOOPED) | NEED_FRAME_UPDATE;
sprite->status = (sprite->status & ~STATE_ANIMATION_DONE) | NEED_FRAME_UPDATE;
}

END_PROFIL(PROFIL_SET_ANIM_FRAME)
Expand Down Expand Up @@ -1033,7 +1037,7 @@ void SPR_setAnim(Sprite* sprite, s16 anim)
KLog_U2_("SPR_setAnim: #", getSpriteIndex(sprite), " anim=", anim, " frame=0");
#endif // SPR_DEBUG

sprite->status = (sprite->status & ~STATE_LOOPED) | NEED_FRAME_UPDATE;
sprite->status = (sprite->status & ~STATE_ANIMATION_DONE) | NEED_FRAME_UPDATE;
}

END_PROFIL(PROFIL_SET_ANIM_FRAME)
Expand Down Expand Up @@ -1083,9 +1087,15 @@ void SPR_nextFrame(Sprite* sprite)

if (frameInd >= anim->numFrame)
{
frameInd = anim->loop;
// looped animation marker
sprite->status |= STATE_LOOPED;
u16 status = sprite->status;

// no loop ? --> stay on last frame
if (status & SPR_FLAG_DISABLE_ANIMATION_LOOP) frameInd = anim->numFrame - 1;
// loop
else frameInd = anim->loop;

// animation done marker
sprite->status = status | STATE_ANIMATION_DONE;
}

// set new frame
Expand All @@ -1094,9 +1104,22 @@ void SPR_nextFrame(Sprite* sprite)
END_PROFIL(PROFIL_SET_ANIM_FRAME)
}

void SPR_setAnimationLoop(Sprite* sprite, bool value)
{
// for debug
checkSpriteValid(sprite, "SPR_setAnimationLoop");

if (value) sprite->status &= ~SPR_FLAG_DISABLE_ANIMATION_LOOP;
else sprite->status |= SPR_FLAG_DISABLE_ANIMATION_LOOP;
}


bool SPR_getAnimationDone(Sprite* sprite)
{
return (sprite->status & STATE_LOOPED)?TRUE:FALSE;
// for debug
checkSpriteValid(sprite, "SPR_getAnimationDone");

return (sprite->status & STATE_ANIMATION_DONE)?TRUE:FALSE;
}

bool SPR_setVRAMTileIndex(Sprite* sprite, s16 value)
Expand Down

0 comments on commit 2e37c3c

Please sign in to comment.