]> git.cworth.org Git - xoboot/commitdiff
Add all basic stages of the animation
authorCarl Worth <cworth@cworth.org>
Tue, 28 Aug 2007 06:34:08 +0000 (23:34 -0700)
committerCarl Worth <cworth@cworth.org>
Tue, 28 Aug 2007 06:34:08 +0000 (23:34 -0700)
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

index ee6828997d3cd596492267b39ee4d4d70dcbe8af..3259c8253194a03c7dce9f74dc196bbd428210bb 100644 (file)
--- a/xoboot.c
+++ b/xoboot.c
@@ -2,10 +2,39 @@
 
 #include <gtk/gtk.h>
 #include <cairo.h>
+#include <math.h>
+
+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 ();