/**
* \file sprite_eng.h
* \brief Sprite engine
* \author Stephane Dallongeville
* \date 10/2013
*
* Sprite engine providing advanced sprites manipulation and operations.
* This unit use both the vram memory manager (see vram.h file for more info)
* and the Sega Genesis VDP sprite capabilities (see vdp_spr.h file for more info).
*/
#if !LEGACY_SPRITE_ENGINE
#ifndef _SPRITE_ENG_H_
#define _SPRITE_ENG_H_
#include "vdp_tile.h"
#include "vdp_spr.h"
#include "pal.h"
#include "pool.h"
/**
* \brief
* No collision type
*/
#define COLLISION_TYPE_NONE 0
/**
* \brief
* Bouding box collision type (Box structure)
*/
#define COLLISION_TYPE_BOX 1
/**
* \brief
* Round circle collision type (Circle structure)
*/
#define COLLISION_TYPE_CIRCLE 2
/**
* \brief
* Special flag to indicate that we want to add the sprite at position 0 (head / top) in the list
* instead of adding it in last / bottom position (default)
*/
#define SPR_FLAG_INSERT_HEAD 0x4000
/**
* \brief
* Disable animation auto loop.
* By default animation always restart after 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.
* By default we delay the frame update when DMA is already full so the frame update happen as soon we have enough DMA capacity to do it.
* This flag forces frame update to always happen immediately but that may cause graphical glitches.
*/
#define SPR_FLAG_DISABLE_DELAYED_FRAME_UPDATE 0x1000
/**
* \brief
* Enable automatic VRAM allocation
*/
#define SPR_FLAG_AUTO_VRAM_ALLOC 0x0800
/**
* \brief
* Enable automatic upload of sprite tiles data into VRAM
*/
#define SPR_FLAG_AUTO_TILE_UPLOAD 0x0400
/**
* \brief
* Enable automatic visibility calculation
*/
#define SPR_FLAG_AUTO_VISIBILITY 0x0200
/**
* \brief
* Enable fast visibility calculation (only meaningful if SPR_FLAG_AUTO_VISIBILITY is used).
* 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 using extra (wasting) hardware sprites.
*/
#define SPR_FLAG_FAST_AUTO_VISIBILITY 0x0100
/**
* \brief
* Mask for sprite flag
*/
#define SPR_FLAG_MASK (SPR_FLAG_INSERT_HEAD | SPR_FLAG_DISABLE_DELAYED_FRAME_UPDATE | SPR_FLAG_AUTO_VRAM_ALLOC | SPR_FLAG_AUTO_TILE_UPLOAD | SPR_FLAG_AUTO_VISIBILITY | SPR_FLAG_FAST_AUTO_VISIBILITY)
/**
* \brief
* Minimum depth for a sprite (always above others sprites)
*/
#define SPR_MIN_DEPTH (-0x8000)
/**
* \brief
* Maximum depth for a sprite (always below others sprites)
*/
#define SPR_MAX_DEPTH 0x7FFF
/**
* \brief
* Sprite visibility enumeration
*/
typedef enum
{
VISIBLE, /**< Sprite is visible (no computation needed) */
HIDDEN, /**< Sprite is hidden (no computation needed) */
AUTO_FAST, /**< Automatic visibility calculation - FAST (computation made on global meta sprite) */
AUTO_SLOW, /**< Automatic visibility calculation - SLOW (computation made per hardware sprite) */
} SpriteVisibility;
/**
* \brief
* Simple Box structure for collision
*
* \param x
* X position (left)
* \param y
* Y position (top)
* \param w
* width
* \param h
* heigth
*/
typedef struct
{
s8 x;
s8 y;
u8 w;
u8 h;
} BoxCollision;
/**
* \brief
* Simple Circle structure (can be used for collision detection)
*
* \param x
* X center position
* \param y
* Y center position
* \param ray
* circle ray
*/
typedef struct
{
s8 x;
s8 y;
u16 ray;
} CircleCollision;
/**
* \struct Collision
* \brief
* Collision definition union.
*
* \param typeHit
* Collision type for hit collision:
* Allowed values are #COLLISION_TYPE_BOX or #COLLISION_TYPE_CIRCLE.
* \param typeAttack
* Collision type for attack collision (can be used as alternative hit collision):
* Allowed values are #COLLISION_TYPE_BOX or #COLLISION_TYPE_CIRCLE.
* \param box
* BoxCollision definition if type = #COLLISION_TYPE_BOX
* \param circle
* CircleCollision definition if type = #COLLISION_TYPE_CIRCLE
* \param inner
* if current collision is verified then we test inner for more precise collision if needed
* \param next
* if current collision is not verified then we test next for next collision if needed
*/
typedef struct _collision
{
u8 typeHit;
u8 typeAttack;
union
{
BoxCollision box;
CircleCollision circle;
} hit;
union
{
BoxCollision box;
CircleCollision circle;
} attack;
} Collision;
/**
* \brief
* Single VDP sprite info structure for sprite animation frame.
*
* \param offsetY
* Y offset for this VDP sprite relative to global Sprite position
* \param offsetYFlip
* Y offset (flip version) for this VDP sprite relative to global Sprite position
* \param size
* sprite size (see SPRITE_SIZE macro)
* \param offsetX
* X offset for this VDP sprite relative to global Sprite position
* \param offsetXFlip
* X offset (flip version) for this VDP sprite relative to global Sprite position
* \param numTile
* number of tile for this VDP sprite (should be coherent with the given size field)
*/
typedef struct
{
u8 offsetY; // respect VDP sprite field order, may help
u8 offsetYFlip;
u8 size;
u8 offsetX;
u8 offsetXFlip;
u8 numTile;
} FrameVDPSprite;
/**
* \brief
* Sprite animation frame structure.
*
* \param numSprite
* number of VDP sprite which compose this frame.
* bit 7 is used as a special flag for the sprite engine so always use 'numSprite & 0x7F' to just retrieve the number of sprite
* \param timer
* active time for this frame (in 1/60 of second)
* \param tileset
* tileset containing tiles for this animation frame (ordered for sprite)
* \param collision
* collision structure (not used currently)
* \param frameSprites
* array of VDP sprites info composing the frame
*/
typedef struct
{
s8 numSprite;
u8 timer;
TileSet* tileset; // TODO: have a tileset per VDP sprite --> probably not a good idea performance wise
Collision* collision; // Require many DMA queue operations and fast DMA flush as well, also bring extra computing in calculating delayed update
FrameVDPSprite frameVDPSprites[];
} AnimationFrame;
/**
* \brief
* Sprite animation structure.
*
* \param numFrame
* number of different frame for this animation (max = 255)
* \param loop
* frame index for loop (last index if no loop)
* \param frames
* frames composing the animation
*/
typedef struct
{
u8 numFrame;
u8 loop;
AnimationFrame** frames;
} Animation;
/**
* \brief
* Sprite definition structure.
*
* \param w
* frame cell width in pixel
* \param h
* frame cell height in pixel
* \param palette
* default palette data
* \param numAnimation
* number of animation for this sprite
* \param animations
* animation definitions
* \param maxNumTile
* maximum number of tile used by a single animation frame (used for VRAM tile space allocation)
* \param maxNumSprite
* maximum number of VDP sprite used by a single animation frame (used for VDP sprite allocation)
*
* Contains all animations for a Sprite and internal informations.
*/
typedef struct
{
u16 w;
u16 h;
Palette* palette;
u16 numAnimation;
Animation** animations;
u16 maxNumTile;
u16 maxNumSprite;
} SpriteDefinition;
/**
* \brief
* Sprite structure used by the Sprite Engine to store state for a sprite.
* WARNING: always use the #SPR_addSprite(..) method to allocate Sprite object.
*
* \param status
* Internal state and automatic allocation information (internal)
* \param visibility
* visibility information of current frame for each VDP sprite (max = 16)
* \param spriteDef
* Sprite definition pointer
* \param onFrameChange
* Custom callback on frame change event (see #SPR_setFrameChangeCallback(..) method)
* \param animation
* Animation pointer cache (internal)
* \param frame
* AnimationFrame pointer cache (internal)
* \param animInd
* current animation index (internal)
* \param frameInd
* current frame animation index (internal)
* \param timer
* timer for current frame (internal)
* \param x
* current sprite X position on screen offseted by 0x80 (internal VDP position)
* \param y
* current sprite Y position on screen offseted by 0x80 (internal VDP position)
* \param depth
* current sprite depth (Z) position used for Z sorting
* \param attribut
* sprite specific attribut and allocated VRAM tile index (see TILE_ATTR_FULL() macro)
* \param data
* this is a free field for user data, use it for whatever you want (flags, pointer...)
* \param prev
* pointer on previous Sprite in list
* \param next
* pointer on next Sprite in list
*
* Used to manage an active sprite in game condition.
*/
typedef struct Sprite
{
u16 status;
u16 visibility;
const SpriteDefinition* definition;
void (*onFrameChange)(struct Sprite* sprite);
Animation* animation;
AnimationFrame* frame;
s16 animInd;
s16 frameInd;
s16 timer;
s16 x;
s16 y;
s16 depth;
u16 attribut;
u32 data;
struct Sprite* prev;
struct Sprite* next;
} Sprite;
/**
* \brief
* Sprite frame change event callback.
*
* \param sprite
* The sprite for which frame just changed.
*
* This event occurs onframe change process during #SPR_update() call (CAUTION: sprite->status field is not up to date at this point).
* It let opportunity to the developer to apply special behavior or process when sprite frame just changed:
* for instance we can disable animation looping by setting sprite->timer to 0 when we meet the last animation frame.
*/
typedef void FrameChangeCallback(Sprite* sprite);
/**
* Sprites object pool for the sprite engine
*/
extern Pool* spritesPool;
/**
* First allocated sprite (NULL if no sprite allocated)
*/
extern Sprite* firstSprite;
/**
* Last allocated sprite (NULL if no sprite allocated)
*/
extern Sprite* lastSprite;
/**
* Allocated VRAM (in tile) for Sprite Engine
*/
extern u16 spriteVramSize;
/**
* \brief
* Initialize the Sprite engine with default parameters.
*
* Initialize the sprite engine using default parameters (420 reserved tiles in VRAM).
* This also initialize the hardware sprite allocation system.
*
* \see SPR_initEx(void)
* \see SPR_end(void)
*/
void SPR_init(void);
/**
* \brief
* Init the Sprite engine with specified advanced parameters (VRAM allocation size and decompression buffer size).
*
* \param vramSize
* size (in tile) of the VRAM region for the automatic VRAM tile allocation.
* If set to 0 the default size is used (420 tiles)
*
* Initialize the sprite engine.
* This allocates a VRAM region for sprite tiles and initialize hardware sprite allocation system.
*
* \see SPR_init(void)
* \see SPR_end(void)
*/
void SPR_initEx(u16 vramSize);
/**
* \brief
* End the Sprite engine.
*
* End the sprite engine and release attached resources.
* This releases the allocated VRAM region and hardware sprites.
*/
void SPR_end(void);
/**
* \brief
* FALSE if sprite cache engine is not initialized, TRUE otherwise.
*/
bool SPR_isInitialized(void);
/**
* \brief
* Reset the Sprite engine.
*
* This method releases all allocated sprites and their resources.
*/
void SPR_reset(void);
/**
* \brief
* Adds a new sprite with specified parameters and returns it.
*
* \param spriteDef
* the SpriteDefinition data to assign to this sprite.
* \param x
* default X position.
* \param y
* default Y position.
* \param attribut
* sprite attribut (see TILE_ATTR() macro).
* \param flag
* specific settings for this sprite:
* #SPR_FLAG_DISABLE_DELAYED_FRAME_UPDATE = Disable delaying of frame update when we are running out of DMA capacity.
* If you set this flag then sprite frame update always happen immediately but may lead to some graphical glitches (tiles data and sprite table data not synchronized).
* You can use SPR_setDelayedFrameUpdate(..) method to change this setting.
* #SPR_FLAG_AUTO_VISIBILITY = Enable automatic sprite visibility calculation (you can also use SPR_setVisibility(..) method).
* #SPR_FLAG_FAST_AUTO_VISIBILITY = Enable fast computation for the automatic visibility calculation (disabled by default)
* 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.
* You can set the automatic visibility computation by using SPR_setVisibility(..) method.
* #SPR_FLAG_AUTO_VRAM_ALLOC = Enable automatic VRAM allocation (enabled by default)
* If you don't set this flag you will have to manually define VRAM tile index position for this sprite with the attribut parameter or by using the #SPR_setVRAMTileIndex(..) method
* #SPR_FLAG_AUTO_TILE_UPLOAD = Enable automatic upload of sprite tiles data into VRAM (enabled by default)
* If you don't set this flag you will have to manually upload tiles data of sprite into the VRAM (you can change this setting using #SPR_setAutoTileUpload(..) method).
* #SPR_FLAG_INSERT_HEAD = Allow to insert the sprite at the start/head of the list.
* When you use this flag the sprite will be inserted at the head of the list making it top most (equivalent to #SPR_setDepth(#SPR_MIN_DEPTH))
* while default insertion position is at the end of the list (equivalent to #SPR_setDepth(#SPR_MAX_DEPTH))
*
* It's recommended to use the following default settings:
* SPR_FLAG_AUTO_VISIBILITY | SPR_FLAG_AUTO_VRAM_ALLOC | SPR_FLAG_AUTO_TILE_UPLOAD
* \return the new sprite or NULL if the operation failed (some logs can be generated in the KMod console in this case)
*
* By default the sprite uses the provided flag setting for automatic resources allocation and sprite visibility computation.
* If auto visibility is not enabled then sprite is considered as not visible by default (see SPR_setVisibility(..) method).
* You can release all sprite resources by using SPR_releaseSprite(..) or SPR_reset(..).
* IMPORTANT NOTE: sprite allocation can fail (return NULL) when you are using auto VRAM allocation (SPR_FLAG_AUTO_VRAM_ALLOC) even if there is enough VRAM available,
* this can happen because of the VRAM fragmentation. You can use #SPR_addSpriteExSafe(..) method instead so it take care about VRAM fragmentation.
*
* \see SPR_addSprite(..)
* \see SPR_addSpriteExSafe(..)
* \see SPR_releaseSprite(..)
*/
Sprite* SPR_addSpriteEx(const SpriteDefinition* spriteDef, s16 x, s16 y, u16 attribut, u16 flag);
/**
* \brief
* Adds a new sprite with auto resource allocation enabled and returns it.
*
* \param spriteDef
* the SpriteDefinition data to assign to this sprite.
* \param x
* default X position.
* \param y
* default Y position.
* \param attribut
* sprite attribut (see TILE_ATTR() macro).
* \return the new sprite or NULL if the operation failed (some logs can be generated in the KMod console in this case)
*
* By default the sprite uses automatic resources allocation (VRAM and hardware sprite) and visibility is set to ON.
* You can change these defaults settings later by calling SPR_setVRAMTileIndex(..), SPR_setAutoTileUpload(..) and SPR_setVisibility(..) methods.
* You can release all sprite resources by using SPR_releaseSprite(..) or SPR_reset(..).
* IMPORTANT NOTE: sprite allocation can fail (return NULL) because of automatic VRAM allocation even if there is enough VRAM available,
* this can happen because of the VRAM fragmentation.
You can use #SPR_addSpriteSafe(..) method instead so it take care about VRAM fragmentation.
*
* \see SPR_addSpriteEx(..)
* \see SPR_addSpriteSafe(..)
* \see SPR_releaseSprite(..)
*/
Sprite* SPR_addSprite(const SpriteDefinition* spriteDef, s16 x, s16 y, u16 attribut);
/**
* \brief
* Adds a new sprite with specified parameters and returns it.
*
* \param spriteDef
* the SpriteDefinition data to assign to this sprite.
* \param x
* default X position.
* \param y
* default Y position.
* \param attribut
* sprite attribut (see TILE_ATTR() macro).
* \param flag
* specific settings for this sprite:
* #SPR_FLAG_DISABLE_DELAYED_FRAME_UPDATE = Disable delaying of frame update when we are running out of DMA capacity.
* If you set this flag then sprite frame update always happen immediately but may lead to some graphical glitches (tiles data and sprite table data not synchronized).
* You can use SPR_setDelayedFrameUpdate(..) method to change this setting.
* #SPR_FLAG_AUTO_VISIBILITY = Enable automatic sprite visibility calculation (you can also use SPR_setVisibility(..) method).
* #SPR_FLAG_FAST_AUTO_VISIBILITY = Enable fast computation for the automatic visibility calculation (disabled by default)
* 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 (scanline limit).
* You can set the automatic visibility computation by using SPR_setVisibility(..) method.
* #SPR_FLAG_AUTO_VRAM_ALLOC = Enable automatic VRAM allocation (enabled by default)
* If you don't set this flag you will have to manually define VRAM tile index position for this sprite with the attribut parameter or by using the #SPR_setVRAMTileIndex(..) method
* #SPR_FLAG_AUTO_TILE_UPLOAD = Enable automatic upload of sprite tiles data into VRAM (enabled by default)
* If you don't set this flag you will have to manually upload tiles data of sprite into the VRAM (you can change this setting using #SPR_setAutoTileUpload(..) method).
* #SPR_FLAG_INSERT_HEAD = Allow to insert the sprite at the start/head of the list.
* When you use this flag the sprite will be inserted at the head of the list making it top most (equivalent to #SPR_setDepth(#SPR_MIN_DEPTH))
* while default insertion position is at the end of the list (equivalent to #SPR_setDepth(#SPR_MAX_DEPTH))
*
* It's recommended to use the following default settings:
* SPR_FLAG_AUTO_VISIBILITY | SPR_FLAG_AUTO_VRAM_ALLOC | SPR_FLAG_AUTO_TILE_UPLOAD
* \return the new sprite or NULL if the operation failed (some logs can be generated in the KMod console in this case)
*
* By default the sprite uses the provided flag setting for automatic resources allocation and sprite visibility computation.
* If auto visibility is not enabled then sprite is considered as not visible by default (see SPR_setVisibility(..) method).
* You can release all sprite resources by using SPR_releaseSprite(..) or SPR_reset(..).
*
* \see SPR_addSpriteSafe(..)
* \see SPR_addSpriteEx(..)
* \see SPR_releaseSprite(..)
*/
Sprite* SPR_addSpriteExSafe(const SpriteDefinition* spriteDef, s16 x, s16 y, u16 attribut, u16 flag);
/**
* \brief
* Adds a new sprite with auto resource allocation enabled and returns it.
*
* \param spriteDef
* the SpriteDefinition data to assign to this sprite.
* \param x
* default X position.
* \param y
* default Y position.
* \param attribut
* sprite attribut (see TILE_ATTR() macro).
* \return the new sprite or NULL if the operation failed (some logs can be generated in the KMod console in this case)
*
* By default the sprite uses automatic resources allocation (VRAM and hardware sprite) and visibility is set to ON.
* You can change these defaults settings later by calling SPR_setVRAMTileIndex(..), SPR_setAutoTileUpload(..) and SPR_setVisibility(..) methods.
* You can release all sprite resources by using SPR_releaseSprite(..) or SPR_reset(..).<
*
* \see SPR_addSpriteSafeEx(..)
* \see SPR_addSprite(..)
* \see SPR_releaseSprite(..)
*/
Sprite* SPR_addSpriteSafe(const SpriteDefinition* spriteDef, s16 x, s16 y, u16 attribut);
/**
* \brief
* Release the specified sprite (no more visible and release its resources).
*
* \param sprite
* Sprite to release
*
* This method release resources for the specified Sprite object and remove it from the screen at next SPR_update() call.
*
* \see SPR_releasesSprite(..)
*/
void SPR_releaseSprite(Sprite* sprite);
/**
* \brief
* Returns the number of active sprite (number of sprite added with SPR_addSprite(..) or SPR_addSpriteEx(..) methods).
*/
u16 SPR_getNumActiveSprite(void);
/**
* \brief
* Returns the (maximum) number of used VDP sprite from current active sprites (sum of maximum hardware sprite usage from all active sprites).
*/
u16 SPR_getUsedVDPSprite(void);
/**
* \brief
* Returns the current remaining free VRAM (in tile) for the sprite engine.
*/
u16 SPR_getFreeVRAM(void);
/**
* \brief
* Return the current largest free VRAM block size (in tile) for the sprite engine.
*/
u16 SPR_getLargestFreeVRAMBlock(void);
/**
* \brief
* Indicate that we want to prevent adding a new sprite if there is possibly not enough hardware sprite to display it
* (counting the maximum hardware sprite usage from all active sprites) and so this ensures to always display all of them.
* By default the sprite engine allow to add a new sprite even if we may run out of hardware sprite to display all of them,
* that can lead to some sprite disappearence in some situations but ultimately it allows to handle more active sprites at once.
*
* \see SPR_disableVDPSpriteChecking(..)
* \see SPR_getNumVDPSprite(..)
*/
void SPR_enableVDPSpriteChecking();
/**
* \brief
* Indicate that we allow the sprite engine to add a new sprite even if we may run out of hardware sprite to display all of them,
* that can lead to some sprite disappearence in some situation but ultimately it allows to handle more active sprites at once (default behavior).
*
* \see SPR_enableVDPSpriteChecking(..)
* \see SPR_getNumVDPSprite(..)
*/
void SPR_disableVDPSpriteChecking();
/**
* \brief
* Defragment allocated VRAM for sprites, that can help when sprite allocation fail (SPR_addSprite(..) or SPR_addSpriteEx(..) return NULL).
*/
void SPR_defragVRAM(void);
/**
* \brief
* Load all frames of SpriteDefinition using DMA at specified VRAM tile index and return the indexes table.
* WARNING: This function should be call at init/loading time as it can be quite long (several frames)
*
* \param sprDef
* the SpriteDefinition we want to load frame data in VRAM.
* \param index
* the tile position in VRAM where we will upload all sprite frame tiles data.
* \param totalNumTile
* if not NULL then the function will store here the total number of tile used to load all animation frames.
* \param tm
* Transfer method to upload sprite frame data.
* Accepted values are:
* - CPU
* - DMA
* - DMA_QUEUE
* - DMA_QUEUE_COPY
*
* Load all frames of spriteDef at specified VRAM tile index and return the indexes table.
* The returned index table is a dynamically allocated 2D table[anim][frame] so you need to release it using #MEM_free(..)
* when you don't need the table anymore.
* You can use the frame change callback (see #SPR_setFrameChangeCallback(..)) to automatically update the VRAM index using the indexes table:
* frameIndexes = SPR_loadAllFrames(sprite->definition, ind);
* SPR_setFrameChangeCallback(sprite, &frameChanged);
* ....
* void frameChanged(Sprite* sprite)
* {
* u16 tileIndex = frameIndexes[sprite->animInd][sprite->frameInd];
* SPR_setVRAMTileIndex(sprite, tileIndex);
* }
*
* \return the 2D indexes table or NULL if there is not enough memory to allocate the table.
* \see SPR_setFrameChangeCallback(...);
*/
u16** SPR_loadAllFramesEx(const SpriteDefinition* sprDef, u16 index, u16* totalNumTile, TransferMethod tm);
/**
* \brief
* Same as all frames of SpriteDefinition at specified VRAM tile index and return the indexes table.
* WARNING: This function should be call at init/loading time as it can be quite long (several frames)
*
* \param sprDef
* the SpriteDefinition we want to load frame data in VRAM.
* \param index
* the tile position in VRAM where we will upload all sprite frame tiles data.
* \param totalNumTile
* if not NULL then the function will store here the total number of tile used to load all animation frames.
*
* Load all frames of spriteDef (using DMA) at specified VRAM tile index and return the indexes table.
* The returned index table is a dynamically allocated 2D table[anim][frame] so you need to release it using #MEM_free(..)
* when you don't need the table anymore.
* You can use the frame change callback (see #SPR_setFrameChangeCallback(..)) to automatically update the VRAM index using the indexes table:
* frameIndexes = SPR_loadAllFrames(sprite->definition, ind);
* SPR_setFrameChangeCallback(sprite, &frameChanged);
* ....
* void frameChanged(Sprite* sprite)
* {
* u16 tileIndex = frameIndexes[sprite->animInd][sprite->frameInd];
* SPR_setVRAMTileIndex(sprite, tileIndex);
* }
*
* \return the 2D indexes table or NULL if there is not enough memory to allocate the table.
* \see SPR_setFrameChangeCallback(...);
*/
u16** SPR_loadAllFrames(const SpriteDefinition* sprDef, u16 index, u16* totalNumTile);
/**
* \brief
* Same as #SPR_loadAllFrames(..) but only computes the indexes table without actually loading the Sprite frame data to VRAM (see #SPR_loadAllTiles(..) for that).
*
* \param sprDef
* the SpriteDefinition we want to compute the indexes table.
* \param index
* the tile position in VRAM where we want to upload all sprite frame data (note that VRAM data upload won't be done here).
* \param totalNumTile
* if not NULL then the function will store here the total number of tile used to load all animation frames.
*
* \return the 2D indexes table or NULL if there is not enough memory to allocate the table.
* \see SPR_loadAllFrames(...)
* \see SPR_loadAllTiles(...)
*/
u16** SPR_loadAllIndexes(const SpriteDefinition* sprDef, u16 index, u16* totalNumTile);
/**
* \brief
* Same as #SPR_loadAllFrames(..) but only perform the Sprite tile data upload process, SPR_loadAllIndexes(..) should be called first to compute the indexes table.
*
* \param sprDef
* the SpriteDefinition we want to load frame data in VRAM.
* \param index
* the tile position in VRAM where we will upload all sprite frame tiles data.
* \param index
* the 2D indexes table providing the tile index position in VRAM for each sprite frame (previously build using #SPR_loadAllIndexes(..) method).
* \param tm
* Transfer method to upload sprite frame data.
* Accepted values are:
* - CPU
* - DMA
* - DMA_QUEUE
* - DMA_QUEUE_COPY
*
* \return the number of tile uploaded to VRAM.
* \see SPR_loadAllFrames(...)
* \see SPR_loadAllIndexes(...)
*/
u16 SPR_loadAllTiles(const SpriteDefinition* sprDef, u16 index, u16** indexes, const TransferMethod tm);
/**
* \brief
* Set the Sprite Definition.
*
* \param sprite
* Sprite to set definition for.
* \param spriteDef
* the SpriteDefinition data to assign to this sprite.
*
* Set the Sprite Definition for this sprite.
* By default the first frame of the first animation from Sprite Definition is loaded.
*
* \return FALSE if auto resource allocation failed, TRUE otherwise.
*/
bool SPR_setDefinition(Sprite* sprite, const SpriteDefinition* spriteDef);
/**
* \brief
* Get sprite position X.
*/
s16 SPR_getPositionX(Sprite* sprite);
/**
* \brief
* Get sprite position Y.
*/
s16 SPR_getPositionY(Sprite* sprite);
/**
* \brief
* Set sprite position.
*
* \param sprite
* Sprite to set position for
* \param x
* X position
* \param y
* Y position
*/
void SPR_setPosition(Sprite* sprite, s16 x, s16 y);
/**
* \brief
* Set sprite Horizontal Flip attribut.
*
* \param sprite
* Sprite to set attribut for
* \param value
* The horizontal flip attribut value (TRUE or FALSE)
*/
void SPR_setHFlip(Sprite* sprite, bool value);
/**
* \brief
* Set sprite Vertical Flip attribut.
*
* \param sprite
* Sprite to set attribut for
* \param value
* The vertical flip attribut value (TRUE or FALSE)
*/
void SPR_setVFlip(Sprite* sprite, bool value);
/**
* \brief
* Set sprite Palette index to use.
*
* \param sprite
* Sprite to set attribut for
* \param value
* The palette index to use for this sprite (PAL0, PAL1, PAL2 or PAL3)
*/
void SPR_setPalette(Sprite* sprite, u16 value);
/**
* \brief
* Set sprite Priority attribut.
*
* \param sprite
* Sprite to set attribut for
* \param value
* The priority attribut value (TRUE or FALSE)
*/
void SPR_setPriority(Sprite* sprite, bool value);
/**
* \deprecated
* Use #SPR_setPriority(..) instead
*/
#define SPR_setPriorityAttribut(sprite, value) _Pragma("GCC error \"This method is deprecated, use SPR_setPriority(..) instead.\"")
/**
* \brief
* Set sprite depth (for sprite display ordering)
*
* \param sprite
* Sprite to set depth for
* \param value
* The depth value (SPR_MIN_DEPTH to set always on top)
*
* Sprite having lower depth are display in front of sprite with higher depth.
* The sprite is *immediately* sorted when its depth value is changed.
*/
void SPR_setDepth(Sprite* sprite, s16 value);
/**
* \brief
* Same as #SPR_setDepth(..)
*/
void SPR_setZ(Sprite* sprite, s16 value);
/**
* \brief
* Set sprite depth so it remains above others sprite - same as SPR_setDepth(SPR_MIN_DEPTH)
*
* \param sprite
* Sprite to change depth for
*
* \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
* Set current sprite animation and frame.
*
* \param sprite
* Sprite to set animation and frame for
* \param anim
* animation index to set
* \param frame
* frame index to set
*/
void SPR_setAnimAndFrame(Sprite* sprite, s16 anim, s16 frame);
/**
* \brief
* Set current sprite animation.
*
* \param sprite
* Sprite to set animation for
* \param anim
* animation index to set.
*/
void SPR_setAnim(Sprite* sprite, s16 anim);
/**
* \brief
* Set current sprite frame.
*
* \param sprite
* Sprite to set frame for
* \param frame
* frame index to set.
*/
void SPR_setFrame(Sprite* sprite, s16 frame);
/**
* \brief
* Pass to the next sprite frame.
*
* \param sprite
* Sprite to pass to next frame for
*/
void SPR_nextFrame(Sprite* sprite);
/**
* \brief
* Enable/disable auto animation for the current animation (default is on).
*
* \param sprite
* Sprite we want to enable/disable auto animation.
* \param value
* TRUE to enable auto animation (default), FALSE otherwise
*
* \see #SPR_getAutoAnimation(Sprite*)
*/
void SPR_setAutoAnimation(Sprite* sprite, bool value);
/**
* \brief
* Return TRUE if auto animation is enabled, FALSE otherwise.
*
* \see #SPR_setAnimationLoop(Sprite*, bool)
*/
bool SPR_getAutoAnimation(Sprite* sprite);
/**
* \brief
* Enable/disable animation loop (default is on).
* When disable the sprite will stay on the last animation frame when animation ended instead of restarting it.
*
* \param sprite
* Sprite we want to enable/disable animation loop for.
* \param value
* TRUE to enable animation loop (default), FALSE otherwise
*
* \see SPR_FLAG_DISABLE_ANIMATION_LOOP
* \see #SPR_getAnimationDone(Sprite*)
*/
void SPR_setAnimationLoop(Sprite* sprite, bool value);
/**
* \brief
* Returns TRUE if the sprite reached the end of the current animation.
* When auto animation is enabled (see SPR_setAutoAnimation(..)) the function returns TRUE only when we reached
* the last *tick* of the last animation frame.
* When auto animation is disabled the function returns TRUE as soon we are on last animation frame.
*
* \see #SPR_setAutoAnimation(Sprite*, bool)
*/
bool SPR_isAnimationDone(Sprite* sprite);
/**
* \brief
* Set the VRAM tile position reserved for this sprite.
*
* \param sprite
* Sprite to set the VRAM tile position for
* \param value
* the tile position in VRAM where we will upload the sprite tiles data.
* Use -1 for auto allocation.
* \return FALSE if auto allocation failed (can happen only if sprite is currently active), TRUE otherwise
*
* By default the Sprite Engine auto allocate VRAM for sprites tiles but you can force
* manual allocation and fix the sprite tiles position in VRAM with this method.
*/
bool SPR_setVRAMTileIndex(Sprite* sprite, s16 value);
/**
* \brief
* Enable/disable the automatic upload of sprite tiles data into VRAM.
*
* \param sprite
* Sprite we want to enable/disable auto tile upload for
* \param value
* TRUE to enable the automatic upload of sprite tiles data into VRAM.
* FALSE to disable it (mean you have to handle that on your own).
*/
void SPR_setAutoTileUpload(Sprite* sprite, bool value);
/**
* \brief
* Enable/disable the delayed frame update.
*
* \param sprite
* Sprite we want to enable/disable delayed frame update
* \param value
* TRUE to enable the delayed frame update when DMA is running out of transfert capacity (default).
* FALSE to disable it. In which case sprite frame is always updated immediately but that may cause graphical glitches (update during active display).
*
* \see #SPR_FLAG_DISABLE_DELAYED_FRAME_UPDATE
*/
void SPR_setDelayedFrameUpdate(Sprite* sprite, bool value);
/**
* \brief
* Set the frame change event callback for this sprite.
*
* \param sprite
* Sprite we want to set the frame change callback
* \param callback
* the callback (function pointer) to call when we just changed the animation frame for this sprite.
*
* The callback (if not NULL) will be called on frame change process during #SPR_update() call (CAUTION: sprite->status field is not up to date at this point).
* It let opportunity to the developer to apply special behavior or process when sprite frame just changed:
* for instance we can disable animation looping by setting sprite->timer to 0 when we meet the last animation frame.
*
* \see #FrameChangeCallback
*/
void SPR_setFrameChangeCallback(Sprite* sprite, FrameChangeCallback* callback);
/**
* \brief
* Return the visibility state for this sprite.
* WARNING: this is different from SPR_isVisible(..) method, possible value are:
* SpriteVisibility.VISIBLE = sprite is visible
* SpriteVisibility.HIDDEN = sprite is not visible
* SpriteVisibility.AUTO_FAST = visibility is automatically computed - global visibility (only using sprite X position)
* SpriteVisibility.AUTO_SLOW = visibility is automatically computed - per hardware sprite visibility (only using sprite X position)
*
* \param sprite
* Sprite to return visibility state
*
* \return
* the visibility state for this sprite.
*
* \see SPR_isVisible(...)
* \see SPR_setVisibility(...)
*/
SpriteVisibility SPR_getVisibility(Sprite* sprite);
/**
* \brief
* Return the visible state for this sprite (meaningful only if AUTO visibility is enabled, see #SPR_setVisibility(..) method).
*
* \param sprite
* Sprite to return visible state
* \param recompute
* Force visibility computation.
* Only required if SPR_update() wasn't called since last sprite position change (note that can force the frame update processing).
*
* Note that only the sprite X position is used to determine if it's visible (see #SPR_setVisibility(..) method for more information)
* \return
* the visible state for this sprite.
*
* \see SPR_setVisibility(...)
*/
bool SPR_isVisible(Sprite* sprite, bool recompute);
/**
* \brief
* Set the visibility state for this sprite.
*
* \param sprite
* Sprite to set the visibility information
* \param value
* Visibility value to set.
* SpriteVisibility.VISIBLE = sprite is visible
* SpriteVisibility.HIDDEN = sprite is not visible
* SpriteVisibility.AUTO_FAST = visibility is automatically computed - global visibility (only using sprite X position)
* SpriteVisibility.AUTO_SLOW = visibility is automatically computed - per hardware sprite visibility (only using sprite X position)
*
* The only interest in having a sprite hidden / not visible is to avoid having it consuming scanline sprite budget:
* The VDP is limited to a maximum of 20 sprites or 320 pixels of sprite per scanline (16 sprites/256 px in H32 mode).
* If we reach this limit, following sprites won't be renderer so it's important to try to optimize the number of sprites on a single scanline.
* When a sprite is set to not visible (automatically or manually), its position is set offscreen *vertically* so it won't eat
* anymore the scanline sprite rendering budget, only X position test is required for that so a sprite is determined not visible only using its X coordinate.
*
* \see SPR_computeVisibility(...)
* \see SPR_getVisibility(...)
* \see SPR_isVisible(...)
*/
void SPR_setVisibility(Sprite* sprite, SpriteVisibility value);
/**
* \deprecated Use #SPR_setVisibility(..) method instead.
*/
#define SPR_setAlwaysVisible(sprite, value) _Pragma("GCC error \"This method is deprecated, use SPR_setVisibility(..) instead.\"")
/**
* \deprecated Use #SPR_setVisibility(..) method instead.
*/
#define SPR_setNeverVisible(sprite, value) _Pragma("GCC error \"This method is deprecated, use SPR_setVisibility(..) instead.\"")
/**
* \deprecated Use SPR_isVisible(..) instead.
*/
#define SPR_computeVisibility(sprite) _Pragma("GCC error \"This method is deprecated, use SPR_isVisible(sprite, TRUE) instead.\"")
/**
* \brief
* Clear all displayed sprites.
*
* This method allow to quickly hide all sprites (without releasing their resources).
* Sprites can be displayed again just by calling SPR_update().
*/
void SPR_clear(void);
/**
* \brief
* Update and display the active list of sprite.
*
* This actually updates all internal active sprites states and prepare the sprite list
* cache to send it to the hardware (VDP) at Vint.
*
* \see #SPR_addSprite(..)
*/
void SPR_update(void);
/**
* \brief
* Log the profil informations (when enabled) in the KMod message window.
*/
void SPR_logProfil(void);
/**
* \brief
* Log the sprites informations (when enabled) in the KMod message window.
*/
void SPR_logSprites(void);
#endif // _SPRITE_ENG_H_
#endif