# HG changeset patch # User Thinker K.F. Li # Date 1218202493 -28800 # Node ID 400b4b5db0dc5c502f77301b9b89c24fc09b461f # Parent e292beec12d4d62da4500b946085305d74f78be2 Working on animation diff -r e292beec12d4 -r 400b4b5db0dc src/Makefile --- a/src/Makefile Wed Aug 06 21:34:53 2008 +0800 +++ b/src/Makefile Fri Aug 08 21:34:53 2008 +0800 @@ -1,5 +1,5 @@ SRCS = coord.c geo.c shape_path.c shape_text.c shape_rect.c \ - redraw_man.c timer.c paint.c event.c tools.c + redraw_man.c timer.c animate.c paint.c event.c tools.c OBJS = ${SRCS:C/(.*)\.c/\1.o/g} TESTCASE_OBJS = ${SRCS:C/(.*)\.c/testcase-\1.o/g} CFLAGS+= -Wall -I/usr/local/include `pkg-config --cflags cairo` diff -r e292beec12d4 -r 400b4b5db0dc src/X_main.c --- a/src/X_main.c Wed Aug 06 21:34:53 2008 +0800 +++ b/src/X_main.c Fri Aug 08 21:34:53 2008 +0800 @@ -24,8 +24,8 @@ redraw_man_t *rdman; }; -void test_motion(mbsec_t sec, mbusec_t usec, - mbsec_t now_sec, mbusec_t now_usec, +void test_motion(const mb_timeval_t *tmo, + const mb_timeval_t *now, void *arg) { struct test_motion_data *data = (struct test_motion_data *)arg; @@ -88,6 +88,7 @@ fd_set rds; int nfds; struct timeval tmo; + mb_timeval_t mb_tmo; int r; XSelectInput(display, win, PointerMotionMask | ExposureMask); @@ -104,14 +105,15 @@ return; } - r = mb_tman_next_timeout(tman, - tmo.tv_sec, tmo.tv_usec, - (mbsec_t *)&tmo.tv_sec, - (mbusec_t *)&tmo.tv_usec); + MB_TIMEVAL_SET(&mb_tmo, tmo.tv_sec, tmo.tv_usec); + r = mb_tman_next_timeout(tman, &mb_tmo, &mb_tmo); if(r != OK) r = select(nfds, &rds, NULL, NULL, NULL); - else + else { + tmo.tv_sec = MB_TIMEVAL_SEC(&mb_tmo); + tmo.tv_usec = MB_TIMEVAL_USEC(&mb_tmo); r = select(nfds, &rds, NULL, NULL, &tmo); + } if(r == -1) { perror("select"); @@ -123,7 +125,8 @@ perror("gettimeofday"); return; } - mb_tman_handle_timeout(tman, tmo.tv_sec, tmo.tv_usec); + MB_TIMEVAL_SET(&mb_tmo, tmo.tv_sec, tmo.tv_usec); + mb_tman_handle_timeout(tman, &mb_tmo); XFlush(display); } else if(FD_ISSET(xcon, &rds)) { event_interaction(display, rdman, w, h); @@ -145,6 +148,7 @@ struct test_motion_data mdata; struct timeval tv; mb_tman_t *tman; + mb_timeval_t mbtv; int i; tmpsuf = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); @@ -296,10 +300,11 @@ mdata.rdman = &rdman; gettimeofday(&tv, NULL); tv.tv_sec += 3; - mb_tman_timeout(tman, tv.tv_sec, tv.tv_usec, - test_motion, &mdata); + MB_TIMEVAL_SET(&mbtv, tv.tv_sec, tv.tv_usec); + mb_tman_timeout(tman, &mbtv, test_motion, &mdata); handle_connection(display, tman, &rdman, w, h); + mb_tman_free(tman); } diff -r e292beec12d4 -r 400b4b5db0dc src/animate.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/animate.c Fri Aug 08 21:34:53 2008 +0800 @@ -0,0 +1,280 @@ +/*! \brief Animation tools. + * + * XXX: Program is a sequence of actions duration a perior. + * Actions are grouped into words. A program defines + * the order and time of playing of words. A word + * defines how long to perform a set of actions. Actions + * in a word are performed concurrently. + */ +#include +#include +#include +#include "mb_types.h" +#include "redraw_man.h" +#include "mb_timer.h" +#include "animate.h" + + +#define STEP_INTERVAL 500000 +#define ASSERT(x) + +/*! \brief A word is a set of concurrent actions in a program. + */ +struct _mb_word { + mb_timeval_t start_time; /*!< time to start the word */ + mb_timeval_t playing_time; /*!< time duration of playing */ + STAILQ(mb_action_t) actions; +}; + +/*! \brief A program describe a series of actions to animate shapes. + */ +struct _mb_progm { + redraw_man_t *rdman; + + mb_timeval_t start_time, last_time; + int first_playing; /*!< first playing word. */ + mb_tman_t *tman; + + int n_words; + int max_words; + mb_word_t words[1]; +}; + +/*! \brief Basic class of nnimation actions. + */ +struct _mb_action { + int act_type; + void (*start)(mb_action_t *act, + const mb_timeval_t *now, + const mb_timeval_t *playing_time, + redraw_man_t *rdman); + void (*step)(mb_action_t *act, mb_timeval_t *now, redraw_man_t *rdman); + void (*stop)(mb_action_t *act, mb_timeval_t *now, redraw_man_t *rdman); + void (*free)(mb_action_t *act); + mb_action_t *next; +}; + +mb_progm_t *mb_progm_new(int max_words, redraw_man_t *rdman) { + mb_progm_t *progm; + int i; + + progm = (mb_progm_t *)malloc(sizeof(mb_progm_t) + + (sizeof(mb_word_t) * (max_words - 1))); + if(progm == NULL) + return NULL; + + progm->rdman = rdman; + progm->n_words = 0; + progm->max_words = max_words; + for(i = 0; i < max_words; i++) + STAILQ_INIT(progm->words[i].actions); + return progm; +} + +void mb_progm_free(mb_progm_t *progm) { + int n_words; + mb_word_t *word; + mb_action_t *cur_act; + int i; + + n_words = progm->n_words; + for(i = 0; i < n_words; i++) { + word = progm->words + i; + for(cur_act = STAILQ_HEAD(word->actions); + cur_act != NULL; + cur_act = STAILQ_HEAD(word->actions)) { + STAILQ_REMOVE(word->actions, mb_action_t, next, cur_act); + cur_act->free(cur_act); + } + free(word); + } + free(progm); +} + +/*! \brief Add a new word into a program. + * + * The start time of new word should bigger or equal to last one. + * The time should be specified in incremental order. + */ +mb_word_t *mb_progm_next_word(mb_progm_t *progm, + const mb_timeval_t *start, + const mb_timeval_t *playing) { + mb_word_t *word; + if(progm->n_words >= progm->max_words) + return NULL; + if(progm->n_words && + MB_TIMEVAL_LATER(&progm->words[progm->n_words - 1].start_time, start)) + return NULL; + word = progm->words + progm->n_words++; + memcpy(&word->start_time, start, sizeof(mb_timeval_t)); + memcpy(&word->playing_time, playing, sizeof(mb_timeval_t)); + return word; +} + +void mb_word_add_action(mb_word_t *word, mb_action_t *act) { + STAILQ_INS_TAIL(word->actions, mb_action_t, next, act); +} + +static void mb_word_start(mb_word_t *word, const mb_timeval_t *tmo, + const mb_timeval_t *now, redraw_man_t *rdman) { +} + +static void mb_word_step(mb_word_t *word, const mb_timeval_t *tmo, + const mb_timeval_t *now, redraw_man_t *rdman) { +} + +static void mb_word_stop(mb_word_t *word, const mb_timeval_t *tmo, + const mb_timeval_t *now, redraw_man_t *rdman) { +} + +static void mb_progm_step(const mb_timeval_t *tmo, + const mb_timeval_t *now, + void *arg) { + mb_progm_t *progm = (mb_progm_t *)arg; + mb_timeval_t next_tmo, w_stp_tm; + mb_word_t *word; + mb_timer_t *timer; + int i; + + MB_TIMEVAL_SET(&next_tmo, 0, STEP_INTERVAL); + MB_TIMEVAL_ADD(&next_tmo, tmo); + + i = progm->first_playing; + for(word = progm->words + i; + i < progm->n_words && MB_TIMEVAL_LATER(tmo, &word->start_time); + word = progm->words + ++i) { + memcpy(&w_stp_tm, &word->start_time, sizeof(mb_timeval_t)); + MB_TIMEVAL_ADD(&w_stp_tm, &word->playing_time); + if(MB_TIMEVAL_LATER(&w_stp_tm, tmo)) + mb_word_step(word, tmo, now, progm->rdman); + else { + if(MB_TIMEVAL_LATER(&w_stp_tm, &progm->last_time)) + mb_word_stop(word, tmo, now, progm->rdman); + if(i == progm->first_playing) + progm->first_playing++; + } + } + + for(word = progm->words + i; + i < progm->n_words && MB_TIMEVAL_LATER(&next_tmo, &word->start_time); + word = progm->words + ++i) { + mb_word_start(word, tmo, now, progm->rdman); + } + + if(progm->first_playing < progm->n_words) { + timer = mb_tman_timeout(progm->tman, &next_tmo, + mb_progm_step, progm); + ASSERT(timer != NULL); + } +} + +void mb_progm_start(mb_progm_t *progm, mb_tman_t *tman, + mb_timeval_t *now) { + mb_timeval_t next_time; + mb_timer_t *timer; + + if(progm->n_words == 0) + return; + + progm->tman = tman; + memcpy(&progm->start_time, now, sizeof(mb_timeval_t)); + memcpy(&progm->last_time, now, sizeof(mb_timeval_t)); + progm->first_playing = 0; + + memcpy(&next_time, &progm->words[0].start_time, sizeof(mb_timeval_t)); + MB_TIMEVAL_ADD(&next_time, now); + if(!MB_TIMEVAL_LATER(&next_time, now)) { + mb_progm_step(&next_time, now, progm); + return; + } + + timer = mb_tman_timeout(tman, &next_time, mb_progm_step, progm); + ASSERT(timer != NULL); +} + +typedef struct _mb_shift mb_shift_t; +/*! \brief Animation action for shift a coordination. */ +struct _mb_shift { + mb_action_t action; + + co_aix x, y; + coord_t *coord; + + mb_timeval_t start_time; + co_aix saved_matrix[6]; + const mb_timeval_t *playing_time; +}; + +static float comp_mb_timeval_ratio(mb_timeval_t *a, const mb_timeval_t *b) { + float ratio; + + ratio = (float)MB_TIMEVAL_SEC(a) * 1000000.0 + (float)MB_TIMEVAL_USEC(a); + ratio /= (float)MB_TIMEVAL_SEC(b) * 1000000.0 + (float)MB_TIMEVAL_USEC(b); + return ratio; +} + +static void mb_shift_start(mb_action_t *act, + const mb_timeval_t *now, + const mb_timeval_t *playing_time, + redraw_man_t *rdman) { + mb_shift_t *shift = (mb_shift_t *)act; + coord_t *coord; + + memcpy(&shift->start_time, now, sizeof(now)); + coord = shift->coord; + memcpy(&shift->saved_matrix, coord->matrix, sizeof(co_aix[6])); + shift->playing_time = playing_time; +} + +static void mb_shift_step(mb_action_t *act, mb_timeval_t *now, + redraw_man_t *rdman) { + mb_shift_t *shift = (mb_shift_t *)act; + mb_timeval_t diff; + coord_t *coord; + float ratio; + + + memcpy(&diff, now, sizeof(mb_timeval_t)); + MB_TIMEVAL_DIFF(&diff, &shift->start_time); + ratio = comp_mb_timeval_ratio(&diff, shift->playing_time); + + coord = shift->coord; + coord->matrix[2] = shift->saved_matrix[2] + shift->x * ratio; + coord->matrix[5] = shift->saved_matrix[5] + shift->y * ratio; + + rdman_coord_changed(rdman, coord); +} + +static void mb_shift_stop(mb_action_t *act, mb_timeval_t *now, + redraw_man_t *rdman) { + mb_shift_t *shift = (mb_shift_t *)act; + coord_t *coord; + + coord = shift->coord; + coord->matrix[2] = shift->saved_matrix[2] + shift->x; + coord->matrix[5] = shift->saved_matrix[5] + shift->y; + + rdman_coord_changed(rdman, coord); +} + + +static void mb_shift_free(mb_action_t *act) { + free(act); +} + +mb_action_t *mb_shift_new(co_aix x, co_aix y) { + mb_shift_t *shift; + + shift = (mb_shift_t *)malloc(sizeof(mb_shift_t)); + if(shift == NULL) + return (mb_action_t *)shift; + + shift->x = x; + shift->y = y; + shift->action.start = mb_shift_start; + shift->action.step = mb_shift_step; + shift->action.stop = mb_shift_stop; + shift->action.free = mb_shift_free; + + return (mb_action_t *)shift; +} diff -r e292beec12d4 -r 400b4b5db0dc src/animate.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/animate.h Fri Aug 08 21:34:53 2008 +0800 @@ -0,0 +1,17 @@ +#ifndef __ANIMATE_H_ +#define __ANIMATE_H_ + +typedef struct _mb_progm mb_progm_t; +typedef struct _mb_word mb_word_t; +typedef struct _mb_action mb_action_t; +typedef struct _mb_progm_state mb_progm_state_t; + +extern mb_progm_t *mb_progm_new(int max_words, redraw_man_t *rdman); +extern void mb_progm_free(mb_progm_t *progm); +extern mb_word_t *mb_progm_next_word(mb_progm_t *progm, + const mb_timeval_t *start, + const mb_timeval_t *playing); +extern void mb_word_add_action(mb_word_t *word, mb_action_t *act); +extern mb_action_t *mb_shift_new(co_aix x, co_aix y); + +#endif /* __ANIMATE_H_ */ diff -r e292beec12d4 -r 400b4b5db0dc src/mb_timer.h --- a/src/mb_timer.h Wed Aug 06 21:34:53 2008 +0800 +++ b/src/mb_timer.h Fri Aug 08 21:34:53 2008 +0800 @@ -1,27 +1,59 @@ #ifndef __MB_TIMER_H_ #define __MB_TIMER_H_ +#include + typedef uint32_t mbsec_t; typedef uint32_t mbusec_t; typedef struct _mb_timer mb_timer_t; typedef struct _mb_tman mb_tman_t; +typedef struct timeval mb_timeval_t; -typedef void (*mb_tmo_hdlr)(mbsec_t sec, mbusec_t usec, - mbsec_t now_sec, mbusec_t now_usec, + +typedef void (*mb_tmo_hdlr)(const mb_timeval_t *tmo, + const mb_timeval_t *now, void *arg); extern mb_tman_t *mb_tman_new(void); extern void mb_tman_free(mb_tman_t *tman); extern mb_timer_t *mb_tman_timeout(mb_tman_t *tman, - mbsec_t sec, mbusec_t usec, + const mb_timeval_t *tmo, mb_tmo_hdlr hdlr, void *arg); extern int mb_tman_remove(mb_tman_t *tman, mb_timer_t *timer); extern int mb_tman_next_timeout(mb_tman_t *tman, - mbsec_t now_sec, mbusec_t now_usec, - mbsec_t *after_sec, mbusec_t *after_usec); -extern int mb_tman_handle_timeout(mb_tman_t *tman, - mbsec_t now_sec, mbusec_t now_usec); + const mb_timeval_t *now, + mb_timeval_t *tmo_after); +extern int mb_tman_handle_timeout(mb_tman_t *tman, mb_timeval_t *now); +#define MB_TIMEVAL_SET(_tv, _sec, _usec) \ + do { \ + (_tv)->tv_sec = _sec; \ + (_tv)->tv_usec = _usec; \ + } while(0) +#define MB_TIMEVAL_SEC(_tv) ((_tv)->tv_sec) +#define MB_TIMEVAL_USEC(_tv) ((_tv)->tv_usec) +#define MB_TIMEVAL_LATER(a, b) \ + ((a)->tv_sec > (b)->tv_sec || \ + ((a)->tv_sec == (b)->tv_sec && \ + (a)->tv_usec > (b)->tv_usec)) +#define MB_TIMEVAL_DIFF(a, b) \ + do { \ + (a)->tv_sec -= (b)->tv_sec; \ + if((a)->tv_usec < (b)->tv_usec) { \ + (a)->tv_sec--; \ + (a)->tv_usec += 1000000; \ + } \ + (a)->tv_usec -= (b)->tv_usec; \ + } while(0) +#define MB_TIMEVAL_ADD(a, b) \ + do { \ + (a)->tv_sec += (b)->tv_sec; \ + (a)->tv_usec += (b)->tv_usec; \ + if((a)->tv_usec >= 1000000) { \ + (a)->tv_sec++; \ + (a)->tv_usec -= 1000000; \ + } \ + } while(0) #endif /* __MB_TIMER_H_ */ diff -r e292beec12d4 -r 400b4b5db0dc src/timer.c --- a/src/timer.c Wed Aug 06 21:34:53 2008 +0800 +++ b/src/timer.c Fri Aug 08 21:34:53 2008 +0800 @@ -1,6 +1,7 @@ #include #include #include +#include #include "mb_timer.h" #include "tools.h" @@ -9,8 +10,7 @@ #define ERR -1 struct _mb_timer { - mbsec_t sec; - mbusec_t usec; + mb_timeval_t tmo; mb_tmo_hdlr hdlr; void *arg; mb_timer_t *next; @@ -45,7 +45,7 @@ } mb_timer_t *mb_tman_timeout(mb_tman_t *tman, - mbsec_t sec, mbusec_t usec, + const mb_timeval_t *tmo, mb_tmo_hdlr hdlr, void *arg) { mb_timer_t *timer, *visit, *last; @@ -53,8 +53,7 @@ if(timer == NULL) return NULL; - timer->sec = sec; - timer->usec = usec; + memcpy(&timer->tmo, tmo, sizeof(mb_timeval_t)); timer->hdlr = hdlr; timer->arg = arg; @@ -62,9 +61,7 @@ for(visit = STAILQ_HEAD(tman->timers); visit != NULL; visit = STAILQ_NEXT(mb_timer_t, next, visit)) { - if(sec < visit->sec) - break; - if(sec == visit->sec && usec < visit->usec) + if(MB_TIMEVAL_LATER(&visit->tmo, tmo)) break; last = visit; } @@ -87,42 +84,31 @@ } int mb_tman_next_timeout(mb_tman_t *tman, - mbsec_t now_sec, mbusec_t now_usec, - mbsec_t *after_sec, mbusec_t *after_usec) { + const mb_timeval_t *now, mb_timeval_t *tmo_after) { mb_timer_t *timer; timer = STAILQ_HEAD(tman->timers); if(timer == NULL) return ERR; - if(now_sec > timer->sec || - (now_sec == timer->usec && now_usec >= timer->usec)) { - *after_sec = 0; - *after_usec = 0; + if(!MB_TIMEVAL_LATER(&timer->tmo, now)) { + memset(tmo_after, 0, sizeof(mb_timeval_t)); return OK; } - *after_sec = timer->sec - now_sec; - if(now_usec > timer->usec) { - --*after_sec; - *after_usec = 1000000 + timer->usec - now_usec; - } else - *after_usec = timer->usec - now_usec; + memcpy(tmo_after, &timer->tmo, sizeof(mb_timeval_t)); + MB_TIMEVAL_DIFF(tmo_after, now); return OK; } -int mb_tman_handle_timeout(mb_tman_t *tman, - mbsec_t now_sec, mbusec_t now_usec) { +int mb_tman_handle_timeout(mb_tman_t *tman, mb_timeval_t *now) { mb_timer_t *timer; while((timer = STAILQ_HEAD(tman->timers)) != NULL){ - if(now_sec < timer->sec || - (now_sec == timer->sec && now_usec < timer->usec)) + if(MB_TIMEVAL_LATER(&timer->tmo, now)) break; - timer->hdlr(timer->sec, timer->usec, - now_sec, now_usec, - timer->arg); + timer->hdlr(&timer->tmo, now, timer->arg); STAILQ_REMOVE(tman->timers, mb_timer_t, next, timer); elmpool_elm_free(tman->timer_pool, timer); }