Mercurial > MadButterfly
comparison src/redraw_man.c @ 12:79e9edf4c00a
Add redraw manager
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Mon, 28 Jul 2008 17:45:36 +0800 |
parents | |
children | ed55009d96d3 |
comparison
equal
deleted
inserted
replaced
11:128af06c876c | 12:79e9edf4c00a |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 #include "mb_types.h" | |
5 #include "shapes.h" | |
6 #include "tools.h" | |
7 #include "redraw_man.h" | |
8 | |
9 #define OK 0 | |
10 #define ERR -1 | |
11 | |
12 int redraw_man_init(redraw_man_t *rdman) { | |
13 extern void redraw_man_destroy(redraw_man_t *rdman); | |
14 | |
15 memset(rdman, 0, sizeof(redraw_man_t)); | |
16 | |
17 rdman->geo_pool = elmpool_new(sizeof(geo_t), 128); | |
18 if(rdman->geo_pool == NULL) | |
19 return ERR; | |
20 | |
21 rdman->coord_pool = elmpool_new(sizeof(coord_t), 16); | |
22 if(rdman->coord_pool == NULL) { | |
23 elmpool_free(rdman->geo_pool); | |
24 return ERR; | |
25 } | |
26 | |
27 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); | |
28 if(rdman->root_coord == NULL) | |
29 redraw_man_destroy(rdman); | |
30 | |
31 coord_init(rdman->root_coord, NULL); | |
32 | |
33 return OK; | |
34 } | |
35 | |
36 void redraw_man_destroy(redraw_man_t *rdman) { | |
37 elmpool_free(rdman->coord_pool); | |
38 elmpool_free(rdman->geo_pool); | |
39 } | |
40 | |
41 | |
42 #define ASSERT(x) | |
43 /* | |
44 * Change transformation matrix | |
45 * - update aggregated transformation matrix | |
46 * - of coord_t object been changed. | |
47 * - of children coord_t objects. | |
48 * - redraw members of coord_t objects. | |
49 * - redraw shape objects they are overlaid with members. | |
50 * - find out overlaid shape objects. | |
51 * - geo_t of a coord_t object | |
52 * - can make finding more efficiency. | |
53 * - fill overlay geo_t objects of members. | |
54 * | |
55 * Change a shape object | |
56 * - redraw changed object. | |
57 * - redraw shape objects they are overlaid with changed object. | |
58 * - find out overlaid shape objects. | |
59 * | |
60 * That coord and geo of shape objects are setted by user code | |
61 * give user code a chance to collect coord and geo objects together | |
62 * and gain interest of higher cache hit rate. | |
63 */ | |
64 | |
65 /*! \brief Find out all affected shape objects. | |
66 * | |
67 * Find out all shape objects that are overalid with geo_t of | |
68 * a geometry changed object. | |
69 * | |
70 * Linear scan geo_t objects of all shape objects in all_shapes | |
71 * list of a redraw_man_t object. | |
72 */ | |
73 int rdman_find_overlaid_shapes(redraw_man_t *rdman, geo_t *geo, | |
74 geo_t ***overlays) { | |
75 int n_geos; | |
76 geo_t **geos; | |
77 geo_t *geo_cur; | |
78 int n_overlays; | |
79 geo_t **_overlays; | |
80 int i; | |
81 | |
82 n_geos = rdman->n_geos; | |
83 | |
84 geos = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
85 if(geos == NULL) | |
86 return -1; | |
87 | |
88 _overlays = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
89 if(geos == NULL) { | |
90 free(geos); | |
91 return -1; | |
92 } | |
93 | |
94 geo_cur = STAILQ_HEAD(rdman->all_geos); | |
95 for(i = 0; i < n_geos; i++) { | |
96 geos[i] = geo_cur; | |
97 geo_cur = STAILQ_NEXT(geo_t, next, geo_cur); | |
98 } | |
99 geo_mark_overlay(geo, n_geos, geos, &n_overlays, _overlays); | |
100 | |
101 free(geos); | |
102 *overlays = _overlays; | |
103 | |
104 return n_overlays; | |
105 } | |
106 | |
107 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) { | |
108 geo_t *geo; | |
109 | |
110 geo = elmpool_elm_alloc(rdman->geo_pool); | |
111 if(geo == NULL) | |
112 return ERR; | |
113 sh_attach_geo(shape, geo); | |
114 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); | |
115 rdman->n_geos++; | |
116 sh_attach_coord(shape, coord); | |
117 | |
118 return OK; | |
119 } | |
120 | |
121 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { | |
122 STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo); | |
123 elmpool_elm_free(rdman->geo_pool, shape->geo); | |
124 sh_detach_geo(shape); | |
125 rdman->n_geos--; | |
126 sh_detach_coord(shape); | |
127 return OK; | |
128 } | |
129 | |
130 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { | |
131 coord_t *coord; | |
132 | |
133 coord = elmpool_elm_alloc(rdman->coord_pool); | |
134 if(coord == NULL) | |
135 return NULL; | |
136 | |
137 coord_init(coord, parent); | |
138 | |
139 return coord; | |
140 } | |
141 | |
142 /*! \brief Free a coord of a redraw_man_t object. | |
143 * | |
144 * \param coord is a coord_t without children and members. | |
145 * \return 0 for successful, -1 for error. | |
146 */ | |
147 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { | |
148 coord_t *parent; | |
149 | |
150 parent = coord->parent; | |
151 if(parent == NULL) | |
152 return ERR; | |
153 | |
154 if(STAILQ_HEAD(coord->members) != NULL) | |
155 return ERR; | |
156 | |
157 if(STAILQ_HEAD(coord->children) != NULL) | |
158 return ERR; | |
159 | |
160 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); | |
161 elmpool_elm_free(rdman->coord_pool, coord); | |
162 | |
163 return OK; | |
164 } | |
165 | |
166 void rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { | |
167 } | |
168 | |
169 /* | |
170 * When redraw an area, the affected elements may also extend to | |
171 * outside of the area. Since the order of drawing will change | |
172 * the result, it will infect more and more elements to keep | |
173 * drawing order althrough they are overlaid directly with | |
174 * specified area. | |
175 * | |
176 * To fix the problem, we don't extend the set of redrawing to | |
177 * elements they are not overliad directly. The redrawing is | |
178 * performed on a temporary surface, clipped to fit the area, and | |
179 * update only specified area on the destinate surface. | |
180 */ | |
181 | |
182 /* | |
183 * To accelerate speed of transformation, when a matrix changed, | |
184 * transformation should be aggregated and computed in a loop. | |
185 * It can get intereset of higher hit rate of cache. | |
186 * - shapes prvoide list of positions needed to be transformed. | |
187 * - redraw_man transforms positions from shapes. | |
188 * - shapes drawing with result of transforms. | |
189 * - shapes should be called to give them a chance to update geometries. | |
190 */ | |
191 | |
192 #ifdef UNITTEST | |
193 | |
194 #include <CUnit/Basic.h> | |
195 | |
196 struct _sh_dummy { | |
197 shape_t shape; | |
198 co_aix x, y; | |
199 co_aix w, h; | |
200 }; | |
201 typedef struct _sh_dummy sh_dummy_t; | |
202 | |
203 shape_t *sh_dummy_new(co_aix x, co_aix y, co_aix w, co_aix h) { | |
204 sh_dummy_t *dummy; | |
205 | |
206 dummy = (sh_dummy_t *)malloc(sizeof(sh_dummy_t)); | |
207 if(dummy == NULL) | |
208 return NULL; | |
209 | |
210 dummy->x = x; | |
211 dummy->y = y; | |
212 dummy->w = w; | |
213 dummy->h = h; | |
214 | |
215 return (shape_t *)dummy; | |
216 } | |
217 | |
218 void sh_dummy_free(shape_t *sh) { | |
219 free(sh); | |
220 } | |
221 | |
222 void sh_dummy_transform(shape_t *shape) { | |
223 sh_dummy_t *dummy = (sh_dummy_t *)shape; | |
224 co_aix poses[2][2]; | |
225 co_aix x1, y1, x2, y2; | |
226 | |
227 if(shape->geo && shape->coord) { | |
228 x1 = dummy->x; | |
229 y1 = dummy->y; | |
230 x2 = x1 + dummy->w; | |
231 y2 = y1 + dummy->h; | |
232 | |
233 coord_trans_pos(shape->coord, &x1, &y1); | |
234 coord_trans_pos(shape->coord, &x2, &y2); | |
235 poses[0][0] = x1; | |
236 poses[0][1] = y1; | |
237 poses[1][0] = x2; | |
238 poses[1][1] = y2; | |
239 | |
240 geo_init(shape->geo, 2, poses); | |
241 } | |
242 } | |
243 | |
244 void test_rdman_find_overlaid_shapes(void) { | |
245 redraw_man_t rdman; | |
246 geo_t geo; | |
247 coord_t *coords[3]; | |
248 shape_t *shapes[5]; | |
249 geo_t **overlays; | |
250 int n; | |
251 int i; | |
252 | |
253 redraw_man_init(&rdman); | |
254 coords[0] = rdman.root_coord; | |
255 for(i = 1; i < 3; i++) { | |
256 coords[i] = rdman_coord_new(&rdman, rdman.root_coord); | |
257 } | |
258 for(i = 0; i < 5; i++) { | |
259 shapes[i] = sh_dummy_new(10 + i * 30, 10 + i * 20, 25, 15); | |
260 CU_ASSERT(shapes[i] != NULL); | |
261 } | |
262 for(i = 0; i < 3; i++) | |
263 rdman_add_shape(&rdman, shapes[i], coords[1]); | |
264 for(i = 3; i < 5; i++) | |
265 rdman_add_shape(&rdman, shapes[i], coords[2]); | |
266 | |
267 coords[1]->matrix[0] = 2; | |
268 coords[0]->matrix[4] = 2; | |
269 | |
270 update_aggr_matrix(coords[0]); | |
271 for(i = 0; i < 5; i++) | |
272 sh_dummy_transform(shapes[i]); | |
273 | |
274 geo.x = 100; | |
275 geo.y = 120; | |
276 geo.w = 140; | |
277 geo.h = 40; | |
278 | |
279 n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays); | |
280 CU_ASSERT(n == 2); | |
281 CU_ASSERT(overlays != NULL); | |
282 CU_ASSERT(overlays[0] == shapes[2]->geo); | |
283 CU_ASSERT(overlays[1] == shapes[3]->geo); | |
284 | |
285 free(overlays); | |
286 for(i = 0; i < 5; i++) | |
287 sh_dummy_free(shapes[i]); | |
288 | |
289 redraw_man_destroy(&rdman); | |
290 } | |
291 | |
292 CU_pSuite get_redraw_man_suite(void) { | |
293 CU_pSuite suite; | |
294 | |
295 suite = CU_add_suite("Suite_redraw_man", NULL, NULL); | |
296 CU_ADD_TEST(suite, test_rdman_find_overlaid_shapes); | |
297 | |
298 return suite; | |
299 } | |
300 | |
301 #endif /* UNITTEST */ |