X-Git-Url: https://git.cworth.org/git?p=xoboot;a=blobdiff_plain;f=xoboot.c;h=3259c8253194a03c7dce9f74dc196bbd428210bb;hp=ee6828997d3cd596492267b39ee4d4d70dcbe8af;hb=82ad6589427808bb226e303a019a61152969daf0;hpb=eaaa3520562b9e72d3ced47dc5e85f7118944a10 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 ();