Mercurial > MadButterfly
comparison src/animate.c @ 41:400b4b5db0dc
Working on animation
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Fri, 08 Aug 2008 21:34:53 +0800 |
parents | |
children | e3295c07faa9 |
comparison
equal
deleted
inserted
replaced
40:e292beec12d4 | 41:400b4b5db0dc |
---|---|
1 /*! \brief Animation tools. | |
2 * | |
3 * XXX: Program is a sequence of actions duration a perior. | |
4 * Actions are grouped into words. A program defines | |
5 * the order and time of playing of words. A word | |
6 * defines how long to perform a set of actions. Actions | |
7 * in a word are performed concurrently. | |
8 */ | |
9 #include <stdio.h> | |
10 #include <stdlib.h> | |
11 #include <string.h> | |
12 #include "mb_types.h" | |
13 #include "redraw_man.h" | |
14 #include "mb_timer.h" | |
15 #include "animate.h" | |
16 | |
17 | |
18 #define STEP_INTERVAL 500000 | |
19 #define ASSERT(x) | |
20 | |
21 /*! \brief A word is a set of concurrent actions in a program. | |
22 */ | |
23 struct _mb_word { | |
24 mb_timeval_t start_time; /*!< time to start the word */ | |
25 mb_timeval_t playing_time; /*!< time duration of playing */ | |
26 STAILQ(mb_action_t) actions; | |
27 }; | |
28 | |
29 /*! \brief A program describe a series of actions to animate shapes. | |
30 */ | |
31 struct _mb_progm { | |
32 redraw_man_t *rdman; | |
33 | |
34 mb_timeval_t start_time, last_time; | |
35 int first_playing; /*!< first playing word. */ | |
36 mb_tman_t *tman; | |
37 | |
38 int n_words; | |
39 int max_words; | |
40 mb_word_t words[1]; | |
41 }; | |
42 | |
43 /*! \brief Basic class of nnimation actions. | |
44 */ | |
45 struct _mb_action { | |
46 int act_type; | |
47 void (*start)(mb_action_t *act, | |
48 const mb_timeval_t *now, | |
49 const mb_timeval_t *playing_time, | |
50 redraw_man_t *rdman); | |
51 void (*step)(mb_action_t *act, mb_timeval_t *now, redraw_man_t *rdman); | |
52 void (*stop)(mb_action_t *act, mb_timeval_t *now, redraw_man_t *rdman); | |
53 void (*free)(mb_action_t *act); | |
54 mb_action_t *next; | |
55 }; | |
56 | |
57 mb_progm_t *mb_progm_new(int max_words, redraw_man_t *rdman) { | |
58 mb_progm_t *progm; | |
59 int i; | |
60 | |
61 progm = (mb_progm_t *)malloc(sizeof(mb_progm_t) + | |
62 (sizeof(mb_word_t) * (max_words - 1))); | |
63 if(progm == NULL) | |
64 return NULL; | |
65 | |
66 progm->rdman = rdman; | |
67 progm->n_words = 0; | |
68 progm->max_words = max_words; | |
69 for(i = 0; i < max_words; i++) | |
70 STAILQ_INIT(progm->words[i].actions); | |
71 return progm; | |
72 } | |
73 | |
74 void mb_progm_free(mb_progm_t *progm) { | |
75 int n_words; | |
76 mb_word_t *word; | |
77 mb_action_t *cur_act; | |
78 int i; | |
79 | |
80 n_words = progm->n_words; | |
81 for(i = 0; i < n_words; i++) { | |
82 word = progm->words + i; | |
83 for(cur_act = STAILQ_HEAD(word->actions); | |
84 cur_act != NULL; | |
85 cur_act = STAILQ_HEAD(word->actions)) { | |
86 STAILQ_REMOVE(word->actions, mb_action_t, next, cur_act); | |
87 cur_act->free(cur_act); | |
88 } | |
89 free(word); | |
90 } | |
91 free(progm); | |
92 } | |
93 | |
94 /*! \brief Add a new word into a program. | |
95 * | |
96 * The start time of new word should bigger or equal to last one. | |
97 * The time should be specified in incremental order. | |
98 */ | |
99 mb_word_t *mb_progm_next_word(mb_progm_t *progm, | |
100 const mb_timeval_t *start, | |
101 const mb_timeval_t *playing) { | |
102 mb_word_t *word; | |
103 if(progm->n_words >= progm->max_words) | |
104 return NULL; | |
105 if(progm->n_words && | |
106 MB_TIMEVAL_LATER(&progm->words[progm->n_words - 1].start_time, start)) | |
107 return NULL; | |
108 word = progm->words + progm->n_words++; | |
109 memcpy(&word->start_time, start, sizeof(mb_timeval_t)); | |
110 memcpy(&word->playing_time, playing, sizeof(mb_timeval_t)); | |
111 return word; | |
112 } | |
113 | |
114 void mb_word_add_action(mb_word_t *word, mb_action_t *act) { | |
115 STAILQ_INS_TAIL(word->actions, mb_action_t, next, act); | |
116 } | |
117 | |
118 static void mb_word_start(mb_word_t *word, const mb_timeval_t *tmo, | |
119 const mb_timeval_t *now, redraw_man_t *rdman) { | |
120 } | |
121 | |
122 static void mb_word_step(mb_word_t *word, const mb_timeval_t *tmo, | |
123 const mb_timeval_t *now, redraw_man_t *rdman) { | |
124 } | |
125 | |
126 static void mb_word_stop(mb_word_t *word, const mb_timeval_t *tmo, | |
127 const mb_timeval_t *now, redraw_man_t *rdman) { | |
128 } | |
129 | |
130 static void mb_progm_step(const mb_timeval_t *tmo, | |
131 const mb_timeval_t *now, | |
132 void *arg) { | |
133 mb_progm_t *progm = (mb_progm_t *)arg; | |
134 mb_timeval_t next_tmo, w_stp_tm; | |
135 mb_word_t *word; | |
136 mb_timer_t *timer; | |
137 int i; | |
138 | |
139 MB_TIMEVAL_SET(&next_tmo, 0, STEP_INTERVAL); | |
140 MB_TIMEVAL_ADD(&next_tmo, tmo); | |
141 | |
142 i = progm->first_playing; | |
143 for(word = progm->words + i; | |
144 i < progm->n_words && MB_TIMEVAL_LATER(tmo, &word->start_time); | |
145 word = progm->words + ++i) { | |
146 memcpy(&w_stp_tm, &word->start_time, sizeof(mb_timeval_t)); | |
147 MB_TIMEVAL_ADD(&w_stp_tm, &word->playing_time); | |
148 if(MB_TIMEVAL_LATER(&w_stp_tm, tmo)) | |
149 mb_word_step(word, tmo, now, progm->rdman); | |
150 else { | |
151 if(MB_TIMEVAL_LATER(&w_stp_tm, &progm->last_time)) | |
152 mb_word_stop(word, tmo, now, progm->rdman); | |
153 if(i == progm->first_playing) | |
154 progm->first_playing++; | |
155 } | |
156 } | |
157 | |
158 for(word = progm->words + i; | |
159 i < progm->n_words && MB_TIMEVAL_LATER(&next_tmo, &word->start_time); | |
160 word = progm->words + ++i) { | |
161 mb_word_start(word, tmo, now, progm->rdman); | |
162 } | |
163 | |
164 if(progm->first_playing < progm->n_words) { | |
165 timer = mb_tman_timeout(progm->tman, &next_tmo, | |
166 mb_progm_step, progm); | |
167 ASSERT(timer != NULL); | |
168 } | |
169 } | |
170 | |
171 void mb_progm_start(mb_progm_t *progm, mb_tman_t *tman, | |
172 mb_timeval_t *now) { | |
173 mb_timeval_t next_time; | |
174 mb_timer_t *timer; | |
175 | |
176 if(progm->n_words == 0) | |
177 return; | |
178 | |
179 progm->tman = tman; | |
180 memcpy(&progm->start_time, now, sizeof(mb_timeval_t)); | |
181 memcpy(&progm->last_time, now, sizeof(mb_timeval_t)); | |
182 progm->first_playing = 0; | |
183 | |
184 memcpy(&next_time, &progm->words[0].start_time, sizeof(mb_timeval_t)); | |
185 MB_TIMEVAL_ADD(&next_time, now); | |
186 if(!MB_TIMEVAL_LATER(&next_time, now)) { | |
187 mb_progm_step(&next_time, now, progm); | |
188 return; | |
189 } | |
190 | |
191 timer = mb_tman_timeout(tman, &next_time, mb_progm_step, progm); | |
192 ASSERT(timer != NULL); | |
193 } | |
194 | |
195 typedef struct _mb_shift mb_shift_t; | |
196 /*! \brief Animation action for shift a coordination. */ | |
197 struct _mb_shift { | |
198 mb_action_t action; | |
199 | |
200 co_aix x, y; | |
201 coord_t *coord; | |
202 | |
203 mb_timeval_t start_time; | |
204 co_aix saved_matrix[6]; | |
205 const mb_timeval_t *playing_time; | |
206 }; | |
207 | |
208 static float comp_mb_timeval_ratio(mb_timeval_t *a, const mb_timeval_t *b) { | |
209 float ratio; | |
210 | |
211 ratio = (float)MB_TIMEVAL_SEC(a) * 1000000.0 + (float)MB_TIMEVAL_USEC(a); | |
212 ratio /= (float)MB_TIMEVAL_SEC(b) * 1000000.0 + (float)MB_TIMEVAL_USEC(b); | |
213 return ratio; | |
214 } | |
215 | |
216 static void mb_shift_start(mb_action_t *act, | |
217 const mb_timeval_t *now, | |
218 const mb_timeval_t *playing_time, | |
219 redraw_man_t *rdman) { | |
220 mb_shift_t *shift = (mb_shift_t *)act; | |
221 coord_t *coord; | |
222 | |
223 memcpy(&shift->start_time, now, sizeof(now)); | |
224 coord = shift->coord; | |
225 memcpy(&shift->saved_matrix, coord->matrix, sizeof(co_aix[6])); | |
226 shift->playing_time = playing_time; | |
227 } | |
228 | |
229 static void mb_shift_step(mb_action_t *act, mb_timeval_t *now, | |
230 redraw_man_t *rdman) { | |
231 mb_shift_t *shift = (mb_shift_t *)act; | |
232 mb_timeval_t diff; | |
233 coord_t *coord; | |
234 float ratio; | |
235 | |
236 | |
237 memcpy(&diff, now, sizeof(mb_timeval_t)); | |
238 MB_TIMEVAL_DIFF(&diff, &shift->start_time); | |
239 ratio = comp_mb_timeval_ratio(&diff, shift->playing_time); | |
240 | |
241 coord = shift->coord; | |
242 coord->matrix[2] = shift->saved_matrix[2] + shift->x * ratio; | |
243 coord->matrix[5] = shift->saved_matrix[5] + shift->y * ratio; | |
244 | |
245 rdman_coord_changed(rdman, coord); | |
246 } | |
247 | |
248 static void mb_shift_stop(mb_action_t *act, mb_timeval_t *now, | |
249 redraw_man_t *rdman) { | |
250 mb_shift_t *shift = (mb_shift_t *)act; | |
251 coord_t *coord; | |
252 | |
253 coord = shift->coord; | |
254 coord->matrix[2] = shift->saved_matrix[2] + shift->x; | |
255 coord->matrix[5] = shift->saved_matrix[5] + shift->y; | |
256 | |
257 rdman_coord_changed(rdman, coord); | |
258 } | |
259 | |
260 | |
261 static void mb_shift_free(mb_action_t *act) { | |
262 free(act); | |
263 } | |
264 | |
265 mb_action_t *mb_shift_new(co_aix x, co_aix y) { | |
266 mb_shift_t *shift; | |
267 | |
268 shift = (mb_shift_t *)malloc(sizeof(mb_shift_t)); | |
269 if(shift == NULL) | |
270 return (mb_action_t *)shift; | |
271 | |
272 shift->x = x; | |
273 shift->y = y; | |
274 shift->action.start = mb_shift_start; | |
275 shift->action.step = mb_shift_step; | |
276 shift->action.stop = mb_shift_stop; | |
277 shift->action.free = mb_shift_free; | |
278 | |
279 return (mb_action_t *)shift; | |
280 } |