diff --git a/include/Tilengine.h b/include/Tilengine.h index 3ab5df8..0101676 100644 --- a/include/Tilengine.h +++ b/include/Tilengine.h @@ -59,8 +59,8 @@ /* version */ #define TILENGINE_VER_MAJ 2 -#define TILENGINE_VER_MIN 7 -#define TILENGINE_VER_REV 6 +#define TILENGINE_VER_MIN 8 +#define TILENGINE_VER_REV 0 #define TILENGINE_HEADER_VERSION ((TILENGINE_VER_MAJ << 16) | (TILENGINE_VER_MIN << 8) | TILENGINE_VER_REV) #define BITVAL(n) (1<<(n)) @@ -626,13 +626,12 @@ TLNAPI bool TLN_DeleteSequencePack (TLN_SequencePack sp); * @{ */ TLNAPI bool TLN_SetPaletteAnimation (int index, TLN_Palette palette, TLN_Sequence sequence, bool blend); TLNAPI bool TLN_SetPaletteAnimationSource (int index, TLN_Palette); -TLNAPI bool TLN_SetTilesetAnimation (int index, int nlayer, TLN_Sequence); -TLNAPI bool TLN_SetTilemapAnimation (int index, int nlayer, TLN_Sequence); -TLNAPI bool TLN_SetSpriteAnimation (int index, int nsprite, TLN_Sequence sequence, int loop); +TLNAPI bool TLN_SetSpriteAnimation (int nsprite, TLN_Sequence sequence, int loop); TLNAPI bool TLN_GetAnimationState (int index); TLNAPI bool TLN_SetAnimationDelay (int index, int delay); TLNAPI int TLN_GetAvailableAnimation (void); -TLNAPI bool TLN_DisableAnimation (int index); +TLNAPI bool TLN_DisablePaletteAnimation(int index); +TLNAPI bool TLN_DisableSpriteAnimation(int index); /**@}*/ #ifdef __cplusplus diff --git a/samples/Actor.c b/samples/Actor.c index 50d724f..221a8e9 100644 --- a/samples/Actor.c +++ b/samples/Actor.c @@ -162,6 +162,6 @@ static void TasksActor (Actor* actor) else { TLN_DisableSprite (actor->index); - TLN_DisableAnimation (actor->index); + TLN_DisableSpriteAnimation (actor->index); } } diff --git a/samples/Explosion.c b/samples/Explosion.c index 086d4b4..4153132 100644 --- a/samples/Explosion.c +++ b/samples/Explosion.c @@ -12,7 +12,7 @@ Actor* CreateExplosion (int index, int x, int y, TLN_Sequence sequence) Actor* actor = GetActor (index); SetActor (index, TYPE_EXPLOSION, x,y, 32,32, ExplosionTasks); TLN_ConfigSprite (index, spritesets[SPRITESET_MAIN], 0); - TLN_SetSpriteAnimation (index, index, sequence, 1); + TLN_SetSpriteAnimation (index, sequence, 1); //TLN_SetSpriteBlendMode (index, BLEND_ADD); return actor; } diff --git a/samples/Forest.c b/samples/Forest.c index 7ddfc7b..70fd364 100644 --- a/samples/Forest.c +++ b/samples/Forest.c @@ -54,7 +54,7 @@ int main(int argc, char* argv[]) if (argc > 2) passkey = argv[2]; - TLN_Init(HRES, VRES, NUM_LAYERS, 8, 8); + TLN_Init(HRES, VRES, NUM_LAYERS, 8, 0); /* load assets */ TLN_SetLogLevel(TLN_LOG_ERRORS); @@ -109,7 +109,7 @@ int main(int argc, char* argv[]) xplayer = 48; yplayer = 144; TLN_ConfigSprite(0, atlas, 0); - TLN_SetSpriteAnimation(0, 0, idle, 0); + TLN_SetSpriteAnimation(0, idle, 0); /* create window & main loop */ TLN_CreateWindow(NULL, 0); diff --git a/samples/Mode7.c b/samples/Mode7.c index d0412b3..6a586a0 100644 --- a/samples/Mode7.c +++ b/samples/Mode7.c @@ -58,7 +58,7 @@ static void raster_callback (int line); int main (int argc, char* argv[]) { /* setup engine */ - TLN_Init (WIDTH,HEIGHT, MAX_LAYER, 0, 5); + TLN_Init (WIDTH,HEIGHT, MAX_LAYER, 0, 0); TLN_SetRasterCallback (raster_callback); TLN_SetBGColor (0,0,0); diff --git a/samples/Platformer.c b/samples/Platformer.c index bccda76..9cda29b 100644 --- a/samples/Platformer.c +++ b/samples/Platformer.c @@ -66,7 +66,7 @@ int main (int argc, char *argv[]) TLN_Palette palette; /* setup engine */ - TLN_Init (WIDTH,HEIGHT, MAX_LAYER, 0, 20); + TLN_Init (WIDTH,HEIGHT, MAX_LAYER, 0, 1); TLN_SetRasterCallback (raster_callback); TLN_SetBGColor (0,128,238); diff --git a/samples/Shadow.c b/samples/Shadow.c index 08fa85e..abc27f9 100644 --- a/samples/Shadow.c +++ b/samples/Shadow.c @@ -48,7 +48,7 @@ int main (int argc, char* argv[]) TLN_Sequence walk; /* setup engine */ - TLN_Init (WIDTH, HEIGHT, 2,1,1); + TLN_Init (WIDTH, HEIGHT, 2,1,0); TLN_SetBGColor (0,128,238); TLN_SetRasterCallback (raster_callback); @@ -65,7 +65,7 @@ int main (int argc, char* argv[]) TLN_ConfigSprite (0, spriteset, 0); TLN_SetSpritePosition (0, 200,160); - TLN_SetSpriteAnimation (0, 0, walk, 0); + TLN_SetSpriteAnimation (0, walk, 0); xpos = 2000; diff --git a/samples/Ship.c b/samples/Ship.c index 74ecbcc..382d753 100644 --- a/samples/Ship.c +++ b/samples/Ship.c @@ -136,7 +136,7 @@ Actor* CreateClaw (int id) Claw* claw = (Claw*)actor->usrdata; TLN_ConfigSprite (actor->index, spritesets[SPRITESET_MAIN], 0); - TLN_SetSpriteAnimation (actor->index, actor->index, sequences[SEQ_CLAW], 0); + TLN_SetSpriteAnimation (actor->index, sequences[SEQ_CLAW], 0); claw->angle = id==ACTOR_CLAW1? 360:180; claw->radius = 0; @@ -197,7 +197,7 @@ Actor* CreateShot (int type, int x, int y) actor->vx = 8; actor->vy = 0; TLN_ConfigSprite (actor->index, spritesets[SPRITESET_MAIN], 0); - TLN_SetSpriteAnimation (actor->index, actor->index, sequences[seq], 0); + TLN_SetSpriteAnimation (actor->index, sequences[seq], 0); return actor; } diff --git a/samples/Shooter.c b/samples/Shooter.c index a00b4d8..103a17d 100644 --- a/samples/Shooter.c +++ b/samples/Shooter.c @@ -95,7 +95,7 @@ int main (int argc, char *argv[]) int c; /* setup engine */ - TLN_Init (WIDTH,HEIGHT, MAX_LAYER, MAX_ACTOR, MAX_ACTOR); + TLN_Init (WIDTH,HEIGHT, MAX_LAYER, MAX_ACTOR, 0); TLN_SetRasterCallback (raster_callback); TLN_SetBGColor (136,238,204); diff --git a/samples/Simon.c b/samples/Simon.c index bfd35f5..7c710b0 100644 --- a/samples/Simon.c +++ b/samples/Simon.c @@ -57,16 +57,16 @@ void SimonSetState (int s) switch (state) { case SIMON_IDLE: - TLN_DisableAnimation (0); + TLN_DisableSpriteAnimation (0); TLN_SetSpritePicture (0, 0); break; case SIMON_WALKING: - TLN_SetSpriteAnimation (0, 0, walk, 0); + TLN_SetSpriteAnimation (0, walk, 0); break; case SIMON_JUMPING: - TLN_DisableAnimation (0); + TLN_DisableSpriteAnimation (0); TLN_SetSpritePicture (0, 7); sy = -18; break; diff --git a/samples/SuperMarioClone.c b/samples/SuperMarioClone.c index 9f33081..ad69ec4 100644 --- a/samples/SuperMarioClone.c +++ b/samples/SuperMarioClone.c @@ -22,7 +22,7 @@ int main (int argc, char* argv[]) int player_y = 160; /* basic setup */ - TLN_Init (WIDTH, HEIGHT, MAX_LAYER,1,3); + TLN_Init (WIDTH, HEIGHT, MAX_LAYER,1,0); TLN_SetBGColor (0, 96, 184); /* load resources */ @@ -42,7 +42,7 @@ int main (int argc, char* argv[]) /* setup animations */ seq_walking = TLN_CreateSpriteSequence (NULL, spriteset, "walking", 6); - TLN_SetSpriteAnimation (2, 0, seq_walking, 0); + TLN_SetSpriteAnimation (0, seq_walking, 0); /* main loop */ TLN_CreateWindow (NULL, 0); diff --git a/src/Animation.c b/src/Animation.c index f40a6d8..ef1c95f 100644 --- a/src/Animation.c +++ b/src/Animation.c @@ -20,6 +20,7 @@ #include "Engine.h" #include "Palette.h" #include "Tables.h" +#include "Debug.h" /* linear interploation */ static int lerp (int x, int x0, int x1, int fx0, int fx1) @@ -37,112 +38,108 @@ static inline void blendColors (uint8_t* srcptr0, uint8_t* srcptr1, uint8_t* dst static void SetAnimation (Animation* animation, TLN_Sequence sequence, animation_t type); static void ColorCycle (TLN_Palette srcpalette, TLN_Palette dstpalette, struct Strip* strip); static void ColorCycleBlend (TLN_Palette srcpalette, TLN_Palette dstpalette, struct Strip* strip, int t); -static void ReplaceTiles (TLN_Tilemap tilemap, int srctile, int dsttile); -/* main loop tasks */ -void UpdateAnimations (int time) +static void tileset_animation(Animation* animation, int srctile, int dsttile) { - int c; - TLN_Sequence sequence; - TLN_SequenceFrame* frames; - struct Strip* strips; - - for (c=0; cnumanimations; c++) + TLN_Tileset tileset = engine->layers[animation->idx].tileset; + debugmsg("TileAnim: %d -> %d\n", srctile, dsttile); + if (srctile != dsttile) + TLN_CopyTile(tileset, srctile, dsttile); + else { - Animation* animation = &engine->animations[c]; - if (animation->enabled==false) - continue; + TLN_Bitmap bitmap = animation->backup; + TLN_SetTilesetPixels(tileset, srctile, bitmap->data, bitmap->pitch); + } +} - sequence = animation->sequence; - if (animation->type == TYPE_PALETTE) +/* updates animation state */ +void UpdateAnimation(Animation* animation, int time) +{ + TLN_Sequence sequence = animation->sequence; + TLN_SequenceFrame* frames = NULL; + + if (animation->type == TYPE_PALETTE) + { + int i; + struct Strip* strips = (struct Strip*)&sequence->data; + for (i = 0; i < sequence->count; i++) { - int i; - strips = (struct Strip*)&sequence->data; - for (i=0; icount; i++) + struct Strip* strip = &strips[i]; + /* next frame */ + if (time >= strip->timer) { - struct Strip* strip = &strips[i]; - /* next frame */ - if (time >= strip->timer) - { - strip->timer = time + strip->delay; - strip->pos = (strip->pos + 1) % strip->count; - strip->t0 = time; - if (!animation->blend) - ColorCycle (animation->srcpalette, animation->palette, strip); - } - - /* interpolate */ - if (animation->blend) - ColorCycleBlend (animation->srcpalette, animation->palette, strip, time); + strip->timer = time + strip->delay; + strip->pos = (strip->pos + 1) % strip->count; + strip->t0 = time; + if (!animation->blend) + ColorCycle(animation->srcpalette, animation->palette, strip); } - continue; - } - if (time < animation->timer) - continue; + /* interpolate */ + if (animation->blend) + ColorCycleBlend(animation->srcpalette, animation->palette, strip, time); + } + return; + } - frames = (TLN_SequenceFrame*)&sequence->data; - animation->timer = time + frames[animation->pos].delay; - switch (animation->type) - { - case TYPE_TILEMAP: - ReplaceTiles (engine->layers[animation->idx].tilemap, - frames[animation->pos].index, - frames[animation->pos + 1].index % sequence->count); - break; + if (time < animation->timer) + return; - case TYPE_SPRITE: - TLN_SetSpritePicture (animation->idx, frames[animation->pos].index); - break; + frames = (TLN_SequenceFrame*)&sequence->data; + animation->timer = time + frames[animation->pos].delay; + switch (animation->type) + { + case TYPE_SPRITE: + TLN_SetSpritePicture(animation->idx, frames[animation->pos].index); + break; - case TYPE_TILESET: - TLN_CopyTile (engine->layers[animation->idx].tileset, frames[animation->pos].index, sequence->target); - break; + case TYPE_TILESET: + tileset_animation(animation, frames[animation->pos].index, sequence->target); + break; - /* Fall through */ + /* Fall through */ /* Stop warning GNU C compiler */ - case TYPE_NONE: - case TYPE_PALETTE: - break; - } + case TYPE_NONE: + case TYPE_PALETTE: + break; + } - /* next frame */ - animation->pos++; - if (animation->pos == sequence->count) + /* next frame */ + animation->pos++; + if (animation->pos == sequence->count) + { + if (animation->loop > 1) { - if (animation->loop > 1) - { - animation->loop--; - animation->pos = 0; - } - else if (animation->loop == 1) - animation->enabled = false; - else if (animation->loop == 0) - animation->pos = 0; + animation->loop--; + animation->pos = 0; } + else if (animation->loop == 1) + animation->enabled = false; + else if (animation->loop == 0) + animation->pos = 0; } } /** * \brief - * Checks the state of the specified animation + * Checks the state of the animation for given sprite * * \param index - * Id of the animation to check (0 <= id < num_animations) + * Id of the sprite to check (0 <= id < num_sprites) * * \returns * true if animation is running, false if it's finished or inactive */ bool TLN_GetAnimationState (int index) { - if (index >= engine->numanimations) + if (index >= engine->numsprites) { - TLN_SetLastError (TLN_ERR_IDX_ANIMATION); + TLN_SetLastError (TLN_ERR_IDX_SPRITE); return false; } TLN_SetLastError (TLN_ERR_OK); - return engine->animations[index].enabled; + return engine->sprites[index].animation.enabled; } /*! @@ -163,7 +160,7 @@ bool TLN_GetAnimationState (int index) */ bool TLN_SetPaletteAnimation (int index, TLN_Palette palette, TLN_Sequence sequence, bool blend) { - Animation* animation; + Animation* animation = NULL; int c; struct Strip* strips; @@ -175,15 +172,16 @@ bool TLN_SetPaletteAnimation (int index, TLN_Palette palette, TLN_Sequence seque return false; } - animation = &engine->animations[index]; - - if (animation->sequence == sequence) + if (engine->animations[index].sequence == sequence) return true; /* validate type */ if (!CheckBaseObject (palette, OT_PALETTE) || !CheckBaseObject (sequence, OT_SEQUENCE)) return false; + animation = &engine->animations[index]; + if (!animation->enabled) + ListAppendNode(&engine->list_animations, index); SetAnimation (animation, sequence, TYPE_PALETTE); animation->palette = palette; animation->blend = blend; @@ -220,7 +218,7 @@ bool TLN_SetPaletteAnimation (int index, TLN_Palette palette, TLN_Sequence seque */ bool TLN_SetPaletteAnimationSource (int index, TLN_Palette palette) { - Animation* animation; + Animation* animation = NULL; if (index >= engine->numanimations) { @@ -239,87 +237,34 @@ bool TLN_SetPaletteAnimationSource (int index, TLN_Palette palette) return true; } -/*! - * \brief - * Starts a tileset animation - * - * \param index - * Id of the animation to set (0 <= id < num_animations) - * - * \param nlayer - * Id of the layer to animate (0 <= id < num_layers) - * - * \param sequence - * Reference of the sequence to assign - * - * \see - * Animations - */ -bool TLN_SetTilesetAnimation (int index, int nlayer, TLN_Sequence sequence) +bool SetTilesetAnimation(TLN_Tileset tileset, int index, TLN_Sequence sequence) { - Animation* animation; + Animation* animation = NULL; + int c; - if (index >= engine->numanimations) + if (index >= tileset->sp->num_sequences) { TLN_SetLastError (TLN_ERR_IDX_ANIMATION); return false; } - if (nlayer >= engine->numlayers) - { - TLN_SetLastError (TLN_ERR_IDX_LAYER); - return false; - } /* validate type */ if (!CheckBaseObject (sequence, OT_SEQUENCE)) return false; - animation = &engine->animations[index]; - SetAnimation (animation, sequence, TYPE_TILESET); - animation->idx = nlayer; - - TLN_SetLastError (TLN_ERR_OK); - return true; -} - -/*! - * \brief - * Starts a tilemap animation - * - * \param index - * Id of the animation to set (0 <= id < num_animations) - * - * \param nlayer - * Id of the layer to animate (0 <= id < num_layers) - * - * \param sequence - * Reference of the sequence to assign - * - * \see - * Animations - */ -bool TLN_SetTilemapAnimation (int index, int nlayer, TLN_Sequence sequence) -{ - Animation* animation; + animation = &tileset->animations[index]; + SetAnimation(animation, sequence, TYPE_TILESET); + if (animation->backup != NULL) + TLN_DeleteBitmap(animation->backup); - if (index >= engine->numanimations) + /* backup tile 0 on separate bitmap */ + animation->backup = TLN_CreateBitmap(tileset->width, tileset->height, 8); + for (c = 0; c < tileset->height; c += 1) { - TLN_SetLastError (TLN_ERR_IDX_ANIMATION); - return false; - } - if (nlayer >= engine->numlayers) - { - TLN_SetLastError (TLN_ERR_IDX_LAYER); - return false; - } - - /* validate type */ - if (!CheckBaseObject (sequence, OT_SEQUENCE)) - return false; - - animation = &engine->animations[index]; - SetAnimation (animation, sequence, TYPE_TILEMAP); - animation->idx = nlayer; + uint8_t* srcdata = &GetTilesetPixel(tileset, sequence->target, 0, c); + uint8_t* dstdata = get_bitmap_ptr(animation->backup, 0, c); + memcpy(dstdata, srcdata, tileset->width); + } TLN_SetLastError (TLN_ERR_OK); return true; @@ -329,9 +274,6 @@ bool TLN_SetTilemapAnimation (int index, int nlayer, TLN_Sequence sequence) * \brief * Starts a sprite animation * - * \param index - * Id of the animation to set (0 <= id < num_animations) - * * \param nsprite * If of the sprite to animate (0 <= id < num_sprites) * @@ -344,15 +286,11 @@ bool TLN_SetTilemapAnimation (int index, int nlayer, TLN_Sequence sequence) * \see * Animations */ -bool TLN_SetSpriteAnimation (int index, int nsprite, TLN_Sequence sequence, int loop) +bool TLN_SetSpriteAnimation (int nsprite, TLN_Sequence sequence, int loop) { - Animation* animation; + Sprite* sprite; + Animation* animation = NULL; - if (index >= engine->numanimations) - { - TLN_SetLastError (TLN_ERR_IDX_ANIMATION); - return false; - } if (nsprite >= engine->numsprites) { TLN_SetLastError (TLN_ERR_IDX_SPRITE); @@ -363,7 +301,8 @@ bool TLN_SetSpriteAnimation (int index, int nsprite, TLN_Sequence sequence, int if (!CheckBaseObject (sequence, OT_SEQUENCE)) return false; - animation = &engine->animations[index]; + sprite = &engine->sprites[nsprite]; + animation = &sprite->animation; SetAnimation (animation, sequence, TYPE_SPRITE); animation->idx = nsprite; animation->loop = loop; @@ -403,7 +342,7 @@ int TLN_GetAvailableAnimation (void) /*! * \brief - * Disables the animation so it stops playing and returns it to the list of available animations + * Disables the color cycle animation so it stops playing * * \param index * Id of the animation to set (0 <= id < num_animations) @@ -411,7 +350,7 @@ int TLN_GetAvailableAnimation (void) * \see * Animations */ -bool TLN_DisableAnimation (int index) +bool TLN_DisablePaletteAnimation (int index) { Animation* animation; @@ -422,14 +361,48 @@ bool TLN_DisableAnimation (int index) } animation = &engine->animations[index]; + if (animation->enabled) + ListUnlinkNode(&engine->list_animations, index); + animation->enabled = false; animation->type = TYPE_NONE; animation->sequence = NULL; - + ListUnlinkNode(&engine->list_animations, index); TLN_SetLastError (TLN_ERR_OK); return true; } +/*! + * \brief + * Disables animation for the given sprite + * + * \param index + * Id of the spriteto set (0 <= id < num_sprites) + * + * \see + * Animations + */ +bool TLN_DisableSpriteAnimation(int index) +{ + Sprite* sprite; + Animation* animation; + + if (index >= engine->numsprites) + { + TLN_SetLastError(TLN_ERR_IDX_SPRITE); + return false; + } + + sprite = &engine->sprites[index]; + animation = &sprite->animation; + animation->enabled = false; + animation->type = TYPE_NONE; + animation->sequence = NULL; + TLN_SetLastError(TLN_ERR_OK); + return true; +} + + /* animation commons */ static void SetAnimation (Animation* animation, TLN_Sequence sequence, animation_t type) { @@ -497,16 +470,3 @@ static void ColorCycleBlend (TLN_Palette srcpalette, TLN_Palette dstpalette, str blendColors (srcptr0, srcptr1, dstptr, f0, f1); } } - -/* tile substitution */ -static void ReplaceTiles (TLN_Tilemap tilemap, int srctile, int dsttile) -{ - int c; - int size = tilemap->rows * tilemap->cols; - - for (c=0; ctiles[c].index == srctile) - tilemap->tiles[c].index = dsttile; - } -} diff --git a/src/Animation.h b/src/Animation.h index b6438ec..19fdc1f 100644 --- a/src/Animation.h +++ b/src/Animation.h @@ -13,13 +13,13 @@ #include "Tilengine.h" #include "Sequence.h" +#include "List.h" -#define MAX_COLOR_STRIPS 32 +#define MAX_COLOR_STRIPS 64 typedef enum { TYPE_NONE, - TYPE_TILEMAP, TYPE_SPRITE, TYPE_PALETTE, TYPE_TILESET, @@ -31,17 +31,20 @@ typedef struct { animation_t type; TLN_Sequence sequence; + TLN_Bitmap backup; /* bavkup of frame 0 for tileset animation */ bool enabled; int loop; int pos; int timer; - int idx; /* indice de capa, sprite */ + int idx; /* index of layer or sprite */ bool blend; TLN_Palette palette; TLN_Palette srcpalette; + ListNode list_node; } Animation; -void UpdateAnimations (int time); +bool SetTilesetAnimation(TLN_Tileset tileset, int index, TLN_Sequence sequence); +void UpdateAnimation(Animation* animation, int time); #endif diff --git a/src/Draw.c b/src/Draw.c index c5f5772..3a19dcd 100644 --- a/src/Draw.c +++ b/src/Draw.c @@ -48,6 +48,7 @@ bool TLN_DrawNextScanline(void) int index; bool background_priority = false; bool sprite_priority = false; + List* list; /* call raster effect callback */ if (engine->raster) @@ -90,7 +91,8 @@ bool TLN_DrawNextScanline(void) } /* draw regular sprites */ - index = engine->first_sprite; + list = &engine->list_sprites; + index = list->first; while (index != -1) { Sprite* sprite = &engine->sprites[index]; @@ -101,7 +103,7 @@ bool TLN_DrawNextScanline(void) else sprite_priority = true; } - index = sprite->next; + index = sprite->list_node.next; } /* draw background layers with priority */ @@ -129,12 +131,13 @@ bool TLN_DrawNextScanline(void) /* draw sprites with priority */ if (sprite_priority == true) { - index = engine->first_sprite; + index = list->first; while (index != -1) { Sprite* sprite = &engine->sprites[index]; if (check_sprite_coverage(sprite, line) && (sprite->flags & FLAG_PRIORITY)) sprite->draw(index, line); + index = sprite->list_node.next; } } diff --git a/src/Engine.h b/src/Engine.h index a62f309..5e39da7 100644 --- a/src/Engine.h +++ b/src/Engine.h @@ -17,6 +17,7 @@ #include "Animation.h" #include "Bitmap.h" #include "Blitters.h" +#include "List.h" /* motor */ typedef struct Engine @@ -44,8 +45,8 @@ typedef struct Engine void (*frame)(int); /* frame callback */ int line; /* current scanline */ - int first_sprite; /* first sprite in list, none = -1 */ - int last_sprite; /* last sprite in list, none = -1 */ + List list_sprites; /* linked list active of sprites */ + List list_animations; /* linked list active of animations */ int sprite_mask_top; /* top scanline for sprite masking */ int sprite_mask_bottom; /* bottom scanline for sprite masking */ diff --git a/src/Layer.c b/src/Layer.c index 4ea9fb2..02e5593 100644 --- a/src/Layer.c +++ b/src/Layer.c @@ -40,27 +40,27 @@ static void SelectBlitter (Layer* layer); * \see * TLN_DisableLayer() */ -bool TLN_SetLayer (int nlayer, TLN_Tileset tileset, TLN_Tilemap tilemap) +bool TLN_SetLayer(int nlayer, TLN_Tileset tileset, TLN_Tilemap tilemap) { Layer *layer; if (nlayer >= engine->numlayers) { - TLN_SetLastError (TLN_ERR_IDX_LAYER); + TLN_SetLastError(TLN_ERR_IDX_LAYER); return false; } layer = &engine->layers[nlayer]; layer->ok = false; - if (!CheckBaseObject (tilemap, OT_TILEMAP)) + if (!CheckBaseObject(tilemap, OT_TILEMAP)) return false; - + /* seleccionar tileset del tilemap */ if (tileset == NULL) tileset = tilemap->tileset; - - if (!CheckBaseObject (tileset, OT_TILESET)) + + if (!CheckBaseObject(tileset, OT_TILESET)) return false; - + if (tilemap->maxindex <= tileset->numtiles) { layer->tileset = tileset; @@ -68,12 +68,12 @@ bool TLN_SetLayer (int nlayer, TLN_Tileset tileset, TLN_Tilemap tilemap) layer->width = tilemap->cols*tileset->width; layer->height = tilemap->rows*tileset->height; if (tileset->palette) - TLN_SetLayerPalette (nlayer, tileset->palette); + TLN_SetLayerPalette(nlayer, tileset->palette); } layer->bitmap = NULL; layer->objects = NULL; layer->ok = true; - layer->draw = GetLayerDraw (layer); + layer->draw = GetLayerDraw(layer); /* aplica atributo de prioridad del tileset al tilemap */ if (tileset->attributes != NULL) @@ -81,7 +81,7 @@ bool TLN_SetLayer (int nlayer, TLN_Tileset tileset, TLN_Tilemap tilemap) const int num_tiles = tilemap->rows * tilemap->cols; int c; Tile* tile = tilemap->tiles; - for (c=0; cindex != 0) { @@ -92,33 +92,20 @@ bool TLN_SetLayer (int nlayer, TLN_Tileset tileset, TLN_Tilemap tilemap) } } } - + /* inicia animaciones */ if (tileset->sp != NULL) { - int index, c; + int c; TLN_Sequence sequence; - /* desactiva animaciones de patr�n de la capa actual */ - for (c=0; cnumanimations; c++) - { - Animation* animation = &engine->animations[c]; - if (animation->idx == nlayer && animation->type == TYPE_TILESET) - TLN_DisableAnimation (c); - } - - /* inicia las del nuevo tileset */ + c = 0; sequence = tileset->sp->sequences; while (sequence != NULL) { - index = TLN_GetAvailableAnimation (); - if (index != -1) - { - TLN_SetTilesetAnimation (index, nlayer, sequence); - sequence = sequence->next; - } - else - sequence = NULL; + SetTilesetAnimation(tileset, c, sequence); + sequence = sequence->next; + c += 1; } } diff --git a/src/List.c b/src/List.c new file mode 100644 index 0000000..1189b74 --- /dev/null +++ b/src/List.c @@ -0,0 +1,107 @@ +/* generic, array-based double linked list */ + +#include +#include "List.h" +#include "Debug.h" + +static ListNode* get_node(List* list, int node) +{ + if (node != -1) + { + uint8_t* addr = (uint8_t*)list->base; + return (ListNode*)(addr + node * (list->node_size)); + } + return NULL; +} + +void ListInit(List* list, ListNode* base, int node_size, int num_nodes) +{ + int c; + list->base = (void*)base; + list->node_size = node_size; + list->num_nodes = num_nodes; + list->first = -1; + list->last = -1; + + for (c = 0; c < num_nodes; c += 1) + { + ListNode* node = get_node(list, c); + node->prev = -1; + node->next = -1; + } +} + +void ListLinkNodes(List* list, int num1, int num2) +{ + ListNode* node; + + node = get_node(list, num1); + if (node) + node->next = num2; + + node = get_node(list, num2); + if (node) + node->prev = num1; +} + +void ListUnlinkNode(List* list, int num) +{ + ListNode* node = get_node(list, num); + ListNode* node_prev = get_node(list, node->prev); + ListNode* node_next = get_node(list, node->next); + + if (node_prev) + node_prev->next = node->next; + if (node_next) + node_next->prev = node->prev; + if (list->first == num) + list->first = node->next; + if (list->last == num) + list->last = node->prev; + node->prev = -1; + node->next = -1; + ListPrint(list); +} + +void ListAppendNode(List* list, int num) +{ + if (list->first == -1) + list->first = num; + ListLinkNodes(list, list->last, num); + list->last = num; + ListPrint(list); +} + +int ListGetPrev(List* list, int num) +{ + ListNode* node = get_node(list, num); + return node->prev; +} + +int ListGetNext(List* list, int num) +{ + ListNode* node = get_node(list, num); + return node->next; +} + +void ListPrint(List* list) +{ +#ifdef _DEBUG + int index; + int c = 0; + debugmsg("list: "); + index = list->first; + while (index != -1) + { + ListNode *node = get_node(list, index); + debugmsg("%d ", index); + index = node->next; + c += 1; + if (c > list->num_nodes) + { + exit(0); + } + } + debugmsg("\n"); +#endif +} diff --git a/src/List.h b/src/List.h new file mode 100644 index 0000000..4fbb62e --- /dev/null +++ b/src/List.h @@ -0,0 +1,29 @@ +#ifndef _LIST_H +#define _LIST_H + +typedef struct +{ + int prev; /* index of prev node */ + int next; /* index of next node */ +} +ListNode; + +typedef struct +{ + void* base; /* ptr to first "ListNode" item */ + int node_size; /* size of nodes */ + int num_nodes; /* total number of nodes in array */ + int first; /* index to first node */ + int last; /* index to last node */ +} +List; + +void ListInit(List* list, ListNode* base, int node_size, int num_nodes); +void ListLinkNodes(List* list, int num1, int num2); +void ListUnlinkNode(List* list, int node); +void ListAppendNode(List* list, int node); +void ListPrint(List* list); +int ListGetPrev(List* list, int num); +int ListGetNext(List* list, int num); + +#endif diff --git a/src/LoadTileset.c b/src/LoadTileset.c index f466553..9b16a33 100644 --- a/src/LoadTileset.c +++ b/src/LoadTileset.c @@ -154,7 +154,7 @@ static void* handler (SimpleXmlParser parser, SimpleXmlEvent evt, else if (!strcasecmp(szName, "frame")) { if (!strcasecmp(szAttribute, "tileid")) - loader.frames[loader.frame_count].index = atoi(szValue); + loader.frames[loader.frame_count].index = atoi(szValue) + 1; else if (!strcasecmp(szAttribute, "duration")) loader.frames[loader.frame_count].delay = atoi(szValue)*60/1000; } @@ -196,7 +196,7 @@ static void* handler (SimpleXmlParser parser, SimpleXmlEvent evt, char name[16]; TLN_Sequence sequence; sprintf (name, "%d", loader.tile.id); - sequence = TLN_CreateSequence (name, loader.tile.id, loader.frame_count, loader.frames); + sequence = TLN_CreateSequence (name, loader.tile.id + 1, loader.frame_count, loader.frames); if (loader.sp == NULL) loader.sp = TLN_CreateSequencePack (); TLN_AddSequenceToPack (loader.sp, sequence); @@ -206,6 +206,37 @@ static void* handler (SimpleXmlParser parser, SimpleXmlEvent evt, return handler; } +/* cache section: keeps already loaded tilesets so it doesnt spawn multiple instances of the same */ +#define CACHE_SIZE 16 +static cache_entries = 0; +struct +{ + char name[200]; + TLN_Tileset tileset; +} +static cache[16]; + +static TLN_Tileset search_cache(const char* name) +{ + int c; + for (c = 0; c < cache_entries; c += 1) + { + if (!strcmp(cache[c].name, name)) + return cache[c].tileset; + } + return NULL; +} + +static void add_to_cache(const char* name, TLN_Tileset tileset) +{ + if (cache_entries < CACHE_SIZE - 1) + { + strncpy(cache[cache_entries].name, name, sizeof(cache[0].name)); + cache[cache_entries].tileset = tileset; + cache_entries += 1; + } +} + /*! * \brief * Loads a tileset from a Tiled .tsx file @@ -225,6 +256,11 @@ TLN_Tileset TLN_LoadTileset (const char* filename) ssize_t size = 0; uint8_t *data = NULL; TLN_Tileset tileset = NULL; + + /* find in cache */ + tileset = search_cache(filename); + if (tileset) + return tileset; /* load file */ data = (uint8_t*)LoadFile (filename, &size); @@ -315,6 +351,7 @@ TLN_Tileset TLN_LoadTileset (const char* filename) if (loader.images != NULL) free(loader.images); + add_to_cache(filename, tileset); TLN_SetLastError (TLN_ERR_OK); return tileset; } diff --git a/src/Sprite.c b/src/Sprite.c index b67ceb8..4948906 100644 --- a/src/Sprite.c +++ b/src/Sprite.c @@ -26,63 +26,6 @@ static void SelectBlitter (Sprite* sprite); static void UpdateSprite (Sprite* sprite); -void print_sprites(void) -{ -#ifdef _DEBUG - int index; - int c = 0; - debugmsg("sprites: "); - index = engine->first_sprite; - while (index != -1) - { - debugmsg("%d ", index); - index = engine->sprites[index].next; - c += 1; - if (c > engine->numsprites) - { - exit(0); - } - } - debugmsg("\n"); -#endif -} - -/* helper for sprite linked list */ -static void link_sprites(int num1, int num2) -{ - if (num1 != -1) - engine->sprites[num1].next = num2; - if (num2 != -1) - engine->sprites[num2].prev = num1; -} - -static void unlink_sprite(int num) -{ - Sprite* sprite = &engine->sprites[num]; - if (sprite->prev != -1) - engine->sprites[sprite->prev].next = sprite->next; - if (sprite->next != -1) - engine->sprites[sprite->next].prev = sprite->prev; - if (engine->first_sprite == num) - engine->first_sprite = sprite->next; - if (engine->last_sprite == num) - engine->last_sprite = sprite->prev; - sprite->prev = -1; - sprite->next = -1; - - print_sprites(); -} - -static append_sprite(int num) -{ - if (engine->first_sprite == -1) - engine->first_sprite = num; - link_sprites(engine->last_sprite, num); - engine->last_sprite = num; - - print_sprites(); -} - /*! * \brief * Configures a sprite, setting spriteset and flags at once @@ -151,7 +94,7 @@ bool TLN_SetSpriteSet (int nsprite, TLN_Spriteset spriteset) /* sprite enabled: add to the end */ if (enabled == false && sprite->ok == true) - append_sprite(nsprite); + ListAppendNode(&engine->list_sprites, nsprite); return sprite->ok; } @@ -253,6 +196,7 @@ bool TLN_SetSpritePicture (int nsprite, int entry) sprite->info = &sprite->spriteset->data[entry]; sprite->pixels = sprite->spriteset->bitmap->data + sprite->info->offset; UpdateSprite (sprite); + debugmsg("SetSpritePicture %d -> %d\n", nsprite, entry); TLN_SetLastError (TLN_ERR_OK); return true; @@ -708,7 +652,7 @@ bool TLN_DisableSprite(int nsprite) if (enabled == true) { debugmsg("%s(%d)\t", __FUNCTION__, nsprite); - unlink_sprite(nsprite); + ListUnlinkNode(&engine->list_sprites, nsprite); } TLN_SetLastError(TLN_ERR_OK); @@ -774,27 +718,31 @@ TLNAPI bool TLN_GetSpriteState(int nsprite, TLN_SpriteState* state) bool TLN_SetFirstSprite(int nsprite) { Sprite* sprite; + List* list; + ListNode* node; int cut1, cut2; - if (nsprite >= engine->numsprites || !engine->sprites[nsprite].ok || nsprite == engine->first_sprite) + if (nsprite >= engine->numsprites || !engine->sprites[nsprite].ok || nsprite == engine->list_sprites.first) { TLN_SetLastError(TLN_ERR_IDX_SPRITE); return false; } + list = &engine->list_sprites; sprite = &engine->sprites[nsprite]; + node = &sprite->list_node; /* cut points inside the list to rejoin */ - cut1 = sprite->prev; - cut2 = sprite->next; + cut1 = node->prev; + cut2 = node->next; /* rejoin segments */ - sprite->prev = -1; - sprite->next = -1; - link_sprites(nsprite, engine->first_sprite); - link_sprites(cut1, cut2); - engine->first_sprite = nsprite; + node->prev = -1; + node->next = -1; + ListLinkNodes(list, nsprite, list->first); + ListLinkNodes(list, cut1, cut2); + list->first = nsprite; debugmsg("%s(%d)\t", __FUNCTION__, nsprite); - print_sprites(); + ListPrint(list); TLN_SetLastError(TLN_ERR_OK); return true; } @@ -806,6 +754,7 @@ bool TLN_SetFirstSprite(int nsprite) */ bool TLN_SetNextSprite(int nsprite, int next) { + List* list; int cut1, cut2, cut3; if (nsprite >= engine->numsprites || !engine->sprites[nsprite].ok || nsprite == next) { @@ -818,21 +767,22 @@ bool TLN_SetNextSprite(int nsprite, int next) TLN_SetLastError(TLN_ERR_IDX_SPRITE); return false; } + list = &engine->list_sprites; /* cut points inside the list te rejoin */ - cut1 = engine->sprites[nsprite].next; - cut2 = engine->sprites[next].prev; - cut3 = engine->sprites[next].next; + cut1 = ListGetNext(list, nsprite); + cut2 = ListGetPrev(list, next); + cut3 = ListGetNext(list, next); /* rejoin segments */ - link_sprites(nsprite, next); - link_sprites(next, cut1); - link_sprites(cut2, cut3); - if (engine->first_sprite == next) - engine->first_sprite = cut3; + ListLinkNodes(list, nsprite, next); + ListLinkNodes(list, next, cut1); + ListLinkNodes(list, cut2, cut3); + if (list->first == next) + list->first = cut3; debugmsg("%s(%d,%d)\t", __FUNCTION__, nsprite, next); - print_sprites(); + ListPrint(list); TLN_SetLastError(TLN_ERR_OK); return true; } diff --git a/src/Sprite.h b/src/Sprite.h index 6a5a779..154dd88 100644 --- a/src/Sprite.h +++ b/src/Sprite.h @@ -15,6 +15,8 @@ #include "Draw.h" #include "Blitters.h" #include "Spriteset.h" +#include "List.h" +#include "Animation.h" /* rectangulo */ typedef struct @@ -50,8 +52,8 @@ typedef struct Sprite bool collision; bool masking; TLN_Bitmap rotation_bitmap; - int prev; - int next; + ListNode list_node; + Animation animation; } Sprite; diff --git a/src/Tilengine.c b/src/Tilengine.c index c85143c..8008535 100644 --- a/src/Tilengine.c +++ b/src/Tilengine.c @@ -33,7 +33,7 @@ static TLN_Engine create_context(int hres, int vres, int bpp, int numlayers, int /*! * \brief - * Initializes the graphic engine in 32 bpp pixel format + * Initializes the graphic engine * * \param hres * horizontal resolution in pixels @@ -48,7 +48,7 @@ static TLN_Engine create_context(int hres, int vres, int bpp, int numlayers, int * number of sprites * * \param numanimations - * number of animations + * number of palette animation slots * * Performs initialisation of the main engine, creates the viewport with the specified dimensions * and allocates the number of layers, sprites and animation slots @@ -118,11 +118,8 @@ static TLN_Engine create_context(int hres, int vres, int bpp, int numlayers, int sprite->draw = GetSpriteDraw (MODE_NORMAL); sprite->blitter = GetBlitter (bpp, true, false, false); sprite->sx = sprite->sy = 1.0f; - sprite->prev = -1; - sprite->next = -1; } - context->first_sprite = -1; - context->last_sprite = -1; + ListInit(&context->list_sprites, &context->sprites[0].list_node, sizeof(Sprite), context->numsprites); context->numanimations = numanimations; context->animations = (Animation*)calloc (numanimations, sizeof(Animation)); @@ -132,6 +129,7 @@ static TLN_Engine create_context(int hres, int vres, int bpp, int numlayers, int TLN_SetLastError (TLN_ERR_OUT_OF_MEMORY); return NULL; } + ListInit(&context->list_animations, &context->animations[0].list_node, sizeof(Animation), context->numanimations); context->bgcolor = PackRGB32(0,0,0); context->blit_fast = GetBlitter (bpp, false, false, false); @@ -412,16 +410,46 @@ void TLN_UpdateFrame (int time) */ void TLN_BeginFrame (int time) { - int c; + /* update active animations */ + List* list; + int index; - UpdateAnimations (time); - engine->line = 0; + /* color cycle animations */ + list = &engine->list_animations; + index = list->first; + while (index != -1) + { + Animation* animation = &engine->animations[index]; + UpdateAnimation(animation, time); + index = animation->list_node.next; + } + + /* sprite animations */ + list = &engine->list_sprites; + index = list->first; + while (index != -1) + { + Sprite* sprite = &engine->sprites[index]; + sprite->collision = false; + if (sprite->animation.enabled) + UpdateAnimation(&sprite->animation, time); + index = sprite->list_node.next; + } - /* limpia colisiones de sprites */ - for (c=0; cnumsprites; c++) - engine->sprites[c].collision = false; + /* tileset animations */ + for (index = 0; index < engine->numlayers; index += 1) + { + TLN_Tileset tileset = engine->layers[index].tileset; + if (tileset != NULL && tileset->sp != NULL) + { + int c; + for (c = 0; c < tileset->sp->num_sequences; c += 1) + UpdateAnimation(&tileset->animations[c], time); + } + } /* frame callback */ + engine->line = 0; if (engine->frame) engine->frame (time); } diff --git a/src/Tilengine.vcxproj b/src/Tilengine.vcxproj index 8d35b98..3a32acf 100644 --- a/src/Tilengine.vcxproj +++ b/src/Tilengine.vcxproj @@ -227,6 +227,7 @@ copy $(TargetDir)$(TargetName).lib $(SolutionDir)lib\$(Platform) + @@ -265,6 +266,7 @@ copy $(TargetDir)$(TargetName).lib $(SolutionDir)lib\$(Platform) + diff --git a/src/Tilengine.vcxproj.filters b/src/Tilengine.vcxproj.filters index 077818f..d18dc90 100644 --- a/src/Tilengine.vcxproj.filters +++ b/src/Tilengine.vcxproj.filters @@ -110,6 +110,9 @@ Archivos de código fuente + + Archivos de código fuente + @@ -196,5 +199,8 @@ Archivos de encabezado + + Archivos de encabezado + \ No newline at end of file diff --git a/src/Tileset.c b/src/Tileset.c index c6446e8..60173a8 100644 --- a/src/Tileset.c +++ b/src/Tileset.c @@ -14,6 +14,7 @@ #include #include +#include #include "Tilengine.h" #include "Tileset.h" #include "Palette.h" @@ -103,6 +104,10 @@ TLN_Tileset TLN_CreateTileset (int numtiles, int width, int height, TLN_Palette tileset->attributes = (TLN_TileAttributes*)(tileset->data + tileset->size_tiles + tileset->size_color); if (attributes != NULL) memcpy (tileset->attributes, attributes, size_attributes); + + /* create animations */ + if (sp != NULL) + tileset->animations = calloc(sp->num_sequences, sizeof(Animation)); TLN_SetLastError (TLN_ERR_OK); return tileset; @@ -399,8 +404,6 @@ bool TLN_CopyTile (TLN_Tileset tileset, int src, int dst) return false; } - src += 1; - dst += 1; tilesize = tileset->width * tileset->height; srcdata = tileset->data + (src * tilesize); dstdata = tileset->data + (dst * tilesize); diff --git a/src/Tileset.h b/src/Tileset.h index 20d47ce..a06423c 100644 --- a/src/Tileset.h +++ b/src/Tileset.h @@ -15,6 +15,7 @@ #include "Palette.h" #include "SequencePack.h" #include "Bitmap.h" +#include "Animation.h" /* types of tilesets */ typedef enum @@ -39,8 +40,9 @@ struct Tileset int vmask; /* vertical bitmask */ int size_tiles; /* size of tiles collection section */ int size_color; /* size of color key array */ - struct Palette* palette; /* palette */ - struct SequencePack* sp; /* associated sequences (if any) */ + TLN_Palette palette; /* palette */ + TLN_SequencePack sp; /* associated sequences (if any) */ + Animation* animations; /* active tile animations */ TLN_TileImage* images; /* image tiles array */ TLN_TileAttributes* attributes; /* attribute array */ bool* color_key; /* array telling if each line has color key or is solid */