From fbf45e3901075ef7e42f58cbfcf55947a8278e7e Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Tue, 28 Aug 2007 00:41:54 -0700 Subject: [PATCH] Add transition animations At this point, things look _really_ close to the original Quicktime animation. The most significant defect is that the circle of dots and the rotating hands have different center points. Currently, these rotate at basically the same angular speed, which means the hands are not pointing nicely at the dots. We should be just a touch more clever to make the dots appear exactly as they are pointed to by the hands. --- xoboot.c | 117 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 94 insertions(+), 23 deletions(-) diff --git a/xoboot.c b/xoboot.c index 14cfd07..4daa763 100644 --- a/xoboot.c +++ b/xoboot.c @@ -21,14 +21,17 @@ typedef struct _timeline { double transition; } timeline_t; +#define TIMELINE_ADVANCE_TIMER_PERIOD_MS 500 +#define TIMELINE_TRANSITION_FPS 20 + timeline_t timeline[] = { { 0.5, ANIM_BLANK, 0.0}, { 1.0, ANIM_HEAD, 0.0}, { 2.0, ANIM_BODY, 0.0}, { 7.0, ANIM_SPIN, 6.0}, { 1.0, ANIM_SPIN_DONE, 0.0}, - { 1.0, ANIM_OUTLINE, 0.0}, - { 1.0, ANIM_FADE, 0.5}, + { 1.0, ANIM_OUTLINE, 0.1}, + { 3.0, ANIM_FADE, 1.0}, { 0.0, ANIM_DONE } }; @@ -36,6 +39,11 @@ typedef struct _state { GtkWidget *drawing_area; double progress; anim_stage_t anim_stage; + int stage_ticks_remaining; + /* frames are used during a transition */ + int num_frames; + int frame; + double transition; } state_t; typedef struct _color { @@ -98,25 +106,35 @@ draw_head (cairo_t *cr, double extra) } static void -draw_body (cairo_t *cr, double extra) +draw_body (cairo_t *cr, double extra, double spin_transition) { + cairo_save (cr); + cairo_move_to (cr, XO_BODY_CENTER_X - XO_BODY_DELTA, - XO_BODY_CENTER_Y - XO_BODY_DELTA); - cairo_rel_line_to (cr, XO_BODY_DELTA, XO_BODY_DELTA); + XO_BODY_CENTER_Y + XO_BODY_DELTA); cairo_rel_line_to (cr, XO_BODY_DELTA, -XO_BODY_DELTA); + cairo_rel_line_to (cr, XO_BODY_DELTA, XO_BODY_DELTA); + + cairo_translate (cr, XO_HEAD_CENTER_X, XO_HEAD_CENTER_Y); + cairo_rotate (cr, 2 * M_PI * spin_transition); + cairo_translate (cr, -XO_HEAD_CENTER_X, -XO_HEAD_CENTER_Y); + cairo_move_to (cr, XO_BODY_CENTER_X - XO_BODY_DELTA, - XO_BODY_CENTER_Y + XO_BODY_DELTA); - cairo_rel_line_to (cr, XO_BODY_DELTA, -XO_BODY_DELTA); + XO_BODY_CENTER_Y - XO_BODY_DELTA); cairo_rel_line_to (cr, XO_BODY_DELTA, XO_BODY_DELTA); + cairo_rel_line_to (cr, XO_BODY_DELTA, -XO_BODY_DELTA); + cairo_set_line_width (cr, XO_BODY_LINE_WIDTH + 2 * extra); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_stroke (cr); + + cairo_restore (cr); } static void -draw_dots (cairo_t *cr) +draw_dots (cairo_t *cr, double num_dots) { int i; @@ -125,14 +143,16 @@ draw_dots (cairo_t *cr) set_color (cr, &dot_gray); cairo_translate (cr, XO_DOTS_CENTER_X, XO_DOTS_CENTER_Y); - cairo_rotate (cr, - M_PI_2); - - for (i = 0; i < XO_DOTS_NUM_DOTS; i++) { - cairo_arc (cr, - XO_DOTS_POSITION_RADIUS, 0, - XO_DOTS_DOT_RADIUS, - 0, 2 * M_PI); - cairo_fill (cr); + cairo_rotate (cr, - 1.5 * M_PI); + + for (i = 0; i < num_dots; i++) { + if (i != 0) { + cairo_arc (cr, + XO_DOTS_POSITION_RADIUS, 0, + XO_DOTS_DOT_RADIUS, + 0, 2 * M_PI); + cairo_fill (cr); + } cairo_rotate (cr, 2 * M_PI / XO_DOTS_NUM_DOTS); } @@ -171,25 +191,33 @@ xoboot_expose_event (GtkWidget *widget, anim_stage_t anim_stage = state->anim_stage; cairo_t *cr; double shrink; + double spin_transition = 1.0; cr = gdk_cairo_create (widget->window); if (anim_stage < ANIM_FADE) set_color (cr, &background[0]); else - set_color (cr, &background[1]); + cairo_set_source_rgb (cr, LERP_COLORS (background[0], + background[1], + state->transition)); cairo_paint (cr); if (anim_stage == ANIM_BLANK) goto DONE; + if (anim_stage == ANIM_SPIN) + spin_transition = state->transition; + shrink = 0.0; if (anim_stage >= ANIM_OUTLINE) { set_color (cr, &xo_black); draw_head (cr, XO_OUTLINE_EXTRA); - draw_body (cr, XO_OUTLINE_EXTRA); + draw_body (cr, XO_OUTLINE_EXTRA, spin_transition); shrink = - XO_OUTLINE_SHRINK; + if (anim_stage == ANIM_OUTLINE) + shrink *= state->transition; } set_color (cr, &xo_green); @@ -198,14 +226,15 @@ xoboot_expose_event (GtkWidget *widget, if (anim_stage == ANIM_HEAD) goto DONE; - draw_body (cr, shrink); + draw_body (cr, shrink, spin_transition); if (anim_stage == ANIM_BODY) goto DONE; - if (anim_stage < ANIM_FADE) - draw_dots (cr); - else + if (anim_stage < ANIM_FADE) { + draw_dots (cr, (XO_DOTS_NUM_DOTS + 1) * spin_transition); + } else { draw_ring (cr); + } DONE: cairo_destroy (cr); @@ -238,17 +267,53 @@ create_window (state_t *state) return drawing_area; } +static gint +transition_advance (gpointer closure) +{ + state_t *state = closure; + + if (state->frame >= state->num_frames - 1) { + state->frame = state->num_frames - 1; + return FALSE; + } + + state->frame++; + state->transition = (double) state->frame / (state->num_frames - 1); + + gtk_widget_queue_draw (state->drawing_area); + + return TRUE; +} + static gint timeline_advance (gpointer closure) { state_t *state = closure; + timeline_t *tl; if (state->anim_stage == ANIM_DONE) return FALSE; + if (--state->stage_ticks_remaining) + return TRUE; + state->anim_stage++; + tl = &timeline[state->anim_stage]; + state->stage_ticks_remaining = (tl->duration * 1000 + / TIMELINE_ADVANCE_TIMER_PERIOD_MS); gtk_widget_queue_draw (state->drawing_area); + if (tl->transition > 1.0 / TIMELINE_TRANSITION_FPS) { + state->num_frames = tl->transition * TIMELINE_TRANSITION_FPS; + state->frame = 0; + state->transition = 0.0; + g_timeout_add (1000 / TIMELINE_TRANSITION_FPS, transition_advance, state); + } else { + state->num_frames = 1; + state->frame = 0; + state->transition = 1.0; + } + return TRUE; } @@ -262,10 +327,16 @@ main (int argc, char *argv[]) state.drawing_area = create_window (&state); state.progress = 0.0; state.anim_stage = 0; + state.num_frames = 1; + state.frame = 0; + state.transition = 1.0; + state.stage_ticks_remaining = (timeline[state.anim_stage].duration * 1000 + / TIMELINE_ADVANCE_TIMER_PERIOD_MS); gtk_widget_show_all (gtk_widget_get_toplevel (state.drawing_area)); - g_timeout_add (1000, timeline_advance, &state); + g_timeout_add (TIMELINE_ADVANCE_TIMER_PERIOD_MS, + timeline_advance, &state); gtk_main (); -- 2.43.0