X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=xoboot.c;h=14cfd07bc737ff80a3138996416f216d786abf9e;hb=b8d54384307f696e801ba39d0196543bed3ca7f5;hp=eee192f04f2cdf8aa37e52376a40bdc9a4dd7c01;hpb=68eb2053add8246aacfbf19dc4bdf015df7ff5b1;p=xoboot diff --git a/xoboot.c b/xoboot.c index eee192f..14cfd07 100644 --- a/xoboot.c +++ b/xoboot.c @@ -2,25 +2,212 @@ #include #include +#include + +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 ();