Mercurial > MadButterfly
annotate src/animate.c @ 935:960e2395973d
Fix the bug of crash by abort() when running testsvg.js.
The cached coords their pcache areas should be recomputed are also add
ro zeroing list. They have no dirty areas. But, their pcache area
must be added to parent cached coord.
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Fri, 12 Nov 2010 16:03:19 +0800 |
parents | 586e50f82c1f |
children | 9b5d4839c5bb |
rev | line source |
---|---|
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
1 // -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 4; -*- |
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
2 // vim: sw=4:ts=8:sts=4 |
111 | 3 /*! \file |
4 * \brief Animation tools. | |
5 * | |
117 | 6 * \sa \ref ani |
111 | 7 */ |
8 /*! \page ani What is Animation? | |
41 | 9 * |
117 | 10 * Animation is a program to move, resize, rotate, ..., changing |
11 * graphics on the output screen. | |
12 * | |
13 * \image html program.png | |
14 * | |
41 | 15 * XXX: Program is a sequence of actions duration a perior. |
16 * Actions are grouped into words. A program defines | |
17 * the order and time of playing of words. A word | |
18 * defines how long to perform a set of actions. Actions | |
19 * in a word are performed concurrently. | |
45 | 20 * |
21 * Animation shapes are updated periodically. Every action | |
22 * are working with start, step, and stop 3 calls. start is | |
23 * called when start time the word, contain it, due. step is | |
24 * called periodically in duration of playing time start at | |
25 * 'start time'. When the clock run out the playing time of | |
26 * a word, it call stop of actions in the word. | |
111 | 27 * |
28 * A program is driven by a timer. Once a program is started, it registers | |
29 * with timer for periodic running. \ref mb_tman_t is timer of | |
30 * MadButterfly. The update frequence is 10fps by default, now. | |
31 * | |
117 | 32 * \section use_progm How to Use Animation Program? |
33 * Following code block creates a program with 2 words. First word is | |
34 * started immediately after the program been started. It is consisted | |
35 * for 1 second. Second word is started 1 second after the program been | |
36 * started. It is consisted for 2 seconds. There are 2 action in | |
37 * first word, they shift graphics managed by coord1 & coord2 by (50,50) and | |
38 * (-50,50) pixels, respectly. The shifting is performed incrementally | |
39 * in 1 second. Second word shifts coord1 and coord2, too. And, graphics | |
40 * managed by coord3 are hidden at end of the word. At end of code in the | |
41 * block, mb_progm_start() starts the program. 3rd argument of | |
42 * mb_progm_start() must be current wall time. | |
43 * | |
44 * \code | |
45 * progm = mb_progm_new(10, &rdman); | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
46 * |
117 | 47 * MB_TIMEVAL_SET(&start, 0, 0); |
48 * MB_TIMEVAL_SET(&playing, 1, 0); | |
49 * word = mb_progm_next_word(progm, &start, &playing); | |
50 * | |
51 * act = mb_shift_new(50, 50, coord1, word); | |
52 * act = mb_shift_new(-50, 50, coord2, word); | |
53 * | |
54 * MB_TIMEVAL_SET(&start, 1, 0); | |
55 * MB_TIMEVAL_SET(&playing, 2, 0); | |
56 * word = mb_progm_next_word(progm, &start, &playing); | |
57 * | |
58 * act = mb_shift_new(0, 20, coord1, word); | |
59 * act = mb_shift_new(0, -20, coord2, word); | |
60 * act = mb_visibility_new(VIS_HIDDEN, coord3, word); | |
61 * | |
62 * gettimeofday(&tv, NULL); | |
63 * MB_TIMEVAL_SET(&mbtv, tv.tv_sec, tv.tv_usec); | |
64 * mb_progm_start(progm, tman, &mbtv); | |
65 * \endcode | |
66 * | |
67 * | |
68 * \sa \ref animate.c | |
41 | 69 */ |
70 #include <stdio.h> | |
71 #include <stdlib.h> | |
72 #include <string.h> | |
186
530bb7728546
Move header files to $(top_srcdir)/include/ and prefixed with 'mb_'.
Thinker K.F. Li <thinker@branda.to>
parents:
185
diff
changeset
|
73 #include "mb_types.h" |
530bb7728546
Move header files to $(top_srcdir)/include/ and prefixed with 'mb_'.
Thinker K.F. Li <thinker@branda.to>
parents:
185
diff
changeset
|
74 #include "mb_redraw_man.h" |
530bb7728546
Move header files to $(top_srcdir)/include/ and prefixed with 'mb_'.
Thinker K.F. Li <thinker@branda.to>
parents:
185
diff
changeset
|
75 #include "mb_timer.h" |
530bb7728546
Move header files to $(top_srcdir)/include/ and prefixed with 'mb_'.
Thinker K.F. Li <thinker@branda.to>
parents:
185
diff
changeset
|
76 #include "mb_animate.h" |
41 | 77 |
78 | |
122
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
79 #define STEP_INTERVAL 90000 |
41 | 80 #define ASSERT(x) |
81 | |
82 /*! \brief A word is a set of concurrent actions in a program. | |
83 */ | |
84 struct _mb_word { | |
85 mb_timeval_t start_time; /*!< time to start the word */ | |
86 mb_timeval_t playing_time; /*!< time duration of playing */ | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
87 mb_timeval_t abs_start, abs_stop; |
41 | 88 STAILQ(mb_action_t) actions; |
89 }; | |
90 | |
91 /*! \brief A program describe a series of actions to animate shapes. | |
51 | 92 * |
93 * first_playing is an index to one of words. It always points to | |
94 * the first of words that is playing or waiting for playing. | |
41 | 95 */ |
96 struct _mb_progm { | |
97 redraw_man_t *rdman; | |
98 | |
46 | 99 mb_timeval_t start_time; |
41 | 100 int first_playing; /*!< first playing word. */ |
101 mb_tman_t *tman; | |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
102 subject_t *complete; /*!< notify when a program is completed. */ |
153
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
103 mb_timer_t *cur_timer; |
41 | 104 |
105 int n_words; | |
106 int max_words; | |
107 mb_word_t words[1]; | |
108 }; | |
109 | |
119 | 110 /*! \brief Create a program object. |
111 * | |
112 * \param max_words is maximum number of words the program can hold. | |
113 * \param rdman is a rdman that show graphics manipulated by it. | |
114 */ | |
41 | 115 mb_progm_t *mb_progm_new(int max_words, redraw_man_t *rdman) { |
116 mb_progm_t *progm; | |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
117 #ifndef UNITTEST |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
118 ob_factory_t *factory; |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
119 #endif /* UNITTEST */ |
41 | 120 int i; |
121 | |
122 progm = (mb_progm_t *)malloc(sizeof(mb_progm_t) + | |
123 (sizeof(mb_word_t) * (max_words - 1))); | |
124 if(progm == NULL) | |
125 return NULL; | |
126 | |
127 progm->rdman = rdman; | |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
128 |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
129 #ifndef UNITTEST |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
130 factory = rdman_get_ob_factory(rdman); |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
131 progm->complete = subject_new(factory, progm, OBJT_PROGM); |
194
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
132 if(progm->complete == NULL) { |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
133 free(progm); |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
134 return NULL; |
45d9a1e2764d
Add mb_subtree_free animate action and fix bugs.
Thinker K.F. Li <thinker@branda.to>
parents:
192
diff
changeset
|
135 } |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
136 #endif /* UNITTEST */ |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
137 |
41 | 138 progm->n_words = 0; |
139 progm->max_words = max_words; | |
140 for(i = 0; i < max_words; i++) | |
141 STAILQ_INIT(progm->words[i].actions); | |
142 return progm; | |
143 } | |
144 | |
145 void mb_progm_free(mb_progm_t *progm) { | |
146 int n_words; | |
147 mb_word_t *word; | |
148 mb_action_t *cur_act; | |
149 int i; | |
150 | |
151 n_words = progm->n_words; | |
152 for(i = 0; i < n_words; i++) { | |
153 word = progm->words + i; | |
154 for(cur_act = STAILQ_HEAD(word->actions); | |
155 cur_act != NULL; | |
156 cur_act = STAILQ_HEAD(word->actions)) { | |
157 STAILQ_REMOVE(word->actions, mb_action_t, next, cur_act); | |
158 cur_act->free(cur_act); | |
159 } | |
160 } | |
124
ad5ab8e61c2b
Free subject of complete when a program is freed
Thinker K.F. Li <thinker@branda.to>
parents:
123
diff
changeset
|
161 |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
162 #ifndef UNITTEST |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
163 subject_free(progm->complete); |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
164 #endif /* UNITTEST */ |
124
ad5ab8e61c2b
Free subject of complete when a program is freed
Thinker K.F. Li <thinker@branda.to>
parents:
123
diff
changeset
|
165 |
41 | 166 free(progm); |
167 } | |
168 | |
169 /*! \brief Add a new word into a program. | |
170 * | |
171 * The start time of new word should bigger or equal to last one. | |
172 * The time should be specified in incremental order. | |
173 */ | |
174 mb_word_t *mb_progm_next_word(mb_progm_t *progm, | |
175 const mb_timeval_t *start, | |
176 const mb_timeval_t *playing) { | |
177 mb_word_t *word; | |
178 if(progm->n_words >= progm->max_words) | |
179 return NULL; | |
180 if(progm->n_words && | |
181 MB_TIMEVAL_LATER(&progm->words[progm->n_words - 1].start_time, start)) | |
182 return NULL; | |
183 word = progm->words + progm->n_words++; | |
43
6270230b9248
Use MB_TIMEVAL_CP() instead of memcpy
Thinker K.F. Li <thinker@branda.to>
parents:
42
diff
changeset
|
184 MB_TIMEVAL_CP(&word->start_time, start); |
6270230b9248
Use MB_TIMEVAL_CP() instead of memcpy
Thinker K.F. Li <thinker@branda.to>
parents:
42
diff
changeset
|
185 MB_TIMEVAL_CP(&word->playing_time, playing); |
41 | 186 return word; |
187 } | |
188 | |
116
1d74eb3861b7
move animation actions from animate.c to files.
Thinker K.F. Li <thinker@branda.to>
parents:
111
diff
changeset
|
189 void mb_word_add_action(mb_word_t *word, mb_action_t *act) { |
41 | 190 STAILQ_INS_TAIL(word->actions, mb_action_t, next, act); |
191 } | |
192 | |
193 static void mb_word_start(mb_word_t *word, const mb_timeval_t *tmo, | |
194 const mb_timeval_t *now, redraw_man_t *rdman) { | |
42 | 195 mb_action_t *act; |
196 | |
197 for(act = STAILQ_HEAD(word->actions); | |
198 act != NULL; | |
199 act = STAILQ_NEXT(mb_action_t, next, act)) { | |
200 act->start(act, tmo, &word->playing_time, rdman); | |
201 } | |
41 | 202 } |
203 | |
204 static void mb_word_step(mb_word_t *word, const mb_timeval_t *tmo, | |
205 const mb_timeval_t *now, redraw_man_t *rdman) { | |
42 | 206 mb_action_t *act; |
207 | |
208 for(act = STAILQ_HEAD(word->actions); | |
209 act != NULL; | |
210 act = STAILQ_NEXT(mb_action_t, next, act)) { | |
211 act->step(act, tmo, rdman); | |
212 } | |
41 | 213 } |
214 | |
215 static void mb_word_stop(mb_word_t *word, const mb_timeval_t *tmo, | |
216 const mb_timeval_t *now, redraw_man_t *rdman) { | |
42 | 217 mb_action_t *act; |
218 | |
219 for(act = STAILQ_HEAD(word->actions); | |
220 act != NULL; | |
221 act = STAILQ_NEXT(mb_action_t, next, act)) { | |
222 act->stop(act, tmo, rdman); | |
223 } | |
41 | 224 } |
225 | |
122
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
226 /*! \brief Time stepping for a program. |
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
227 * |
46 | 228 * Any two actions in concurrent words never change the same attribute. |
229 * Start time of words in a program are specified in incremental order. | |
122
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
230 * |
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
231 * \note Program will take a big step at last monent. It is because |
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
232 * mb_progm_step() running mb_word_stop() if the word being stop |
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
233 * between now and next_tmo. It is not obviously if time stepping |
17e97e92b76e
Encapsulate X_MB_runtime_t and support X keyboard events.
Thinker K.F. Li <thinker@branda.to>
parents:
120
diff
changeset
|
234 * small. |
46 | 235 */ |
41 | 236 static void mb_progm_step(const mb_timeval_t *tmo, |
120 | 237 const mb_timeval_t *now, |
238 void *arg) { | |
41 | 239 mb_progm_t *progm = (mb_progm_t *)arg; |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
240 #ifndef UNITTEST |
129
ba581d8a4b9b
Now, tank1 can be controlled by user with keyboard
Thinker K.F. Li <thinker@branda.to>
parents:
128
diff
changeset
|
241 /*! \todo Leverage aspective programming to prevent problem of unittest. |
ba581d8a4b9b
Now, tank1 can be controlled by user with keyboard
Thinker K.F. Li <thinker@branda.to>
parents:
128
diff
changeset
|
242 */ |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
243 mb_progm_complete_t comp_evt; |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
244 #endif /* UNITTEST */ |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
245 mb_timeval_t next_tmo; |
41 | 246 mb_word_t *word; |
247 mb_timer_t *timer; | |
248 int i; | |
249 | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
250 MB_TIMEVAL_SET(&next_tmo, 0, STEP_INTERVAL); |
120 | 251 MB_TIMEVAL_ADD(&next_tmo, now); |
41 | 252 |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
253 /* _step() or _stop() words that in playing. */ |
41 | 254 i = progm->first_playing; |
255 for(word = progm->words + i; | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
256 i < progm->n_words && MB_TIMEVAL_LATER(tmo, &word->abs_start); |
41 | 257 word = progm->words + ++i) { |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
258 if(MB_TIMEVAL_LATER(tmo, &word->abs_stop)) |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
259 continue; |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
260 if(MB_TIMEVAL_LATER(&next_tmo, &word->abs_stop)) |
46 | 261 mb_word_stop(word, tmo, now, progm->rdman); |
262 else | |
41 | 263 mb_word_step(word, tmo, now, progm->rdman); |
264 } | |
265 | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
266 /* Start words that their abs_start is in duration |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
267 * from now to timeout for next update. |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
268 */ |
41 | 269 for(word = progm->words + i; |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
270 i < progm->n_words && MB_TIMEVAL_LATER(&next_tmo, &word->abs_start); |
41 | 271 word = progm->words + ++i) { |
272 mb_word_start(word, tmo, now, progm->rdman); | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
273 if(MB_TIMEVAL_LATER(&next_tmo, &word->abs_stop)) |
46 | 274 mb_word_stop(word, tmo, now, progm->rdman); |
41 | 275 } |
276 | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
277 /* Find a new first_playing if any consequence words, following current |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
278 * first_playing word, are stoped. |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
279 */ |
46 | 280 i = progm->first_playing; |
281 for(word = progm->words + i; | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
282 i < progm->n_words && MB_TIMEVAL_LATER(&next_tmo, &word->abs_stop); |
46 | 283 word = progm->words + ++i) { |
284 progm->first_playing++; | |
285 } | |
286 | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
287 /* Setup timeout for next update. */ |
41 | 288 if(progm->first_playing < progm->n_words) { |
42 | 289 word = progm->words + progm->first_playing; |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
290 if(MB_TIMEVAL_LATER(&word->abs_start, &next_tmo)) |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
291 MB_TIMEVAL_CP(&next_tmo, &word->abs_start); |
46 | 292 timer = mb_tman_timeout(progm->tman, &next_tmo, |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
293 mb_progm_step, progm); |
155
6749f6639924
Fix bug for STAILQ that fail to remove a node.
Thinker K.F. Li <thinker@branda.to>
parents:
153
diff
changeset
|
294 progm->cur_timer = timer; |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
295 } else { |
153
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
296 /* Make program to complete. */ |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
297 #ifndef UNITTEST |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
298 comp_evt.event.type = EVT_PROGM_COMPLETE; |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
299 comp_evt.event.tgt = comp_evt.event.cur_tgt = progm->complete; |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
300 comp_evt.progm = progm; |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
301 subject_notify(progm->complete, &comp_evt.event); |
128
07dc9ec71221
Fix the problem that animate.c can not pass testcases
Thinker K.F. Li <thinker@branda.to>
parents:
124
diff
changeset
|
302 #endif /* UNITTEST */ |
153
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
303 progm->cur_timer = NULL; |
41 | 304 } |
305 } | |
306 | |
307 void mb_progm_start(mb_progm_t *progm, mb_tman_t *tman, | |
308 mb_timeval_t *now) { | |
309 mb_timer_t *timer; | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
310 mb_word_t *word; |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
311 int i; |
41 | 312 |
313 if(progm->n_words == 0) | |
314 return; | |
315 | |
316 progm->tman = tman; | |
43
6270230b9248
Use MB_TIMEVAL_CP() instead of memcpy
Thinker K.F. Li <thinker@branda.to>
parents:
42
diff
changeset
|
317 MB_TIMEVAL_CP(&progm->start_time, now); |
41 | 318 progm->first_playing = 0; |
319 | |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
320 for(i = 0; i < progm->n_words; i++) { |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
321 word = progm->words + i; |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
322 MB_TIMEVAL_CP(&word->abs_start, &word->start_time); |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
323 MB_TIMEVAL_ADD(&word->abs_start, now); |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
324 MB_TIMEVAL_CP(&word->abs_stop, &word->abs_start); |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
325 MB_TIMEVAL_ADD(&word->abs_stop, &word->playing_time); |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
326 } |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
327 |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
328 if(MB_TIMEVAL_EQ(&progm->words[0].abs_start, now)) { |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
329 mb_progm_step(now, now, progm); |
41 | 330 return; |
331 } | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
332 |
48
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
333 timer = mb_tman_timeout(tman, &progm->words[0].abs_start, |
bdf711cbf0fb
Use absolute time to dispatch animation actions.
Thinker K.F. Li <thinker@branda.to>
parents:
47
diff
changeset
|
334 mb_progm_step, progm); |
41 | 335 ASSERT(timer != NULL); |
153
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
336 |
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
337 /* We need timer to abort it. */ |
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
338 progm->cur_timer = timer; |
41 | 339 } |
340 | |
332
f90c60967a9c
Add mb_progm_finish to terminate the current animation and put all objects in the final position.
wycc
parents:
194
diff
changeset
|
341 void mb_progm_finish(mb_progm_t *progm) { |
f90c60967a9c
Add mb_progm_finish to terminate the current animation and put all objects in the final position.
wycc
parents:
194
diff
changeset
|
342 mb_timeval_t infi; |
f90c60967a9c
Add mb_progm_finish to terminate the current animation and put all objects in the final position.
wycc
parents:
194
diff
changeset
|
343 |
f90c60967a9c
Add mb_progm_finish to terminate the current animation and put all objects in the final position.
wycc
parents:
194
diff
changeset
|
344 mb_progm_abort(progm); |
f90c60967a9c
Add mb_progm_finish to terminate the current animation and put all objects in the final position.
wycc
parents:
194
diff
changeset
|
345 MB_TIMEVAL_SET(&infi, 0x7fffffff,0); |
f90c60967a9c
Add mb_progm_finish to terminate the current animation and put all objects in the final position.
wycc
parents:
194
diff
changeset
|
346 mb_progm_step(&progm->start_time, &infi,progm); |
f90c60967a9c
Add mb_progm_finish to terminate the current animation and put all objects in the final position.
wycc
parents:
194
diff
changeset
|
347 } |
153
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
348 void mb_progm_abort(mb_progm_t *progm) { |
131
6a8588df68af
Tank can change direction and navigate on the mud area
Thinker K.F. Li <thinker@branda.to>
parents:
129
diff
changeset
|
349 /*! \todo Make sure abort release resources. */ |
153
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
350 if(progm->cur_timer) { |
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
351 mb_tman_remove(progm->tman, progm->cur_timer); |
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
352 progm->cur_timer = NULL; |
9870b049b7f6
Make mb_progm_abort() work.
Thinker K.F. Li <thinker@branda.to>
parents:
131
diff
changeset
|
353 } |
42 | 354 } |
355 | |
123
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
356 /*! \brief Return event subject for completion of a program. |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
357 */ |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
358 subject_t *mb_progm_get_complete(mb_progm_t *progm) { |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
359 return progm->complete; |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
360 } |
9e2316dc6ecb
Program completion events
Thinker K.F. Li <thinker@branda.to>
parents:
122
diff
changeset
|
361 |
192
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
362 static void _free_completed_hdlr(event_t *event, void *arg) { |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
363 mb_progm_t *progm = (mb_progm_t *)arg; |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
364 |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
365 mb_progm_free(progm); |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
366 } |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
367 |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
368 /*! \brief The program should be freed after completed. */ |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
369 void mb_progm_free_completed(mb_progm_t *progm) { |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
370 subject_t *complete; |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
371 |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
372 complete = mb_progm_get_complete(progm); |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
373 subject_add_observer(complete, _free_completed_hdlr, progm); |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
374 } |
54fdc2a65242
Remove factory from observer APIs.
Thinker K.F. Li <thinker@branda.to>
parents:
186
diff
changeset
|
375 |
50 | 376 #ifdef UNITTEST |
377 | |
378 #include <CUnit/Basic.h> | |
379 | |
380 typedef struct _mb_dummy mb_dummy_t; | |
381 | |
382 struct _mb_dummy { | |
383 mb_action_t action; | |
384 int id; | |
385 int *logidx; | |
386 int *logs; | |
387 }; | |
388 | |
389 | |
390 static void mb_dummy_start(mb_action_t *act, | |
391 const mb_timeval_t *now, | |
392 const mb_timeval_t *playing_time, | |
393 redraw_man_t *rdman) { | |
394 mb_dummy_t *dummy = (mb_dummy_t *)act; | |
395 | |
396 dummy->logs[(*dummy->logidx)++] = dummy->id; | |
397 } | |
398 | |
399 static void mb_dummy_step(mb_action_t *act, | |
400 const mb_timeval_t *now, | |
401 redraw_man_t *rdman) { | |
402 mb_dummy_t *dummy = (mb_dummy_t *)act; | |
403 | |
404 dummy->logs[(*dummy->logidx)++] = dummy->id; | |
405 } | |
406 | |
407 static void mb_dummy_stop(mb_action_t *act, | |
408 const mb_timeval_t *now, | |
409 redraw_man_t *rdman) { | |
410 mb_dummy_t *dummy = (mb_dummy_t *)act; | |
411 | |
412 dummy->logs[(*dummy->logidx)++] = dummy->id; | |
413 } | |
414 | |
415 static void mb_dummy_free(mb_action_t *act) { | |
416 free(act); | |
417 } | |
418 | |
419 mb_action_t *mb_dummy_new(int id, int *logidx, int *logs, mb_word_t *word) { | |
420 mb_dummy_t *dummy; | |
421 | |
422 dummy = (mb_dummy_t *)malloc(sizeof(mb_dummy_t)); | |
423 if(dummy == NULL) | |
424 return NULL; | |
425 | |
426 dummy->id = id; | |
427 dummy->logidx = logidx; | |
428 dummy->logs = logs; | |
429 | |
430 dummy->action.start = mb_dummy_start; | |
431 dummy->action.step = mb_dummy_step; | |
432 dummy->action.stop = mb_dummy_stop; | |
433 dummy->action.free = mb_dummy_free; | |
434 | |
435 mb_word_add_action(word, (mb_action_t *)dummy); | |
436 | |
437 return (mb_action_t *)dummy; | |
438 } | |
439 | |
440 void test_animate_words(void) { | |
441 mb_progm_t *progm; | |
442 mb_word_t *word; | |
443 mb_action_t *acts[4]; | |
444 mb_tman_t *tman; | |
445 mb_timeval_t tv1, tv2, now, tmo_after; | |
446 int logcnt = 0; | |
447 int logs[256]; | |
448 int r; | |
449 | |
450 tman = mb_tman_new(); | |
451 CU_ASSERT(tman != NULL); | |
452 | |
453 progm = mb_progm_new(3, NULL); | |
454 CU_ASSERT(progm != NULL); | |
455 | |
456 MB_TIMEVAL_SET(&tv1, 1, 0); | |
457 MB_TIMEVAL_SET(&tv2, 0, STEP_INTERVAL * 3); | |
458 word = mb_progm_next_word(progm, &tv1, &tv2); | |
459 CU_ASSERT(word != NULL); | |
460 acts[0] = mb_dummy_new(0, &logcnt, logs, word); | |
461 CU_ASSERT(acts[0] != NULL); | |
462 | |
463 MB_TIMEVAL_SET(&tv1, 1, STEP_INTERVAL * 4 / 3); | |
464 MB_TIMEVAL_SET(&tv2, 0, STEP_INTERVAL / 3); | |
465 word = mb_progm_next_word(progm, &tv1, &tv2); | |
466 CU_ASSERT(word != NULL); | |
467 acts[1] = mb_dummy_new(1, &logcnt, logs, word); | |
468 CU_ASSERT(acts[1] != NULL); | |
469 | |
470 MB_TIMEVAL_SET(&tv1, 1, STEP_INTERVAL * 2); | |
471 MB_TIMEVAL_SET(&tv2, 0, STEP_INTERVAL * 3); | |
472 word = mb_progm_next_word(progm, &tv1, &tv2); | |
473 CU_ASSERT(word != NULL); | |
474 acts[2] = mb_dummy_new(2, &logcnt, logs, word); | |
475 CU_ASSERT(acts[2] != NULL); | |
476 | |
477 MB_TIMEVAL_SET(&now, 0, 0); | |
478 mb_progm_start(progm, tman, &now); | |
479 | |
480 r = mb_tman_next_timeout(tman, &now, &tmo_after); | |
481 CU_ASSERT(r == 0); | |
482 CU_ASSERT(MB_TIMEVAL_SEC(&tmo_after) == 1 && | |
483 MB_TIMEVAL_USEC(&tmo_after) == 0); | |
484 | |
485 /* 1.0s */ | |
486 MB_TIMEVAL_ADD(&now, &tmo_after); | |
487 mb_tman_handle_timeout(tman, &now); | |
488 CU_ASSERT(logcnt == 1); | |
489 | |
490 r = mb_tman_next_timeout(tman, &now, &tmo_after); | |
491 CU_ASSERT(r == 0); | |
492 CU_ASSERT(MB_TIMEVAL_SEC(&tmo_after) == 0 && | |
493 MB_TIMEVAL_USEC(&tmo_after) == STEP_INTERVAL); | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
494 |
50 | 495 /* 1.1s */ |
496 MB_TIMEVAL_ADD(&now, &tmo_after); | |
497 mb_tman_handle_timeout(tman, &now); | |
498 CU_ASSERT(logcnt == 4); | |
499 | |
500 r = mb_tman_next_timeout(tman, &now, &tmo_after); | |
501 CU_ASSERT(r == 0); | |
502 CU_ASSERT(MB_TIMEVAL_SEC(&tmo_after) == 0 && | |
503 MB_TIMEVAL_USEC(&tmo_after) == STEP_INTERVAL); | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
504 |
50 | 505 /* 1.2s */ |
506 MB_TIMEVAL_ADD(&now, &tmo_after); | |
507 mb_tman_handle_timeout(tman, &now); | |
508 CU_ASSERT(logcnt == 6); | |
509 | |
510 r = mb_tman_next_timeout(tman, &now, &tmo_after); | |
511 CU_ASSERT(r == 0); | |
512 CU_ASSERT(MB_TIMEVAL_SEC(&tmo_after) == 0 && | |
513 MB_TIMEVAL_USEC(&tmo_after) == STEP_INTERVAL); | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
514 |
50 | 515 /* 1.3s */ |
516 MB_TIMEVAL_ADD(&now, &tmo_after); | |
517 mb_tman_handle_timeout(tman, &now); | |
518 CU_ASSERT(logcnt == 8); | |
519 | |
520 r = mb_tman_next_timeout(tman, &now, &tmo_after); | |
521 CU_ASSERT(r == 0); | |
522 CU_ASSERT(MB_TIMEVAL_SEC(&tmo_after) == 0 && | |
523 MB_TIMEVAL_USEC(&tmo_after) == STEP_INTERVAL); | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
524 |
50 | 525 /* 1.4s */ |
526 MB_TIMEVAL_ADD(&now, &tmo_after); | |
527 mb_tman_handle_timeout(tman, &now); | |
528 CU_ASSERT(logcnt == 9); | |
529 | |
530 r = mb_tman_next_timeout(tman, &now, &tmo_after); | |
531 CU_ASSERT(r == 0); | |
532 CU_ASSERT(MB_TIMEVAL_SEC(&tmo_after) == 0 && | |
533 MB_TIMEVAL_USEC(&tmo_after) == STEP_INTERVAL); | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
534 |
50 | 535 /* 1.5s */ |
536 MB_TIMEVAL_ADD(&now, &tmo_after); | |
537 mb_tman_handle_timeout(tman, &now); | |
538 CU_ASSERT(logcnt == 10); | |
539 | |
540 r = mb_tman_next_timeout(tman, &now, &tmo_after); | |
541 CU_ASSERT(r == -1); | |
542 | |
543 mb_progm_free(progm); | |
544 mb_tman_free(tman); | |
545 } | |
546 | |
547 CU_pSuite get_animate_suite(void) { | |
548 CU_pSuite suite; | |
549 | |
550 suite = CU_add_suite("Suite_animate", NULL, NULL); | |
551 if(suite == NULL) | |
552 return NULL; | |
553 | |
554 CU_ADD_TEST(suite, test_animate_words); | |
822
586e50f82c1f
Unify coding style tag for emacs and vim.
Shih-Yuan Lee (FourDollars) <fourdollars@gmail.com>
parents:
332
diff
changeset
|
555 |
50 | 556 return suite; |
557 } | |
558 | |
559 #endif /* UNITTEST */ |