Skip to content

Commit 6c292d7

Browse files
committed
Add tag support
1 parent 44bc04a commit 6c292d7

File tree

4 files changed

+265
-34
lines changed

4 files changed

+265
-34
lines changed

README.md

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,23 @@ int main() {
2222
// Load the backpacker Aseprite file.
2323
Aseprite backpacker = LoadAseprite("resources/backpacker.aseprite");
2424

25+
// Load the Walk Down tag.
26+
AsepriteTag walkdown = LoadAsepriteTag(backpacker, "Walk Down");
27+
walkdown.speed = 2; // Double the animation speed.
28+
2529
while(!WindowShouldClose()) {
30+
// Update the animation frame for walk down.
31+
UpdateAsperiteTag(&walkdown);
32+
2633
BeginDrawing();
2734
ClearBackground(RAYWHITE);
2835

29-
// Draw the 0th frame from the aseprite.
36+
// Draw the 0th frame from the backpacker sprite.
3037
DrawAseprite(backpacker, 0, 100, 100, WHITE);
3138

39+
// Draw the walkdown animation tag.
40+
DrawAsepriteTag(walkdown, 200, 100, WHITE);
41+
3242
EndDrawing();
3343
}
3444

@@ -43,15 +53,25 @@ int main() {
4353
### Cheatsheet
4454

4555
``` c
46-
Aseprite LoadAseprite(const char* fileName); // Load an .aseprite file.
47-
Aseprite LoadAsepriteFromMemory(unsigned char* fileData, unsigned int size); // Load an aseprite file from memory.
48-
void UnloadAseprite(Aseprite ase); // Unloads the aseprite file.
49-
void TraceAseprite(Aseprite ase); // Display all information associated with the aseprite.
50-
Texture GetAsepriteTexture(Aseprite ase); // Retrieve the raylib texture associated with the aseprite.
51-
void DrawAseprite(Aseprite ase, int frame, int posX, int posY, Color tint);
52-
void DrawAsepriteV(Aseprite ase, int frame, Vector2 position, Color tint);
53-
void DrawAsepriteEx(Aseprite ase, int frame, Vector2 position, float rotation, float scale, Color tint);
54-
void DrawAsepritePro(Aseprite ase, int frame, Rectangle dest, Vector2 origin, float rotation, Color tint);
56+
Aseprite LoadAseprite(const char* fileName); // Load an .aseprite file
57+
Aseprite LoadAsepriteFromMemory(unsigned char* fileData, unsigned int size); // Load an aseprite file from memory
58+
void UnloadAseprite(Aseprite aseprite); // Unloads the aseprite file
59+
void TraceAseprite(Aseprite aseprite); // Display all information associated with the aseprite
60+
Texture GetAsepriteTexture(Aseprite aseprite); // Retrieve the raylib texture associated with the aseprite
61+
void DrawAseprite(Aseprite aseprite, int frame, int posX, int posY, Color tint);
62+
void DrawAsepriteV(Aseprite aseprite, int frame, Vector2 position, Color tint);
63+
void DrawAsepriteEx(Aseprite aseprite, int frame, Vector2 position, float rotation, float scale, Color tint);
64+
void DrawAsepritePro(Aseprite aseprite, int frame, Rectangle dest, Vector2 origin, float rotation, Color tint);
65+
66+
AsepriteTag LoadAsepriteTag(Aseprite aseprite, const char* name); // Load a Aseprite tag animation sequence
67+
AsepriteTag LoadAsepriteTagFromId(Aseprite aseprite, int id); // Load a Aseprite tag animation sequence from its index
68+
void UpdateAsepriteTag(AsepriteTag* tag); // Update the tag animation frame if needed
69+
void DrawAsepriteTag(AsepriteTag tag, int posX, int posY, Color tint);
70+
void DrawAsepriteTagV(AsepriteTag tag, Vector2 position, Color tint);
71+
void DrawAsepriteTagEx(AsepriteTag tag, Vector2 position, float rotation, float scale, Color tint);
72+
void DrawAsepriteTagPro(AsepriteTag tag, Rectangle dest, Vector2 origin, float rotation, Color tint);
73+
const char* GetAsepriteTagName(AsepriteTag tag); // Retrieve the given tag's name
74+
int GetAspriteTagCount(Aseprite aseprite); // Get the total amount of available tags from the loaded Aseprite
5575
```
5676
5777
## Development

example/raylib-aseprite-example.c

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,15 @@ int main() {
2525

2626
// Load the Aseprite file.
2727
Aseprite aseprite = LoadAseprite("resources/backpacker.aseprite");
28-
ase_t* ase = aseprite.ase;
29-
30-
// TODO: Add a Tag Manager/Renderer.
31-
//Tag tag = LoadAsepriteTag(ase, "Walk Down");
32-
//UpdateAseprite(ase);
3328

3429
// Display information about it.
3530
TraceAseprite(aseprite);
3631

32+
// Load the "Walk Down" tag from aseprite.
33+
AsepriteTag walkdown = LoadAsepriteTag(aseprite, "Walk Down");
34+
3735
// Build all the frame information for each tag.
36+
ase_t* ase = aseprite.ase;
3837
int frame[ase->tag_count];
3938
float frameTimer[ase->tag_count];
4039
for (int i = 0; i < ase->tag_count; i++) {
@@ -47,6 +46,19 @@ int main() {
4746

4847
// Update
4948
//----------------------------------------------------------------------------------
49+
50+
// Pause the animation if the space key is down.
51+
if (IsKeyDown(KEY_SPACE)) {
52+
walkdown.speed = 0;
53+
}
54+
else {
55+
walkdown.speed = 2;
56+
}
57+
58+
// Update the active animation of the walk down tag.
59+
UpdateAsepriteTag(&walkdown);
60+
61+
// Manually update the sprites.
5062
float timeSpend = GetFrameTime();
5163
for (int i = 0; i < ase->tag_count; i++) {
5264
ase_tag_t tag = ase->tags[i];
@@ -64,18 +76,22 @@ int main() {
6476
// Draw
6577
//----------------------------------------------------------------------------------
6678
BeginDrawing();
67-
ClearBackground(RAYWHITE);
79+
{
80+
ClearBackground(RAYWHITE);
6881

69-
// Loop through each tag, and display the animated sprite.
70-
for (int i = 0; i < ase->tag_count; i++) {
71-
ase_tag_t tag = ase->tags[i];
72-
DrawText(tag.name, 170, i * 115 + 90, 40, BLACK);
73-
Vector2 position = {100, i * 115 + 70};
82+
// Loop through each tag, and display the animated sprite.
83+
for (int i = 0; i < ase->tag_count; i++) {
84+
ase_tag_t tag = ase->tags[i];
85+
DrawText(tag.name, 170, i * 115 + 90, 40, BLACK);
86+
Vector2 position = {100, i * 115 + 70};
7487

75-
// Draw the active frame.
76-
DrawAsepriteEx(aseprite, frame[i], position, 0, 6, WHITE);
77-
}
88+
// Draw the active frame.
89+
DrawAsepriteEx(aseprite, frame[i], position, 0, 6, WHITE);
90+
}
7891

92+
// Display the loaded walkdown tag in animation.
93+
DrawAsepriteTagEx(walkdown, (Vector2){470, 120}, 0, 16, WHITE);
94+
}
7995
EndDrawing();
8096
//----------------------------------------------------------------------------------
8197
}

include/raylib-aseprite.h

Lines changed: 176 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,35 @@ typedef struct Aseprite {
4343
ase_t* ase;
4444
} Aseprite;
4545

46-
Aseprite LoadAseprite(const char* fileName); // Load an .aseprite file.
47-
Aseprite LoadAsepriteFromMemory(unsigned char* fileData, unsigned int size); // Load an aseprite file from memory.
48-
void UnloadAseprite(Aseprite aseprite); // Unloads the aseprite file.
49-
void TraceAseprite(Aseprite aseprite); // Display all information associated with the aseprite.
50-
Texture GetAsepriteTexture(Aseprite aseprite); // Retrieve the raylib texture associated with the aseprite.
46+
typedef struct AsepriteTag {
47+
ase_tag_t* tag;
48+
Aseprite aseprite;
49+
int currentFrame;
50+
float timer;
51+
int direction;
52+
float speed;
53+
} AsepriteTag;
54+
55+
Aseprite LoadAseprite(const char* fileName); // Load an .aseprite file
56+
Aseprite LoadAsepriteFromMemory(unsigned char* fileData, unsigned int size); // Load an aseprite file from memory
57+
void UnloadAseprite(Aseprite aseprite); // Unloads the aseprite file
58+
void TraceAseprite(Aseprite aseprite); // Display all information associated with the aseprite
59+
Texture GetAsepriteTexture(Aseprite aseprite); // Retrieve the raylib texture associated with the aseprite
5160
void DrawAseprite(Aseprite aseprite, int frame, int posX, int posY, Color tint);
5261
void DrawAsepriteV(Aseprite aseprite, int frame, Vector2 position, Color tint);
5362
void DrawAsepriteEx(Aseprite aseprite, int frame, Vector2 position, float rotation, float scale, Color tint);
5463
void DrawAsepritePro(Aseprite aseprite, int frame, Rectangle dest, Vector2 origin, float rotation, Color tint);
5564

65+
AsepriteTag LoadAsepriteTag(Aseprite aseprite, const char* name); // Load a Aseprite tag animation sequence
66+
AsepriteTag LoadAsepriteTagFromId(Aseprite aseprite, int id); // Load a Aseprite tag animation sequence from its index
67+
void UpdateAsepriteTag(AsepriteTag* tag); // Update the tag animation frame if needed
68+
void DrawAsepriteTag(AsepriteTag tag, int posX, int posY, Color tint);
69+
void DrawAsepriteTagV(AsepriteTag tag, Vector2 position, Color tint);
70+
void DrawAsepriteTagEx(AsepriteTag tag, Vector2 position, float rotation, float scale, Color tint);
71+
void DrawAsepriteTagPro(AsepriteTag tag, Rectangle dest, Vector2 origin, float rotation, Color tint);
72+
const char* GetAsepriteTagName(AsepriteTag tag); // Retrieve the given tag's name
73+
int GetAspriteTagCount(Aseprite aseprite); // Get the total amount of available tags from the loaded Aseprite
74+
5675
#ifdef __cplusplus
5776
}
5877
#endif
@@ -122,9 +141,9 @@ extern "C" {
122141
#endif
123142

124143
Aseprite LoadAsepriteFromMemory(unsigned char* fileData, unsigned int size) {
144+
struct Aseprite aseprite;
125145
ase_t* ase = cute_aseprite_load_from_memory(fileData, (int)size, 0);
126146
if (ase == 0) {
127-
struct Aseprite aseprite;
128147
aseprite.ase = 0;
129148
return aseprite;
130149
}
@@ -174,7 +193,6 @@ Aseprite LoadAsepriteFromMemory(unsigned char* fileData, unsigned int size) {
174193
texturePointer->mipmaps = texture.mipmaps;
175194
texturePointer->width = texture.width;
176195
texturePointer->height = texture.height;
177-
struct Aseprite aseprite;
178196
aseprite.ase = ase;
179197
return aseprite;
180198
}
@@ -221,19 +239,21 @@ void DrawAseprite(Aseprite aseprite, int frame, int posX, int posY, Color tint)
221239

222240
void DrawAsepriteV(Aseprite aseprite, int frame, Vector2 position, Color tint) {
223241
ase_t* ase = aseprite.ase;
224-
if (frame < 0 || frame >= ase->frame_count) {
242+
if (ase == 0 || frame < 0 || frame >= ase->frame_count) {
225243
return;
226244
}
245+
227246
Rectangle source = {(float)(frame * ase->w), 0, (float)ase->w, (float)ase->h};
228247
Texture2D texture = GetAsepriteTexture(aseprite);
229248
DrawTextureRec(texture, source, position, tint);
230249
}
231250

232251
void DrawAsepriteEx(Aseprite aseprite, int frame, Vector2 position, float rotation, float scale, Color tint) {
233252
ase_t* ase = aseprite.ase;
234-
if (frame < 0 || frame >= ase->frame_count) {
253+
if (ase == 0 || frame < 0 || frame >= ase->frame_count) {
235254
return;
236255
}
256+
237257
Rectangle source = {(float)(frame * ase->w), 0, (float)ase->w, (float)ase->h};
238258
Texture2D texture = GetAsepriteTexture(aseprite);
239259
Rectangle dest = {(float)position.x, (float)position.y, (float)(ase->w * scale), (float)(ase->h * scale)};
@@ -243,16 +263,22 @@ void DrawAsepriteEx(Aseprite aseprite, int frame, Vector2 position, float rotati
243263

244264
void DrawAsepritePro(Aseprite aseprite, int frame, Rectangle dest, Vector2 origin, float rotation, Color tint) {
245265
ase_t* ase = aseprite.ase;
246-
if (frame < 0 || frame >= ase->frame_count) {
266+
if (ase == 0 || frame < 0 || frame >= ase->frame_count) {
247267
return;
248268
}
269+
249270
Rectangle source = {(float)(frame * ase->w), 0, (float)ase->w, (float)ase->h};
250271
Texture2D texture = GetAsepriteTexture(aseprite);
251272
DrawTexturePro(texture, source, dest, origin, rotation, tint);
252273
}
253274

254275
void TraceAseprite(Aseprite aseprite) {
255276
ase_t* ase = aseprite.ase;
277+
if (ase == 0) {
278+
TraceLog(LOG_INFO, "ASEPRITE: Empty file information");
279+
return;
280+
}
281+
256282
TraceLog(LOG_INFO, "ASEPRITE: File information:");
257283
TraceLog(LOG_INFO, " > Size: %ix%i", ase->w, ase->h);
258284
TraceLog(LOG_INFO, " > Frames: %i", ase->frame_count);
@@ -264,13 +290,153 @@ void TraceAseprite(Aseprite aseprite) {
264290
ase_layer_t* layer = ase->layers + i;
265291
TraceLog(LOG_INFO, " - %s", layer->name);
266292
}
293+
267294
TraceLog(LOG_INFO, " > Tags: %i", ase->tag_count);
268295
for (int i = 0; i < ase->tag_count; i++) {
269296
ase_tag_t* tag = ase->tags + i;
270297
TraceLog(LOG_INFO, " - %s", tag->name);
271298
}
272299
}
273300

301+
void UpdateAsepriteTag(AsepriteTag* tag) {
302+
if (tag == 0 || tag->tag == 0 || tag->aseprite.ase == 0) {
303+
TraceLog(LOG_ERROR, "ASEPRITE: Cannot update empty tag");
304+
return;
305+
}
306+
307+
ase_t* ase = tag->aseprite.ase;
308+
ase_tag_t* aseTag = tag->tag;
309+
310+
// Count down the timer and see if it's time to update the frame.
311+
tag->timer -= GetFrameTime() * tag->speed;
312+
if (tag->timer > 0) {
313+
return;
314+
}
315+
316+
// Advance the frame and see if it's time to reset the position.
317+
tag->currentFrame += tag->direction;
318+
switch (aseTag->loop_animation_direction) {
319+
case ASE_ANIMATION_DIRECTION_BACKWORDS:
320+
if (tag->currentFrame < aseTag->from_frame) {
321+
tag->currentFrame = aseTag->to_frame;
322+
}
323+
break;
324+
case ASE_ANIMATION_DIRECTION_FORWARDS:
325+
if (tag->currentFrame > aseTag->to_frame) {
326+
tag->currentFrame = aseTag->from_frame;
327+
}
328+
break;
329+
case ASE_ANIMATION_DIRECTION_PINGPONG:
330+
if (tag->direction > 0) {
331+
if (tag->currentFrame > aseTag->to_frame) {
332+
tag->direction = -1;
333+
tag->currentFrame = aseTag->to_frame - 1;
334+
}
335+
}
336+
else {
337+
if (tag->currentFrame < aseTag->from_frame) {
338+
tag->direction = 1;
339+
tag->currentFrame = aseTag->from_frame + 1;
340+
}
341+
}
342+
break;
343+
}
344+
345+
// Reset the timer.
346+
// TODO: Add the original tag->timer to make up the different in frame time?
347+
tag->timer = (float)(ase->frames[tag->currentFrame].duration_milliseconds) / 1000.0f/* + tag->timer; */;
348+
}
349+
350+
void DrawAsepriteTag(AsepriteTag tag, int posX, int posY, Color tint) {
351+
DrawAseprite(tag.aseprite, tag.currentFrame, posX, posY, tint);
352+
}
353+
354+
void DrawAsepriteTagV(AsepriteTag tag, Vector2 position, Color tint) {
355+
DrawAsepriteV(tag.aseprite, tag.currentFrame, position, tint);
356+
}
357+
358+
void DrawAsepriteTagEx(AsepriteTag tag, Vector2 position, float rotation, float scale, Color tint) {
359+
DrawAsepriteEx(tag.aseprite, tag.currentFrame, position, rotation, scale, tint);
360+
}
361+
362+
void DrawAsepriteTagPro(AsepriteTag tag, Rectangle dest, Vector2 origin, float rotation, Color tint) {
363+
DrawAsepritePro(tag.aseprite, tag.currentFrame, dest, origin, rotation, tint);
364+
}
365+
366+
AsepriteTag LoadAsepriteTagFromId(Aseprite aseprite, int id) {
367+
struct AsepriteTag tag;
368+
tag.aseprite.ase = 0;
369+
tag.currentFrame = 0;
370+
tag.tag = 0;
371+
tag.timer = 0;
372+
tag.direction = 0;
373+
tag.speed = 1.0f;
374+
ase_t* ase = aseprite.ase;
375+
if (ase == 0) {
376+
TraceLog(LOG_ERROR, "ASEPRITE: Asprite not loaded when attempting to load tag #%i", id);
377+
return tag;
378+
}
379+
380+
if (id < 0 || id >= ase->tag_count) {
381+
TraceLog(LOG_ERROR, "ASEPRITE: Tag index %i out of range for %i tags", id, ase->tag_count);
382+
return tag;
383+
}
384+
385+
tag.aseprite.ase = aseprite.ase;
386+
tag.tag = &ase->tags[id];
387+
tag.currentFrame = tag.tag->from_frame;
388+
tag.direction = 1;
389+
if (tag.tag->loop_animation_direction == ASE_ANIMATION_DIRECTION_BACKWORDS) {
390+
tag.currentFrame = tag.tag->to_frame;
391+
tag.direction = -1;
392+
}
393+
tag.timer = (float)(ase->frames[tag.currentFrame].duration_milliseconds) / 1000.0f; // Timer in seconds.
394+
return tag;
395+
}
396+
397+
AsepriteTag LoadAsepriteTag(Aseprite aseprite, const char* name) {
398+
struct AsepriteTag tag;
399+
tag.aseprite.ase = 0;
400+
tag.currentFrame = 0;
401+
tag.tag = 0;
402+
tag.timer = 0;
403+
tag.direction = 0;
404+
tag.speed = 1.0f;
405+
ase_t* ase = aseprite.ase;
406+
if (ase == 0) {
407+
TraceLog(LOG_ERROR, "ASEPRITE: Asprite not loaded when attempting to load tag '%s'", name);
408+
return tag;
409+
}
410+
411+
// Loop through all tags to find the correct name.
412+
for (int i = 0; i < ase->tag_count; i++) {
413+
if (TextIsEqual(name, ase->tags[i].name)) {
414+
return LoadAsepriteTagFromId(aseprite, i);
415+
}
416+
}
417+
418+
TraceLog(LOG_WARNING, "ASEPRITE: Could not find tag %s", name);
419+
return tag;
420+
}
421+
422+
const char* GetAsepriteTagName(AsepriteTag tag) {
423+
if (tag.tag == 0) {
424+
TraceLog(LOG_WARNING, "ASEPRITE: Cannot get name of missing tag");
425+
return 0;
426+
}
427+
428+
return tag.tag->name;
429+
}
430+
431+
int GetAspriteTagCount(Aseprite aseprite) {
432+
if (aseprite.ase == 0) {
433+
TraceLog(LOG_WARNING, "ASEPRITE: Cannot get tag count when there is not loaded aseprite");
434+
return 0;
435+
}
436+
437+
return aseprite.ase->tag_count;
438+
}
439+
274440
#ifdef __cplusplus
275441
}
276442
#endif

0 commit comments

Comments
 (0)