From 82ad6589427808bb226e303a019a61152969daf0 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 27 Aug 2007 23:34:08 -0700 Subject: [PATCH] Add all basic stages of the animation The element shapes, positions, and colors are all carefully designed to match the original Quicktime animation provided. All that's really missing now is the rotating animation of the hands. --- xoboot.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 7 deletions(-) diff --git a/xoboot.c b/xoboot.c index ee68289..3259c82 100644 --- a/xoboot.c +++ b/xoboot.c @@ -2,10 +2,39 @@ #include #include +#include + +typedef enum { + ANIM_BLANK, + ANIM_HEAD, + ANIM_BODY, + ANIM_SPIN, + ANIM_SPIN_DONE, + ANIM_OUTLINE, + ANIM_FADE, + ANIM_DONE +} anim_state_t; + +typedef struct _anim_stage { + double length; + anim_state_t state; +} anim_stage_t; + +anim_stage_t timeline[] = { + { 0.5, ANIM_BLANK }, + { 1.0, ANIM_HEAD }, + { 2.0, ANIM_BODY }, + { 6.0, ANIM_SPIN }, + { 1.0, ANIM_SPIN_DONE }, + { 1.0, ANIM_OUTLINE }, + { 1.0, ANIM_FADE }, + { 0.0, ANIM_DONE } +}; typedef struct _state { GtkWidget *drawing_area; double progress; + anim_state_t anim_state; } state_t; typedef struct _color { @@ -21,25 +50,163 @@ color_t background[2] = { HEX_COLOR (0xdb, 0xdc, 0xdf) }; +color_t xo_green = HEX_COLOR (0x4f, 0xff, 0x12); +color_t xo_black = HEX_COLOR (0x30, 0x30, 0x30); +color_t dot_gray = HEX_COLOR (0xe5, 0xe5, 0xe5); +color_t ring_white = HEX_COLOR (0xf1, 0xf1, 0xf1); + #define LERP(a,b,t) ((a) + (t) * ((b) - (a))) #define LERP_COLORS(c0, c1, t) LERP((c0).r, (c1).r, (t)), \ LERP((c0).g, (c1).g, (t)), \ LERP((c0).b, (c1).b, (t)) + +static void +set_color (cairo_t *cr, color_t *color) +{ + cairo_set_source_rgb (cr, color->r, color->g, color->b); +} + +#define XO_HEAD_CENTER_X 320 +#define XO_HEAD_CENTER_Y 211.5 +#define XO_HEAD_RADIUS 12.25 +#define XO_BODY_CENTER_X 320 +#define XO_BODY_CENTER_Y 250 +#define XO_BODY_DELTA 20.5 +#define XO_BODY_LINE_WIDTH 12.25 +#define XO_OUTLINE_EXTRA 2.5 +#define XO_OUTLINE_SHRINK 1.1 +#define XO_DOTS_CENTER_X 320 +#define XO_DOTS_CENTER_Y 240 +#define XO_DOTS_POSITION_RADIUS 112.5 +#define XO_DOTS_DOT_RADIUS 5.5 +#define XO_DOTS_NUM_DOTS 30 +#define XO_RING_CENTER_X 320 +#define XO_RING_CENTER_Y 240 +#define XO_RING_INNER_RADIUS 63 +#define XO_RING_OUTER_RADIUS 118 + +static void +draw_head (cairo_t *cr, double extra) +{ + cairo_arc (cr, + XO_HEAD_CENTER_X, + XO_HEAD_CENTER_Y, + XO_HEAD_RADIUS + extra, + 0, 2 * M_PI); + cairo_fill (cr); +} + +static void +draw_body (cairo_t *cr, double extra) +{ + 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); + cairo_rel_line_to (cr, XO_BODY_DELTA, -XO_BODY_DELTA); + 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); + 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); +} + +static void +draw_dots (cairo_t *cr) +{ + int i; + + cairo_save (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, 2 * M_PI / XO_DOTS_NUM_DOTS); + } + + cairo_restore (cr); +} + +static void +draw_ring (cairo_t *cr) +{ + cairo_save (cr); + + cairo_arc (cr, + XO_RING_CENTER_X, + XO_RING_CENTER_Y, + XO_RING_INNER_RADIUS, + 0, 2 * M_PI); + cairo_arc (cr, + XO_RING_CENTER_X, + XO_RING_CENTER_Y, + XO_RING_OUTER_RADIUS, + 0, 2 * M_PI); + set_color (cr, &ring_white); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + + cairo_restore (cr); +} + static gboolean xoboot_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer closure) { state_t *state = closure; + anim_state_t anim_state = state->anim_state; cairo_t *cr; + double shrink; cr = gdk_cairo_create (widget->window); - cairo_set_source_rgb (cr, LERP_COLORS (background[0], - background[1], - state->progress)); + if (anim_state < ANIM_FADE) + set_color (cr, &background[0]); + else + set_color (cr, &background[1]); + cairo_paint (cr); + if (anim_state == ANIM_BLANK) + goto DONE; + + shrink = 0.0; + if (anim_state >= ANIM_OUTLINE) { + set_color (cr, &xo_black); + draw_head (cr, XO_OUTLINE_EXTRA); + draw_body (cr, XO_OUTLINE_EXTRA); + shrink = - XO_OUTLINE_SHRINK; + } + + set_color (cr, &xo_green); + + draw_head (cr, shrink); + if (anim_state == ANIM_HEAD) + goto DONE; + + draw_body (cr, shrink); + if (anim_state == ANIM_BODY) + goto DONE; + + if (anim_state < ANIM_FADE) + draw_dots (cr); + else + draw_ring (cr); + + DONE: cairo_destroy (cr); return TRUE; @@ -75,9 +242,9 @@ timeout_callback (gpointer closure) { state_t *state = closure; - state->progress += 0.01; - if (state->progress > 1.0) - state->progress = 1.0; + state->anim_state++; + if (state->anim_state > ANIM_DONE) + state->anim_state = ANIM_DONE; else gtk_widget_queue_draw (state->drawing_area); @@ -93,10 +260,11 @@ main (int argc, char *argv[]) state.drawing_area = create_window (&state); state.progress = 0.0; + state.anim_state = 0; gtk_widget_show_all (gtk_widget_get_toplevel (state.drawing_area)); - g_timeout_add (100, timeout_callback, &state); + g_timeout_add (1000, timeout_callback, &state); gtk_main (); -- 2.43.0