]> git.cworth.org Git - xoboot/blobdiff - xoboot.c
Rename anim_state_t to anim_stage_t to avoid confusion with state_t
[xoboot] / xoboot.c
index eee192f04f2cdf8aa37e52376a40bdc9a4dd7c01..14cfd07bc737ff80a3138996416f216d786abf9e 100644 (file)
--- a/xoboot.c
+++ b/xoboot.c
 
 #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_stage_t;
+
+typedef struct _timeline {
+    double duration;
+    anim_stage_t state;
+    double transition;
+} timeline_t;
+
+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},
+    { 0.0, ANIM_DONE }
+};
 
 typedef struct _state {
     GtkWidget *drawing_area;
     double progress;
+    anim_stage_t anim_stage;
 } state_t;
 
+typedef struct _color {
+    double r;
+    double g;
+    double b;
+} color_t;
+
+#define HEX_COLOR(r,g,b) {(r) / 255.0, (g) / 255.0, (b) / 255.0}
+
+color_t background[2] = {
+    HEX_COLOR (0x75, 0x75, 0x75),
+    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_stage_t anim_stage = state->anim_stage;
     cairo_t *cr;
+    double shrink;
 
     cr = gdk_cairo_create (widget->window);
 
-    cairo_set_source_rgb (cr, state->progress, 0, 0);
+    if (anim_stage < ANIM_FADE)
+       set_color (cr, &background[0]);
+    else
+       set_color (cr, &background[1]);
+
     cairo_paint (cr);
 
+    if (anim_stage == ANIM_BLANK)
+       goto DONE;
+
+    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);
+       shrink = - XO_OUTLINE_SHRINK;
+    }
+
+    set_color (cr, &xo_green);
+
+    draw_head (cr, shrink);
+    if (anim_stage == ANIM_HEAD)
+       goto DONE;
+
+    draw_body (cr, shrink);
+    if (anim_stage == ANIM_BODY)
+       goto DONE;
+
+    if (anim_stage < ANIM_FADE)
+       draw_dots (cr);
+    else
+       draw_ring (cr);
+
+  DONE:
     cairo_destroy (cr);
 
     return TRUE;
@@ -52,15 +239,15 @@ create_window (state_t *state)
 }
 
 static gint
-timeout_callback (gpointer closure)
+timeline_advance (gpointer closure)
 {
     state_t *state = closure;
 
-    state->progress += 0.01;
-    if (state->progress > 1.0)
-       state->progress = 1.0;
-    else
-       gtk_widget_queue_draw (state->drawing_area);
+    if (state->anim_stage == ANIM_DONE)
+       return FALSE;
+
+    state->anim_stage++;
+    gtk_widget_queue_draw (state->drawing_area);
 
     return TRUE;
 }
@@ -74,10 +261,11 @@ main (int argc, char *argv[])
 
     state.drawing_area = create_window (&state);
     state.progress = 0.0;
+    state.anim_stage = 0;
 
     gtk_widget_show_all (gtk_widget_get_toplevel (state.drawing_area));
 
-    g_timeout_add (100, timeout_callback, &state);
+    g_timeout_add (1000, timeline_advance, &state);
 
     gtk_main ();