Mercurial > MadButterfly
comparison src/redraw_man.c @ 13:ed55009d96d3
refactory for redrawing
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Thu, 31 Jul 2008 08:10:00 +0800 |
parents | 79e9edf4c00a |
children | d34232f15863 |
comparison
equal
deleted
inserted
replaced
12:79e9edf4c00a | 13:ed55009d96d3 |
---|---|
7 #include "redraw_man.h" | 7 #include "redraw_man.h" |
8 | 8 |
9 #define OK 0 | 9 #define OK 0 |
10 #define ERR -1 | 10 #define ERR -1 |
11 | 11 |
12 #define OFFSET(type, field) ((void *)&((type *)NULL)->field - (void *)NULL) | |
13 #define SWAP(a, b, t) do { t c; c = a; a = b; b = c; } while(0) | |
14 | |
12 int redraw_man_init(redraw_man_t *rdman) { | 15 int redraw_man_init(redraw_man_t *rdman) { |
13 extern void redraw_man_destroy(redraw_man_t *rdman); | 16 extern void redraw_man_destroy(redraw_man_t *rdman); |
14 | 17 |
15 memset(rdman, 0, sizeof(redraw_man_t)); | 18 memset(rdman, 0, sizeof(redraw_man_t)); |
16 | 19 |
25 } | 28 } |
26 | 29 |
27 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); | 30 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); |
28 if(rdman->root_coord == NULL) | 31 if(rdman->root_coord == NULL) |
29 redraw_man_destroy(rdman); | 32 redraw_man_destroy(rdman); |
30 | 33 rdman->n_coords = 1; |
31 coord_init(rdman->root_coord, NULL); | 34 coord_init(rdman->root_coord, NULL); |
32 | 35 |
33 return OK; | 36 return OK; |
34 } | 37 } |
35 | 38 |
36 void redraw_man_destroy(redraw_man_t *rdman) { | 39 void redraw_man_destroy(redraw_man_t *rdman) { |
37 elmpool_free(rdman->coord_pool); | 40 elmpool_free(rdman->coord_pool); |
38 elmpool_free(rdman->geo_pool); | 41 elmpool_free(rdman->geo_pool); |
42 if(rdman->dirty_coords) | |
43 free(rdman->dirty_coords); | |
44 if(rdman->redrawing_geos) | |
45 free(rdman->redrawing_geos); | |
39 } | 46 } |
40 | 47 |
41 | 48 |
42 #define ASSERT(x) | 49 #define ASSERT(x) |
43 /* | 50 /* |
104 return n_overlays; | 111 return n_overlays; |
105 } | 112 } |
106 | 113 |
107 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) { | 114 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) { |
108 geo_t *geo; | 115 geo_t *geo; |
116 geo_t *visit; | |
117 unsigned int next_order; | |
109 | 118 |
110 geo = elmpool_elm_alloc(rdman->geo_pool); | 119 geo = elmpool_elm_alloc(rdman->geo_pool); |
111 if(geo == NULL) | 120 if(geo == NULL) |
112 return ERR; | 121 return ERR; |
113 sh_attach_geo(shape, geo); | 122 sh_attach_geo(shape, geo); |
114 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); | 123 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); |
115 rdman->n_geos++; | 124 rdman->n_geos++; |
125 | |
126 geo->order = ++rdman->next_geo_order; | |
127 if(geo->order == 0) { | |
128 next_order = 0; | |
129 for(visit = STAILQ_HEAD(rdman->all_geos); | |
130 visit != NULL; | |
131 visit = STAILQ_NEXT(geo_t, next, visit)) | |
132 visit->order = ++next_order; | |
133 rdman->next_geo_order = next_order; | |
134 } | |
135 | |
116 sh_attach_coord(shape, coord); | 136 sh_attach_coord(shape, coord); |
117 | 137 |
118 return OK; | 138 return OK; |
119 } | 139 } |
120 | 140 |
126 sh_detach_coord(shape); | 146 sh_detach_coord(shape); |
127 return OK; | 147 return OK; |
128 } | 148 } |
129 | 149 |
130 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { | 150 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { |
131 coord_t *coord; | 151 coord_t *coord, *root_coord; |
152 coord_t *visit; | |
132 | 153 |
133 coord = elmpool_elm_alloc(rdman->coord_pool); | 154 coord = elmpool_elm_alloc(rdman->coord_pool); |
134 if(coord == NULL) | 155 if(coord == NULL) |
135 return NULL; | 156 return NULL; |
136 | 157 |
137 coord_init(coord, parent); | 158 coord_init(coord, parent); |
159 rdman->n_coords++; | |
160 | |
161 coord->order = ++rdman->next_coord_order; | |
162 if(coord->order == 0) { | |
163 rdman->next_coord_order = 0; | |
164 root_coord = visit = rdman->root_coord; | |
165 /* skip root coord. */ | |
166 visit = preorder_coord_subtree(root_coord, visit); | |
167 while(visit) { | |
168 visit->order = ++rdman->next_coord_order; | |
169 visit = preorder_coord_subtree(root_coord, visit); | |
170 } | |
171 } | |
138 | 172 |
139 return coord; | 173 return coord; |
140 } | 174 } |
141 | 175 |
142 /*! \brief Free a coord of a redraw_man_t object. | 176 /*! \brief Free a coord of a redraw_man_t object. |
157 if(STAILQ_HEAD(coord->children) != NULL) | 191 if(STAILQ_HEAD(coord->children) != NULL) |
158 return ERR; | 192 return ERR; |
159 | 193 |
160 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); | 194 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); |
161 elmpool_elm_free(rdman->coord_pool, coord); | 195 elmpool_elm_free(rdman->coord_pool, coord); |
162 | 196 rdman->n_coords--; |
163 return OK; | 197 |
164 } | 198 return OK; |
165 | 199 } |
166 void rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { | 200 |
201 static int extend_memblk(void **buf, int o_size, int n_size) { | |
202 void *new_buf; | |
203 | |
204 new_buf = realloc(*buf, n_size); | |
205 if(new_buf == NULL) | |
206 return ERR; | |
207 | |
208 if(new_buf != *buf) { | |
209 memcpy(new_buf, *buf, o_size); | |
210 free(*buf); | |
211 *buf = new_buf; | |
212 } | |
213 | |
214 return OK; | |
215 } | |
216 | |
217 static int add_dirty_geo(redraw_man_t *rdman, geo_t *geo) { | |
218 int max_redrawing_geos; | |
219 int r; | |
220 | |
221 if(rdman->n_redrawing_geos >= rdman->max_redrawing_geos) { | |
222 max_redrawing_geos = rdman->n_geos + rdman->n_coords; | |
223 r = extend_memblk((void **)&rdman->redrawing_geos, | |
224 sizeof(geo_t *) * rdman->n_redrawing_geos, | |
225 sizeof(geo_t *) * max_redrawing_geos); | |
226 if(r != OK) | |
227 return ERR; | |
228 rdman->max_redrawing_geos = max_redrawing_geos; | |
229 } | |
230 | |
231 rdman->redrawing_geos[rdman->n_redrawing_geos++] = geo; | |
232 return OK; | |
233 } | |
234 | |
235 static int add_dirty_area(redraw_man_t *rdman, area_t *area) { | |
236 int max_dirty_areas; | |
237 int r; | |
238 | |
239 if(rdman->n_dirty_areas >= rdman->max_dirty_areas) { | |
240 max_dirty_areas = (rdman->n_geos + rdman->n_coords) * 2; | |
241 r = extend_memblk((void **)&rdman->dirty_areas, | |
242 sizeof(area_t *) * rdman->n_dirty_areas, | |
243 sizeof(area_t *) * max_dirty_areas); | |
244 if(r != OK) | |
245 return ERR; | |
246 rdman->max_dirty_areas = max_dirty_areas; | |
247 } | |
248 | |
249 rdman->dirty_areas[++rdman->n_dirty_areas] = area; | |
250 return OK; | |
251 } | |
252 | |
253 /*! \brief Mark a coord is changed. | |
254 * | |
255 * A changed coord_t object is marked as dirty and put | |
256 * into dirty_coords list. | |
257 */ | |
258 int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { | |
259 int max_dirty_coords; | |
260 int r; | |
261 | |
262 if(coord->flags & COF_DIRTY) | |
263 return OK; | |
264 | |
265 if(rdman->n_dirty_coords >= rdman->max_dirty_coords) { | |
266 /* Max of dirty_coords is not big enough. */ | |
267 max_dirty_coords = rdman->max_dirty_coords + 16; | |
268 | |
269 r = extend_memblk((void **)&rdman->dirty_coords, | |
270 sizeof(coord_t *) * rdman->n_dirty_coords, | |
271 sizeof(coord_t *) * max_dirty_coords); | |
272 rdman->max_dirty_coords = max_dirty_coords; | |
273 } | |
274 | |
275 rdman->dirty_coords[rdman->n_dirty_coords++] = coord; | |
276 coord->flags |= COF_DIRTY; | |
277 | |
278 return OK; | |
279 } | |
280 | |
281 /*! \brief Mark a shape is changed. | |
282 * | |
283 * The geo_t object of a changed shape is mark as dirty and | |
284 * put into redrawing_geos list. | |
285 */ | |
286 int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) { | |
287 geo_t *geo; | |
288 int r; | |
289 | |
290 geo = shape->geo; | |
291 | |
292 if(geo->flags & GEF_DIRTY) | |
293 return OK; | |
294 | |
295 r = add_dirty_geo(rdman, geo); | |
296 if(r == ERR) | |
297 return ERR; | |
298 geo->flags |= GEF_DIRTY; | |
299 | |
300 return OK; | |
301 } | |
302 | |
303 /*! \brief Sort a list of element by a unsigned integer. | |
304 * | |
305 * The result is in ascend order. The unsigned integers is | |
306 * at offset specified by 'off' from start address of elemnts. | |
307 */ | |
308 static void _insert_sort(void **elms, int num, int off) { | |
309 int i, j; | |
310 unsigned int val; | |
311 | |
312 for(i = 1; i < num; i++) { | |
313 val = *(unsigned int *)(elms[i] + off); | |
314 for(j = i; j > 0; j--) { | |
315 if(*(unsigned int *)(elms[j - 1] + off) <= val) | |
316 break; | |
317 elms[j] = elms[j - 1]; | |
318 } | |
319 elms[j] = elms[i]; | |
320 } | |
321 } | |
322 | |
323 static void make_redrawing_members(redraw_man_t *rdman, coord_t *coord) { | |
324 shape_t *shape; | |
325 | |
326 for(shape = STAILQ_HEAD(coord->members); | |
327 shape != NULL; | |
328 shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) { | |
329 shape->geo->flags &= ~GEF_DIRTY; | |
330 add_dirty_geo(rdman, shape->geo); | |
331 } | |
332 } | |
333 | |
334 static void compute_coord_geo(coord_t *coord) { | |
335 } | |
336 | |
337 static void transform_shape(shape_t *shape) { | |
338 } | |
339 | |
340 static void draw_shape(shape_t *shape) { | |
341 } | |
342 | |
343 /*! \brief Re-draw all changed shapes or shapes affected by changed coords. | |
344 * | |
345 * A coord object has a geo to keep track the range that it's members will | |
346 * draw on. Geo of a coord should be recomputed when the coord is changed. | |
347 * Geo of a coord used to accelerate finding overlay shape objects of | |
348 * a specified geo. A coord object also must be recomputed when one of | |
349 * it's members is changed. | |
350 * | |
351 * New and old geo values of a coord object that is recomputed for | |
352 * changing of it-self must be used to find overlay shape objects. | |
353 * New and old geo values of a shape should also be used to find | |
354 * overlay shape objects, too. If a shape's coord is changed, shape's | |
355 * geo object is not used to find overlay shape objects any more. | |
356 * | |
357 * steps: | |
358 * - update chagned coord objects | |
359 * - recompute geo for changed coord objects | |
360 * - recompute geo for members shape objects | |
361 * - recompute geo for changed shape objects | |
362 * - finding overlaid shape objects for recomputed geo objects. | |
363 * - overlaid shape objects is invoked by traveling tree of coord. | |
364 * - members of changed coord object are marked computed and dirty. | |
365 * | |
366 * assert(n_redrawing_geos <= (num_of(shape) + num_of(coord))) | |
367 * Because | |
368 * - num_of(geo from coord) < num_of(coord) | |
369 * - num_of(geo from shape) < num_of(shape) | |
370 */ | |
371 int rdman_redraw_changed(redraw_man_t *rdman) { | |
372 int i, j; | |
373 int n_dirty_coords; | |
374 coord_t **dirty_coords; | |
375 coord_t *visit_coord; | |
376 geo_t *visit_geo, **redrawing_geos; | |
377 int n_redrawing_geos; | |
378 int n_dirty_areas; | |
379 | |
380 if(rdman->n_dirty_coords > 0) { | |
381 _insert_sort((void **)rdman->dirty_coords, | |
382 rdman->n_dirty_coords, | |
383 OFFSET(coord_t, order)); | |
384 n_dirty_coords = rdman->n_dirty_coords; | |
385 dirty_coords = rdman->dirty_coords; | |
386 for(i = 0; i < n_dirty_coords; i++) { | |
387 if(!(dirty_coords[i]->flags & COF_DIRTY)) | |
388 continue; | |
389 | |
390 update_aggr_matrix(dirty_coords[i]); | |
391 for(visit_coord = dirty_coords[i]; | |
392 visit_coord != NULL; | |
393 visit_coord = preorder_coord_subtree(dirty_coords[i], | |
394 visit_coord)) { | |
395 /* Dirty member, here, and members of this coord | |
396 * will not be visited anymore. */ | |
397 visit_coord->flags &= ~COF_DIRTY; | |
398 visit_coord->flags |= COF_RECOMP; | |
399 | |
400 SWAP(visit_coord->cur_area, visit_coord->last_area, area_t *); | |
401 compute_coord_geo(visit_coord); | |
402 add_dirty_area(rdman, visit_coord->cur_area); | |
403 add_dirty_area(rdman, visit_coord->last_area); | |
404 make_redrawing_members(rdman, visit_coord); | |
405 } | |
406 } | |
407 rdman->n_dirty_coords = 0; | |
408 } | |
409 | |
410 n_redrawing_geos = rdman->n_redrawing_geos; | |
411 if(n_redrawing_geos > 0) { | |
412 redrawing_geos = rdman->redrawing_geos; | |
413 for(i = 0; i < n_redrawing_geos; i++) { | |
414 visit_geo = redrawing_geos[i]; | |
415 if(!(visit_geo->flags & GEF_DIRTY)) | |
416 continue; | |
417 | |
418 SWAP(visit_geo->cur_area, visit_geo->last_area, area_t *); | |
419 transform_shape(visit_geo->shape); | |
420 visit_geo->flags &= ~GEF_DIRTY; | |
421 add_dirty_area(rdman, visit_geo->cur_area); | |
422 add_dirty_area(rdman, visit_geo->last_area); | |
423 } | |
424 | |
425 n_dirty_areas = rdman->n_dirty_areas; | |
426 for(visit_geo = STAILQ_HEAD(rdman->all_geos); | |
427 visit_geo != NULL; | |
428 visit_geo = STAILQ_NEXT(geo_t, next, visit_geo)) { | |
429 if(visit_geo->flags & GEF_DIRTY) | |
430 continue; | |
431 | |
432 } | |
433 } | |
434 | |
435 return OK; | |
167 } | 436 } |
168 | 437 |
169 /* | 438 /* |
170 * When redraw an area, the affected elements may also extend to | 439 * When redraw an area, the affected elements may also extend to |
171 * outside of the area. Since the order of drawing will change | 440 * outside of the area. Since the order of drawing will change |
185 * It can get intereset of higher hit rate of cache. | 454 * It can get intereset of higher hit rate of cache. |
186 * - shapes prvoide list of positions needed to be transformed. | 455 * - shapes prvoide list of positions needed to be transformed. |
187 * - redraw_man transforms positions from shapes. | 456 * - redraw_man transforms positions from shapes. |
188 * - shapes drawing with result of transforms. | 457 * - shapes drawing with result of transforms. |
189 * - shapes should be called to give them a chance to update geometries. | 458 * - shapes should be called to give them a chance to update geometries. |
459 */ | |
460 | |
461 /* | |
462 * functions: | |
463 * - redraw all | |
464 * - redraw changed | |
190 */ | 465 */ |
191 | 466 |
192 #ifdef UNITTEST | 467 #ifdef UNITTEST |
193 | 468 |
194 #include <CUnit/Basic.h> | 469 #include <CUnit/Basic.h> |
245 redraw_man_t rdman; | 520 redraw_man_t rdman; |
246 geo_t geo; | 521 geo_t geo; |
247 coord_t *coords[3]; | 522 coord_t *coords[3]; |
248 shape_t *shapes[5]; | 523 shape_t *shapes[5]; |
249 geo_t **overlays; | 524 geo_t **overlays; |
525 co_aix pos[2][2]; | |
250 int n; | 526 int n; |
251 int i; | 527 int i; |
252 | 528 |
253 redraw_man_init(&rdman); | 529 redraw_man_init(&rdman); |
254 coords[0] = rdman.root_coord; | 530 coords[0] = rdman.root_coord; |
269 | 545 |
270 update_aggr_matrix(coords[0]); | 546 update_aggr_matrix(coords[0]); |
271 for(i = 0; i < 5; i++) | 547 for(i = 0; i < 5; i++) |
272 sh_dummy_transform(shapes[i]); | 548 sh_dummy_transform(shapes[i]); |
273 | 549 |
274 geo.x = 100; | 550 pos[0][0] = 100; |
275 geo.y = 120; | 551 pos[0][1] = 120; |
276 geo.w = 140; | 552 pos[1][0] = 100 + 140; |
277 geo.h = 40; | 553 pos[1][1] = 120 + 40; |
554 geo_init(&geo, 2, pos); | |
278 | 555 |
279 n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays); | 556 n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays); |
280 CU_ASSERT(n == 2); | 557 CU_ASSERT(n == 2); |
281 CU_ASSERT(overlays != NULL); | 558 CU_ASSERT(overlays != NULL); |
282 CU_ASSERT(overlays[0] == shapes[2]->geo); | 559 CU_ASSERT(overlays[0] == shapes[2]->geo); |