Skip to content

Commit 9ba5b51

Browse files
authored
Support GIF image decoder and animation (#40)
To enable support for GIF animations, the twin_pixmap_t has been extended. The twin_pixmap_t now includes a new pointer to the new twin_animation_t, which manages multiple frames and their timing information for animated images. To manipulate twin_animation_t, the following APIs have been added: * twin_animation_get_current_delay: Retrieves the display duration ofthe current frame. * twin_animation_get_current_frame: Obtains the current frame for display. * twin_animation_advance_frame: Advances the animation to the next frame. If the animation is looping, it will return to the first frame after the last one. * twin_animation_destroy: Frees the memory allocated for the animation, including all associated frames. To showcase the new features, a demo application has been developed. This application supports both animated images and static images, and serves as a practical example of how to utilize the new animation capabilities.
1 parent 4260cc7 commit 9ba5b51

File tree

12 files changed

+919
-0
lines changed

12 files changed

+919
-0
lines changed

Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ libtwin.a_files-y = \
5151
src/pixmap.c \
5252
src/timeout.c \
5353
src/image.c \
54+
src/animation.c \
5455
src/api.c
5556

5657
libtwin.a_includes-y := \
@@ -74,6 +75,10 @@ libtwin.a_cflags-y += $(shell pkg-config --cflags libpng)
7475
TARGET_LIBS += $(shell pkg-config --libs libpng)
7576
endif
7677

78+
ifeq ($(CONFIG_LOADER_GIF), y)
79+
libtwin.a_files-y += src/image-gif.c
80+
endif
81+
7782
# Applications
7883

7984
libapps.a_files-y := apps/dummy.c
@@ -83,6 +88,7 @@ libapps.a_files-$(CONFIG_DEMO_CLOCK) += apps/clock.c
8388
libapps.a_files-$(CONFIG_DEMO_CALCULATOR) += apps/calc.c
8489
libapps.a_files-$(CONFIG_DEMO_LINE) += apps/line.c
8590
libapps.a_files-$(CONFIG_DEMO_SPLINE) += apps/spline.c
91+
libapps.a_files-$(CONFIG_DEMO_ANIMATION) += apps/animation.c
8692

8793
libapps.a_includes-y := include
8894

apps/animation.c

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Twin - A Tiny Window System
3+
* Copyright (c) 2024 National Cheng Kung University
4+
* All rights reserved.
5+
*/
6+
7+
#include <stdlib.h>
8+
9+
#include "twin_private.h"
10+
11+
#include "apps_animation.h"
12+
13+
#define _apps_animation_pixmap(animation) ((animation)->widget.window->pixmap)
14+
15+
typedef struct {
16+
twin_widget_t widget;
17+
twin_pixmap_t *pix;
18+
twin_timeout_t *timeout;
19+
} apps_animation_t;
20+
21+
static void _apps_animation_paint(apps_animation_t *anim)
22+
{
23+
twin_pixmap_t *current_frame = NULL;
24+
25+
if (twin_pixmap_is_animated(anim->pix)) {
26+
twin_animation_t *a = anim->pix->animation;
27+
current_frame = twin_animation_get_current_frame(a);
28+
twin_animation_advance_frame(a);
29+
} else {
30+
current_frame = anim->pix;
31+
}
32+
33+
twin_operand_t srcop = {
34+
.source_kind = TWIN_PIXMAP,
35+
.u.pixmap = current_frame,
36+
};
37+
twin_composite(_apps_animation_pixmap(anim), 0, 0, &srcop, 0, 0, NULL, 0, 0,
38+
TWIN_SOURCE, current_frame->width, current_frame->height);
39+
}
40+
41+
static twin_time_t _apps_animation_timeout(twin_time_t maybe_unused now,
42+
void *closure)
43+
{
44+
apps_animation_t *anim = closure;
45+
_twin_widget_queue_paint(&anim->widget);
46+
twin_animation_t *a = anim->pix->animation;
47+
twin_time_t delay = twin_animation_get_current_delay(a);
48+
return delay;
49+
}
50+
51+
static twin_dispatch_result_t _apps_animation_dispatch(twin_widget_t *widget,
52+
twin_event_t *event)
53+
{
54+
apps_animation_t *anim = (apps_animation_t *) widget;
55+
if (_twin_widget_dispatch(widget, event) == TwinDispatchDone)
56+
return TwinDispatchDone;
57+
switch (event->kind) {
58+
case TwinEventPaint:
59+
_apps_animation_paint(anim);
60+
break;
61+
default:
62+
break;
63+
}
64+
return TwinDispatchContinue;
65+
}
66+
67+
static void _apps_animation_init(apps_animation_t *anim,
68+
twin_box_t *parent,
69+
twin_dispatch_proc_t dispatch)
70+
{
71+
static const twin_widget_layout_t preferred = {0, 0, 1, 1};
72+
_twin_widget_init(&anim->widget, parent, 0, preferred, dispatch);
73+
74+
if (twin_pixmap_is_animated(anim->pix)) {
75+
twin_animation_t *a = anim->pix->animation;
76+
twin_time_t delay = twin_animation_get_current_delay(a);
77+
anim->timeout = twin_set_timeout(_apps_animation_timeout, delay, anim);
78+
} else {
79+
anim->timeout = NULL;
80+
}
81+
}
82+
83+
static apps_animation_t *apps_animation_create(twin_box_t *parent,
84+
twin_pixmap_t *pix)
85+
{
86+
apps_animation_t *anim = malloc(sizeof(apps_animation_t));
87+
anim->pix = pix;
88+
_apps_animation_init(anim, parent, _apps_animation_dispatch);
89+
return anim;
90+
}
91+
92+
void apps_animation_start(twin_screen_t *screen,
93+
const char *name,
94+
const char *path,
95+
int x,
96+
int y)
97+
{
98+
twin_pixmap_t *pix = twin_pixmap_from_file(path, TWIN_ARGB32);
99+
twin_toplevel_t *toplevel =
100+
twin_toplevel_create(screen, TWIN_ARGB32, TwinWindowApplication, x, y,
101+
pix->width, pix->height, name);
102+
apps_animation_t *anim = apps_animation_create(&toplevel->box, pix);
103+
(void) anim;
104+
twin_toplevel_show(toplevel);
105+
}

apps/apps_animation.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Twin - A Tiny Window System
3+
* Copyright (c) 2024 National Cheng Kung University
4+
* All rights reserved.
5+
*/
6+
7+
#ifndef _APPS_ANIMATION_H_
8+
#define _APPS_ANIMATION_H_
9+
10+
#include <twin.h>
11+
12+
void apps_animation_start(twin_screen_t *screen,
13+
const char *name,
14+
const char *path,
15+
int x,
16+
int y);
17+
18+
#endif /* _APPS_ANIMATION_H_ */

apps/main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <time.h>
1414
#include <unistd.h>
1515

16+
#include "apps_animation.h"
1617
#include "apps_calc.h"
1718
#include "apps_clock.h"
1819
#include "apps_hello.h"
@@ -122,6 +123,10 @@ int main(void)
122123
#if defined(CONFIG_DEMO_SPLINE)
123124
apps_spline_start(tx->screen, "Spline", 20, 20, 400, 400);
124125
#endif
126+
#if defined(CONFIG_DEMO_ANIMATION)
127+
apps_animation_start(tx->screen, "Viewer", ASSET_PATH "nyancat.gif", 20,
128+
20);
129+
#endif
125130

126131
twin_dispatch();
127132

assets/nyancat.gif

10.4 KB
Loading

configs/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ config LOADER_JPEG
3434
bool "Enable JPEG loader"
3535
default y
3636

37+
config LOADER_GIF
38+
bool "Enable GIF loader"
39+
default y
40+
3741
endmenu
3842

3943
menu "Demo Applications"
@@ -72,4 +76,8 @@ config DEMO_SPLINE
7276
default y
7377
depends on DEMO_APPLICATIONS
7478

79+
config DEMO_ANIMATION
80+
bool "Build animation demo"
81+
default y
82+
depends on DEMO_APPLICATIONS
7583
endmenu

configs/defconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
CONFIG_BACKEND_SDL=y
22
CONFIG_LOADER_PNG=y
33
CONFIG_LOADER_JPEG=y
4+
CONFIG_LOADER_GIF=y
45
CONFIG_DEMO_APPLICATIONS=y
56
CONFIG_DEMO_MULTI=y
67
CONFIG_DEMO_HELLO=y
78
CONFIG_DEMO_CLOCK=y
89
CONFIG_DEMO_CALCULATOR=y
910
CONFIG_DEMO_LINE=y
1011
CONFIG_DEMO_SPLINE=y
12+
CONFIG_DEMO_ANIMATION=y

include/twin.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ typedef union _twin_pointer {
7272

7373
typedef struct _twin_window twin_window_t;
7474
typedef struct _twin_screen twin_screen_t;
75+
typedef struct _twin_pixmap twin_pixmap_t;
76+
typedef struct _twin_animation twin_animation_t;
7577

7678
/*
7779
* Events
@@ -133,6 +135,27 @@ typedef struct _twin_event_queue {
133135
twin_event_t event;
134136
} twin_event_queue_t;
135137

138+
typedef struct _twin_animation_iter {
139+
twin_animation_t *anim;
140+
twin_count_t current_index;
141+
twin_pixmap_t *current_frame;
142+
twin_time_t current_delay;
143+
} twin_animation_iter_t;
144+
145+
typedef struct _twin_animation {
146+
/* Array of pixmaps representing each frame of the animation */
147+
twin_pixmap_t **frames;
148+
/* Number of frames in the animation */
149+
twin_count_t n_frames;
150+
/* Delay between frames in milliseconds */
151+
twin_time_t *frame_delays;
152+
/* Whether the animation should loop */
153+
bool loop;
154+
twin_animation_iter_t *iter;
155+
twin_coord_t width; /* pixels */
156+
twin_coord_t height; /* pixels */
157+
} twin_animation_t;
158+
136159
/*
137160
* A rectangular array of pixels
138161
*/
@@ -171,6 +194,7 @@ typedef struct _twin_pixmap {
171194
/*
172195
* Pixels
173196
*/
197+
twin_animation_t *animation;
174198
twin_pointer_t p;
175199
/*
176200
* When representing a window, this point
@@ -692,6 +716,32 @@ void twin_icon_draw(twin_pixmap_t *pixmap,
692716

693717
twin_pixmap_t *twin_pixmap_from_file(const char *path, twin_format_t fmt);
694718

719+
/*
720+
* animation.c
721+
*
722+
* Defines the interface for managing frame-based animations.
723+
* It provides functions to control and manipulate animations such as getting
724+
* the current frame, advancing the animation, and releasing resources.
725+
*/
726+
727+
/* Get the number of milliseconds the current frame should be displayed. */
728+
twin_time_t twin_animation_get_current_delay(const twin_animation_t *anim);
729+
730+
/* Get the current frame which should be displayed. */
731+
twin_pixmap_t *twin_animation_get_current_frame(const twin_animation_t *anim);
732+
733+
/* Advances the animation to the next frame. If the animation is looping, it
734+
* will return to the first frame after the last one. */
735+
void twin_animation_advance_frame(twin_animation_t *anim);
736+
737+
/* Frees the memory allocated for the animation, including all associated
738+
* frames. */
739+
void twin_animation_destroy(twin_animation_t *anim);
740+
741+
twin_animation_iter_t *twin_animation_iter_init(twin_animation_t *anim);
742+
743+
void twin_animation_iter_advance(twin_animation_iter_t *iter);
744+
695745
/*
696746
* label.c
697747
*/
@@ -856,6 +906,8 @@ twin_pixmap_t *twin_make_pattern(void);
856906
* pixmap.c
857907
*/
858908

909+
#define twin_pixmap_is_animated(pix) ((pix)->animation != NULL)
910+
859911
twin_pixmap_t *twin_pixmap_create(twin_format_t format,
860912
twin_coord_t width,
861913
twin_coord_t height);

src/animation.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Twin - A Tiny Window System
3+
* Copyright (c) 2024 National Cheng Kung University, Taiwan
4+
* All rights reserved.
5+
*/
6+
#include <stdlib.h>
7+
8+
#include "twin.h"
9+
10+
twin_time_t twin_animation_get_current_delay(const twin_animation_t *anim)
11+
{
12+
if (!anim)
13+
return 0;
14+
return anim->iter->current_delay;
15+
}
16+
17+
twin_pixmap_t *twin_animation_get_current_frame(const twin_animation_t *anim)
18+
{
19+
if (!anim)
20+
return NULL;
21+
return anim->iter->current_frame;
22+
}
23+
24+
void twin_animation_advance_frame(twin_animation_t *anim)
25+
{
26+
if (!anim)
27+
return;
28+
twin_animation_iter_advance(anim->iter);
29+
}
30+
31+
void twin_animation_destroy(twin_animation_t *anim)
32+
{
33+
if (!anim)
34+
return;
35+
36+
free(anim->iter);
37+
for (twin_count_t i = 0; i < anim->n_frames; i++) {
38+
twin_pixmap_destroy(anim->frames[i]);
39+
}
40+
free(anim->frames);
41+
free(anim->frame_delays);
42+
free(anim);
43+
}
44+
45+
twin_animation_iter_t *twin_animation_iter_init(twin_animation_t *anim)
46+
{
47+
twin_animation_iter_t *iter = malloc(sizeof(twin_animation_iter_t));
48+
if (!iter || !anim)
49+
return NULL;
50+
iter->current_index = 0;
51+
iter->current_frame = anim->frames[0];
52+
iter->current_delay = anim->frame_delays[0];
53+
anim->iter = iter;
54+
iter->anim = anim;
55+
return iter;
56+
}
57+
58+
void twin_animation_iter_advance(twin_animation_iter_t *iter)
59+
{
60+
twin_animation_t *anim = iter->anim;
61+
iter->current_index++;
62+
if (iter->current_index >= anim->n_frames) {
63+
if (anim->loop) {
64+
iter->current_index = 0;
65+
} else {
66+
iter->current_index = anim->n_frames - 1;
67+
}
68+
}
69+
iter->current_frame = anim->frames[iter->current_index];
70+
iter->current_delay = anim->frame_delays[iter->current_index];
71+
}

0 commit comments

Comments
 (0)