Mercurial > MadButterfly
diff src/redraw_man.c @ 159:b90abd31a281
Postponse free of coords, shapes, and paints when the rdman is dirty.
- Life-cycle of shapes and paints are managed by rdman.
- Add redraw_man_t::free_objs to collect objects their freeing are
postonsed.
Know Issue:
- Bullet of tank are not removed from screen when it is go out the range
of the map.
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Sun, 05 Oct 2008 23:32:58 +0800 |
parents | c1cdd3fcd28f |
children | 147c93163ef0 |
line wrap: on
line diff
--- a/src/redraw_man.c Fri Oct 03 10:22:08 2008 +0800 +++ b/src/redraw_man.c Sun Oct 05 23:32:58 2008 +0800 @@ -74,6 +74,16 @@ STAILQ_REMOVE((coord)->members, geo_t, coord_next, (member)) #define FIRST_MEMBER(coord) STAILQ_HEAD((coord)->members) +/* Functions for paint members. */ +#define FORPAINTMEMBERS(paint, member) \ + for((member) = STAILQ_HEAD((paint)->members); \ + (member) != NULL; \ + (member) = STAILQ_NEXT(paint_t, next, member)) +#define RM_PAINTMEMBER(paint, member) \ + STAILQ_REMOVE((paint)->members, shnode_t, next, member) +#define RM_PAINT(rdman, paint) \ + STAILQ_REMOVE((rdman)->paints, paint_t, pnt_next, paint) + /*! \brief Sort a list of element by a unsigned integer. * * The result is in ascend order. The unsigned integers is @@ -122,12 +132,42 @@ ADD_DATA(areas, dirty_areas, area); } -static int add_free_coord(redraw_man_t *rdman, coord_t *coord) { - ADD_DATA(coords, free_coords, coord); +static int add_free_obj(redraw_man_t *rdman, void *obj, + free_func_t free_func) { + int max; + free_obj_t *new_objs, *free_obj; + + if(rdman->free_objs.num >= rdman->free_objs.max) { + max = rdman->free_objs.num + ARRAY_EXT_SZ; + new_objs = realloc(rdman->free_objs.objs, + max * sizeof(free_obj_t)); + if(new_objs == NULL) + return ERR; + rdman->free_objs.max = max; + rdman->free_objs.objs = new_objs; + } + + free_obj = rdman->free_objs.objs + rdman->free_objs.num++; + free_obj->obj = obj; + free_obj->free_func = free_func; + + return OK; } -static int add_free_geo(redraw_man_t *rdman, geo_t *geo) { - ADD_DATA(geos, free_geos, geo); +static void free_free_objs(redraw_man_t *rdman) { + int i; + free_obj_t *free_obj; + + for(i = 0; i < rdman->free_objs.num; i++) { + free_obj = &rdman->free_objs.objs[i]; + free_obj->free_func(rdman, free_obj->obj); + } + rdman->free_objs.num = 0; +} + +static void free_objs_destroy(redraw_man_t *rdman) { + if(rdman->free_objs.objs != NULL) + free(rdman->free_objs.objs); } static void area_to_positions(area_t *area, co_aix (*poses)[2]) { @@ -269,29 +309,47 @@ rdman->cr = cr; rdman->backend = backend; + STAILQ_INIT(rdman->shapes); + STAILQ_INIT(rdman->paints); + return OK; } void redraw_man_destroy(redraw_man_t *rdman) { coord_t *coord, *saved_coord; + shape_t *shape, *saved_shape; geo_t *member; + free_free_objs(rdman); + free_objs_destroy(rdman); + coord = postorder_coord_subtree(rdman->root_coord, NULL); while(coord) { saved_coord = coord; coord = postorder_coord_subtree(rdman->root_coord, coord); FORMEMBERS(saved_coord, member) { - rdman_remove_shape(rdman, member->shape); + rdman_shape_free(rdman, member->shape); } rdman_coord_free(rdman, saved_coord); } FORMEMBERS(saved_coord, member) { - rdman_remove_shape(rdman, member->shape); + rdman_shape_free(rdman, member->shape); } /* Resources of root_coord is free by elmpool_free() or * caller; for canvas */ + shape = saved_shape = STAILQ_HEAD(rdman->shapes); + while(shape && (shape = STAILQ_NEXT(shape_t, sh_next, shape))) { + rdman_shape_free(rdman, saved_shape); +#if 0 + STAILQ_REMOVE(rdman->shapes, shape_t, sh_next, saved_shape); +#endif + saved_shape = shape; + } + if(saved_shape != NULL) + rdman_shape_free(rdman, saved_shape); + elmpool_free(rdman->coord_pool); elmpool_free(rdman->geo_pool); elmpool_free(rdman->shnode_pool); @@ -303,8 +361,6 @@ DARRAY_DESTROY(&rdman->dirty_geos); DARRAY_DESTROY(&rdman->dirty_areas); DARRAY_DESTROY(&rdman->gen_geos); - DARRAY_DESTROY(&rdman->free_coords); - DARRAY_DESTROY(&rdman->free_geos); } @@ -362,35 +418,95 @@ * is postponsed. * \todo redraw shape objects that overlaid with removed one. */ -int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { +int rdman_shape_free(redraw_man_t *rdman, shape_t *shape) { geo_t *geo; - coord_t *coord; int r; geo = shape->geo; - coord = shape->coord; - if(rdman_is_dirty(rdman)) { + if(rdman_is_dirty(rdman) && geo != NULL) { + if(geo->flags & GEF_FREE) + return ERR; + geo->flags |= GEF_FREE | GEF_HIDDEN; if(!(geo->flags & GEF_DIRTY)) { r = add_dirty_geo(rdman, geo); if(r != OK) return ERR; } - r = add_free_geo(rdman, geo); + r = add_free_obj(rdman, shape, (free_func_t)rdman_shape_free); if(r != OK) return ERR; return OK; } - geo_detach_coord(geo, coord); - subject_free(&rdman->ob_factory, geo->mouse_event); - sh_detach_geo(shape); - elmpool_elm_free(rdman->geo_pool, geo); - sh_detach_coord(shape); + if(geo != NULL) { + geo_detach_coord(geo, shape->coord); + sh_detach_coord(shape); + sh_detach_geo(shape); + subject_free(&rdman->ob_factory, geo->mouse_event); + elmpool_elm_free(rdman->geo_pool, geo); + } + STAILQ_REMOVE(rdman->shapes, shape_t, sh_next, shape); + shape->free(shape); return OK; } +shnode_t *shnode_new(redraw_man_t *rdman, shape_t *shape) { + shnode_t *node; + + node = (shnode_t *)elmpool_elm_alloc(rdman->shnode_pool); + if(node) { + node->shape = shape; + node->next = NULL; + } + return node; +} + +int rdman_paint_free(redraw_man_t *rdman, paint_t *paint) { + shnode_t *shnode, *saved_shnode; + + if(rdman_is_dirty(rdman)) { + if(!(paint->flags & PNTF_FREE)) + return ERR; + add_free_obj(rdman, paint, (free_func_t)rdman_paint_free); + paint->flags |= PNTF_FREE; + return OK; + } + + /* Free member shapes that using this paint. */ + saved_shnode = NULL; + FORPAINTMEMBERS(paint, shnode) { + if(saved_shnode) { + RM_PAINTMEMBER(paint, saved_shnode); + shnode_free(rdman, saved_shnode); + } + saved_shnode = shnode; + } + if(saved_shnode) { + RM_PAINTMEMBER(paint, saved_shnode); + shnode_free(rdman, saved_shnode); + } + + RM_PAINT(rdman, paint); + paint->free(rdman, paint); + return OK; +} + +void _rdman_paint_real_remove_child(redraw_man_t *rdman, + paint_t *paint, + shape_t *shape) { + shnode_t *shnode; + + FORPAINTMEMBERS(paint, shnode) { + if(shnode->shape == shape) { + RM_PAINTMEMBER(paint, shnode); + shnode_free(rdman, shnode); + break; + } + } +} + coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { coord_t *coord, *root_coord; coord_t *visit; @@ -448,6 +564,9 @@ return ERR; if(rdman_is_dirty(rdman)) { + if(coord->flags & COF_FREE) + return ERR; + FORCHILDREN(coord, child) { if(!(child->flags & COF_FREE)) return ERR; @@ -462,7 +581,7 @@ if(r != OK) return ERR; } - r = add_free_coord(rdman, coord); + r = add_free_obj(rdman, coord, (free_func_t)rdman_coord_free); if(r != OK) return ERR; return OK; @@ -474,9 +593,6 @@ if(FIRST_CHILD(coord) != NULL) return ERR; - if(coord->flags & COF_FREE) - return ERR; - /* Free canvas (\ref redraw) */ if(coord->flags & COF_OWN_CANVAS) free_canvas(coord->canvas); @@ -500,14 +616,18 @@ for(coord = postorder_coord_subtree(subtree, prev_coord); coord != NULL; coord = postorder_coord_subtree(subtree, coord)) { + if(!(prev_coord->flags & COF_FREE)) { + r = rdman_coord_free(rdman, prev_coord); + if(r != OK) + return ERR; + } + prev_coord = coord; + } + if(!(prev_coord->flags & COF_FREE)) { r = rdman_coord_free(rdman, prev_coord); if(r != OK) return ERR; - prev_coord = coord; } - r = rdman_coord_free(rdman, prev_coord); - if(r != OK) - return ERR; return OK; } @@ -566,13 +686,11 @@ } int rdman_paint_changed(redraw_man_t *rdman, paint_t *paint) { - shnode_t *node; + shnode_t *shnode; int r; - for(node = STAILQ_HEAD(paint->members); - node != NULL; - node = STAILQ_NEXT(shnode_t, next, node)) { - r = _rdman_shape_changed(rdman, node->shape); + FORPAINTMEMBERS(paint, shnode) { + r = _rdman_shape_changed(rdman, shnode->shape); if(r != OK) return ERR; } @@ -986,9 +1104,6 @@ event_t event; ob_factory_t *factory; subject_t *redraw; - geo_t *geo; - coord_t *coord; - int i; r = clean_rdman_dirties(rdman); if(r != OK) @@ -1010,17 +1125,7 @@ rdman->dirty_areas.num = 0; /* Free postponsed removing */ - for(i = 0; i < rdman->free_geos.num; i++) { - geo = rdman->free_geos.ds[i]; - rdman_remove_shape(rdman, geo->shape); - } - DARRAY_CLEAN(&rdman->free_geos); - - for(i = 0; i < rdman->free_coords.num; i++) { - coord = rdman->free_coords.ds[i]; - rdman_remove_shape(rdman, coord); - } - DARRAY_CLEAN(&rdman->free_coords); + free_free_objs(rdman); factory = rdman_get_ob_factory(rdman); redraw = rdman_get_redraw_subject(rdman); @@ -1058,8 +1163,10 @@ */ int rdman_redraw_all(redraw_man_t *rdman) { + area_t area; +#ifndef UNITTEST cairo_surface_t *surface; - area_t area; +#endif int r; area.x = area.y = 0; @@ -1128,17 +1235,6 @@ return r; } -shnode_t *shnode_new(redraw_man_t *rdman, shape_t *shape) { - shnode_t *node; - - node = (shnode_t *)elmpool_elm_alloc(rdman->shnode_pool); - if(node) { - node->shape = shape; - node->next = NULL; - } - return node; -} - /*! \page dirty Dirty geo, coord, and area. * * \section dirty_of_ego Dirty of geo @@ -1174,6 +1270,28 @@ * coords will also clean member geos. */ +/*! \page man_obj Manage Objects. + * + * Shapes and paints should also be managed by redraw manager. Redraw + * manager must know life-cycle of shapes and paints to avoid to use them + * after being free. If a shape is released when it is dirty, redraw + * manager will try to access them, after released, for redrawing. + * We can make a copy information need by redraw manager to redraw them, + * but it is more complicate, and induce runtime overhead. + * + * So, redraw manage had better also manage life-cycle of shapes and paints. + * Shapes and paints should be created and freed through interfaces + * provided by redraw manager. To reduce overhead of interfaces, they can + * be implemented as C macros. + * + * To refactory redraw manage to manage life-cycle of shapes and paints, + * following functions/macros are introduced. + * - rdman_paint_*_new() + * - rdman_paint_free() + * - rdman_shape_*_new() + * - rdman_shape_free() + */ + /* * When redraw an area, the affected elements may also extend to * outside of the area. Since the order of drawing will change @@ -1284,7 +1402,12 @@ int draw_cnt; }; -shape_t *sh_dummy_new(co_aix x, co_aix y, co_aix w, co_aix h) { +void sh_dummy_free(shape_t *sh) { + free(sh); +} + +shape_t *sh_dummy_new(redraw_man_t *rdman, + co_aix x, co_aix y, co_aix w, co_aix h) { sh_dummy_t *dummy; dummy = (sh_dummy_t *)malloc(sizeof(sh_dummy_t)); @@ -1299,14 +1422,13 @@ dummy->h = h; dummy->trans_cnt = 0; dummy->draw_cnt = 0; + dummy->shape.free = sh_dummy_free; + + rdman_shape_man(rdman, (shape_t *)dummy); return (shape_t *)dummy; } -void sh_dummy_free(shape_t *sh) { - free(sh); -} - void sh_dummy_transform(shape_t *shape) { sh_dummy_t *dummy = (sh_dummy_t *)shape; co_aix poses[2][2]; @@ -1341,7 +1463,7 @@ static void dummy_paint_prepare(paint_t *paint, cairo_t *cr) { } -static void dummy_paint_free(paint_t *paint) { +static void dummy_paint_free(redraw_man_t *rdman, paint_t *paint) { if(paint) free(paint); } @@ -1358,7 +1480,7 @@ return paint; } -void test_rdman_redraw_changed(void) { +static void test_rdman_redraw_changed(void) { coord_t *coords[3]; shape_t *shapes[3]; sh_dummy_t **dummys; @@ -1373,7 +1495,7 @@ redraw_man_init(rdman, NULL, NULL); paint = dummy_paint_new(rdman); for(i = 0; i < 3; i++) { - shapes[i] = sh_dummy_new(0, 0, 50, 50); + shapes[i] = sh_dummy_new(rdman, 0, 0, 50, 50); rdman_paint_fill(rdman, paint, shapes[i]); coords[i] = rdman_coord_new(rdman, rdman->root_coord); coords[i]->matrix[2] = 10 + i * 100; @@ -1399,15 +1521,39 @@ CU_ASSERT(dummys[1]->draw_cnt == 2); CU_ASSERT(dummys[2]->draw_cnt == 2); - paint->free(paint); + rdman_paint_free(rdman, paint); redraw_man_destroy(rdman); } +static int test_free_pass = 0; + +static void test_free(redraw_man_t *rdman, void *obj) { + test_free_pass++; +} + +static void test_rdman_free_objs(void) { + redraw_man_t *rdman; + redraw_man_t _rdman; + int i; + + redraw_man_init(&_rdman, NULL, NULL); + rdman = &_rdman; + + test_free_pass = 0; + + for(i = 0; i < 4; i++) + add_free_obj(rdman, NULL, test_free); + + redraw_man_destroy(rdman); + CU_ASSERT(test_free_pass == 4); +} + CU_pSuite get_redraw_man_suite(void) { CU_pSuite suite; suite = CU_add_suite("Suite_redraw_man", NULL, NULL); CU_ADD_TEST(suite, test_rdman_redraw_changed); + CU_ADD_TEST(suite, test_rdman_free_objs); return suite; }