Mercurial > MadButterfly
annotate src/redraw_man.c @ 15:c2ce186a5c37
X_main uses rdman_redraw_all()
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Fri, 01 Aug 2008 01:40:07 +0800 |
parents | d34232f15863 |
children | e17e12b112c4 |
rev | line source |
---|---|
12 | 1 #include <stdio.h> |
2 #include <stdlib.h> | |
3 #include <string.h> | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
4 #include <cairo.h> |
12 | 5 #include "mb_types.h" |
6 #include "shapes.h" | |
7 #include "tools.h" | |
8 #include "redraw_man.h" | |
9 | |
10 #define OK 0 | |
11 #define ERR -1 | |
12 | |
13 | 13 #define OFFSET(type, field) ((void *)&((type *)NULL)->field - (void *)NULL) |
14 #define SWAP(a, b, t) do { t c; c = a; a = b; b = c; } while(0) | |
15 | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
16 int redraw_man_init(redraw_man_t *rdman, cairo_t *cr) { |
12 | 17 extern void redraw_man_destroy(redraw_man_t *rdman); |
18 | |
19 memset(rdman, 0, sizeof(redraw_man_t)); | |
20 | |
21 rdman->geo_pool = elmpool_new(sizeof(geo_t), 128); | |
22 if(rdman->geo_pool == NULL) | |
23 return ERR; | |
24 | |
25 rdman->coord_pool = elmpool_new(sizeof(coord_t), 16); | |
26 if(rdman->coord_pool == NULL) { | |
27 elmpool_free(rdman->geo_pool); | |
28 return ERR; | |
29 } | |
30 | |
31 rdman->root_coord = elmpool_elm_alloc(rdman->coord_pool); | |
32 if(rdman->root_coord == NULL) | |
33 redraw_man_destroy(rdman); | |
13 | 34 rdman->n_coords = 1; |
12 | 35 coord_init(rdman->root_coord, NULL); |
36 | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
37 rdman->cr = cr; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
38 |
12 | 39 return OK; |
40 } | |
41 | |
42 void redraw_man_destroy(redraw_man_t *rdman) { | |
43 elmpool_free(rdman->coord_pool); | |
44 elmpool_free(rdman->geo_pool); | |
13 | 45 if(rdman->dirty_coords) |
46 free(rdman->dirty_coords); | |
14 | 47 if(rdman->dirty_geos) |
48 free(rdman->dirty_geos); | |
12 | 49 } |
50 | |
51 | |
52 #define ASSERT(x) | |
53 /* | |
54 * Change transformation matrix | |
55 * - update aggregated transformation matrix | |
56 * - of coord_t object been changed. | |
57 * - of children coord_t objects. | |
58 * - redraw members of coord_t objects. | |
59 * - redraw shape objects they are overlaid with members. | |
60 * - find out overlaid shape objects. | |
61 * - geo_t of a coord_t object | |
62 * - can make finding more efficiency. | |
63 * - fill overlay geo_t objects of members. | |
64 * | |
65 * Change a shape object | |
66 * - redraw changed object. | |
67 * - redraw shape objects they are overlaid with changed object. | |
68 * - find out overlaid shape objects. | |
69 * | |
70 * That coord and geo of shape objects are setted by user code | |
71 * give user code a chance to collect coord and geo objects together | |
72 * and gain interest of higher cache hit rate. | |
73 */ | |
74 | |
75 /*! \brief Find out all affected shape objects. | |
76 * | |
77 * Find out all shape objects that are overalid with geo_t of | |
78 * a geometry changed object. | |
79 * | |
80 * Linear scan geo_t objects of all shape objects in all_shapes | |
81 * list of a redraw_man_t object. | |
82 */ | |
83 int rdman_find_overlaid_shapes(redraw_man_t *rdman, geo_t *geo, | |
84 geo_t ***overlays) { | |
85 int n_geos; | |
86 geo_t **geos; | |
87 geo_t *geo_cur; | |
88 int n_overlays; | |
89 geo_t **_overlays; | |
90 int i; | |
91 | |
92 n_geos = rdman->n_geos; | |
93 | |
94 geos = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
95 if(geos == NULL) | |
96 return -1; | |
97 | |
98 _overlays = (geo_t **)malloc(sizeof(geo_t *) * n_geos); | |
99 if(geos == NULL) { | |
100 free(geos); | |
101 return -1; | |
102 } | |
103 | |
104 geo_cur = STAILQ_HEAD(rdman->all_geos); | |
105 for(i = 0; i < n_geos; i++) { | |
106 geos[i] = geo_cur; | |
107 geo_cur = STAILQ_NEXT(geo_t, next, geo_cur); | |
108 } | |
109 geo_mark_overlay(geo, n_geos, geos, &n_overlays, _overlays); | |
110 | |
111 free(geos); | |
112 *overlays = _overlays; | |
113 | |
114 return n_overlays; | |
115 } | |
116 | |
117 int rdman_add_shape(redraw_man_t *rdman, shape_t *shape, coord_t *coord) { | |
118 geo_t *geo; | |
13 | 119 geo_t *visit; |
120 unsigned int next_order; | |
12 | 121 |
122 geo = elmpool_elm_alloc(rdman->geo_pool); | |
123 if(geo == NULL) | |
124 return ERR; | |
125 sh_attach_geo(shape, geo); | |
126 STAILQ_INS_TAIL(rdman->all_geos, geo_t, next, geo); | |
127 rdman->n_geos++; | |
13 | 128 |
129 geo->order = ++rdman->next_geo_order; | |
130 if(geo->order == 0) { | |
131 next_order = 0; | |
132 for(visit = STAILQ_HEAD(rdman->all_geos); | |
133 visit != NULL; | |
134 visit = STAILQ_NEXT(geo_t, next, visit)) | |
135 visit->order = ++next_order; | |
136 rdman->next_geo_order = next_order; | |
137 } | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
138 geo->flags |= GEF_DIRTY; |
13 | 139 |
12 | 140 sh_attach_coord(shape, coord); |
141 | |
142 return OK; | |
143 } | |
144 | |
145 int rdman_remove_shape(redraw_man_t *rdman, shape_t *shape) { | |
146 STAILQ_REMOVE(rdman->all_geos, geo_t, next, shape->geo); | |
147 elmpool_elm_free(rdman->geo_pool, shape->geo); | |
148 sh_detach_geo(shape); | |
149 rdman->n_geos--; | |
150 sh_detach_coord(shape); | |
151 return OK; | |
152 } | |
153 | |
154 coord_t *rdman_coord_new(redraw_man_t *rdman, coord_t *parent) { | |
13 | 155 coord_t *coord, *root_coord; |
156 coord_t *visit; | |
12 | 157 |
158 coord = elmpool_elm_alloc(rdman->coord_pool); | |
159 if(coord == NULL) | |
160 return NULL; | |
161 | |
162 coord_init(coord, parent); | |
13 | 163 rdman->n_coords++; |
164 | |
165 coord->order = ++rdman->next_coord_order; | |
166 if(coord->order == 0) { | |
167 rdman->next_coord_order = 0; | |
168 root_coord = visit = rdman->root_coord; | |
169 /* skip root coord. */ | |
170 visit = preorder_coord_subtree(root_coord, visit); | |
171 while(visit) { | |
172 visit->order = ++rdman->next_coord_order; | |
173 visit = preorder_coord_subtree(root_coord, visit); | |
174 } | |
175 } | |
12 | 176 |
177 return coord; | |
178 } | |
179 | |
180 /*! \brief Free a coord of a redraw_man_t object. | |
181 * | |
182 * \param coord is a coord_t without children and members. | |
183 * \return 0 for successful, -1 for error. | |
184 */ | |
185 int rdman_coord_free(redraw_man_t *rdman, coord_t *coord) { | |
186 coord_t *parent; | |
187 | |
188 parent = coord->parent; | |
189 if(parent == NULL) | |
190 return ERR; | |
191 | |
192 if(STAILQ_HEAD(coord->members) != NULL) | |
193 return ERR; | |
194 | |
195 if(STAILQ_HEAD(coord->children) != NULL) | |
196 return ERR; | |
197 | |
198 STAILQ_REMOVE(parent->children, coord_t, sibling, coord); | |
199 elmpool_elm_free(rdman->coord_pool, coord); | |
13 | 200 rdman->n_coords--; |
201 | |
202 return OK; | |
203 } | |
204 | |
205 static int extend_memblk(void **buf, int o_size, int n_size) { | |
206 void *new_buf; | |
207 | |
208 new_buf = realloc(*buf, n_size); | |
209 if(new_buf == NULL) | |
210 return ERR; | |
211 | |
212 if(new_buf != *buf) { | |
213 memcpy(new_buf, *buf, o_size); | |
214 free(*buf); | |
215 *buf = new_buf; | |
216 } | |
217 | |
218 return OK; | |
219 } | |
220 | |
221 static int add_dirty_geo(redraw_man_t *rdman, geo_t *geo) { | |
14 | 222 int max_dirty_geos; |
13 | 223 int r; |
224 | |
14 | 225 if(rdman->n_dirty_geos >= rdman->max_dirty_geos) { |
226 max_dirty_geos = rdman->n_geos; | |
227 r = extend_memblk((void **)&rdman->dirty_geos, | |
228 sizeof(geo_t *) * rdman->n_dirty_geos, | |
229 sizeof(geo_t *) * max_dirty_geos); | |
13 | 230 if(r != OK) |
231 return ERR; | |
14 | 232 rdman->max_dirty_geos = max_dirty_geos; |
13 | 233 } |
234 | |
14 | 235 rdman->dirty_geos[rdman->n_dirty_geos++] = geo; |
13 | 236 return OK; |
237 } | |
238 | |
239 static int add_dirty_area(redraw_man_t *rdman, area_t *area) { | |
240 int max_dirty_areas; | |
241 int r; | |
242 | |
243 if(rdman->n_dirty_areas >= rdman->max_dirty_areas) { | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
244 /* every geo object and coord object can contribute 2 areas. */ |
13 | 245 max_dirty_areas = (rdman->n_geos + rdman->n_coords) * 2; |
246 r = extend_memblk((void **)&rdman->dirty_areas, | |
247 sizeof(area_t *) * rdman->n_dirty_areas, | |
248 sizeof(area_t *) * max_dirty_areas); | |
249 if(r != OK) | |
250 return ERR; | |
251 rdman->max_dirty_areas = max_dirty_areas; | |
252 } | |
253 | |
254 rdman->dirty_areas[++rdman->n_dirty_areas] = area; | |
255 return OK; | |
256 } | |
257 | |
258 /*! \brief Mark a coord is changed. | |
259 * | |
260 * A changed coord_t object is marked as dirty and put | |
261 * into dirty_coords list. | |
262 */ | |
263 int rdman_coord_changed(redraw_man_t *rdman, coord_t *coord) { | |
264 int max_dirty_coords; | |
265 int r; | |
266 | |
267 if(coord->flags & COF_DIRTY) | |
268 return OK; | |
269 | |
270 if(rdman->n_dirty_coords >= rdman->max_dirty_coords) { | |
271 /* Max of dirty_coords is not big enough. */ | |
272 max_dirty_coords = rdman->max_dirty_coords + 16; | |
273 | |
274 r = extend_memblk((void **)&rdman->dirty_coords, | |
275 sizeof(coord_t *) * rdman->n_dirty_coords, | |
276 sizeof(coord_t *) * max_dirty_coords); | |
277 rdman->max_dirty_coords = max_dirty_coords; | |
278 } | |
279 | |
280 rdman->dirty_coords[rdman->n_dirty_coords++] = coord; | |
281 coord->flags |= COF_DIRTY; | |
282 | |
283 return OK; | |
284 } | |
285 | |
286 /*! \brief Mark a shape is changed. | |
287 * | |
288 * The geo_t object of a changed shape is mark as dirty and | |
14 | 289 * put into dirty_geos list. |
13 | 290 */ |
291 int rdman_shape_changed(redraw_man_t *rdman, shape_t *shape) { | |
292 geo_t *geo; | |
293 int r; | |
294 | |
295 geo = shape->geo; | |
296 | |
297 if(geo->flags & GEF_DIRTY) | |
298 return OK; | |
299 | |
300 r = add_dirty_geo(rdman, geo); | |
301 if(r == ERR) | |
302 return ERR; | |
303 geo->flags |= GEF_DIRTY; | |
12 | 304 |
305 return OK; | |
306 } | |
307 | |
13 | 308 /*! \brief Sort a list of element by a unsigned integer. |
309 * | |
310 * The result is in ascend order. The unsigned integers is | |
311 * at offset specified by 'off' from start address of elemnts. | |
312 */ | |
313 static void _insert_sort(void **elms, int num, int off) { | |
314 int i, j; | |
315 unsigned int val; | |
316 | |
317 for(i = 1; i < num; i++) { | |
318 val = *(unsigned int *)(elms[i] + off); | |
319 for(j = i; j > 0; j--) { | |
320 if(*(unsigned int *)(elms[j - 1] + off) <= val) | |
321 break; | |
322 elms[j] = elms[j - 1]; | |
323 } | |
324 elms[j] = elms[i]; | |
325 } | |
326 } | |
327 | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
328 static void update_shape_geo(shape_t *shape) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
329 switch(shape->sh_type) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
330 case SHT_PATH: |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
331 sh_path_transform(shape); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
332 break; |
13 | 333 } |
334 } | |
335 | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
336 static void area_to_positions(area_t *area, co_aix (*poses)[2]) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
337 poses[0][0] = area->x; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
338 poses[0][1] = area->y; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
339 poses[1][0] = area->x + area->w; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
340 poses[1][1] = area->y + area->h;; |
14 | 341 } |
342 | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
343 static int compute_coord_area(coord_t *coord) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
344 shape_t *shape; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
345 geo_t *geo; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
346 co_aix (*poses)[2]; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
347 int cnt, pos_cnt; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
348 int i; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
349 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
350 cnt = 0; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
351 for(shape = STAILQ_HEAD(coord->members); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
352 shape != NULL; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
353 shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
354 SWAP(shape->geo->cur_area, shape->geo->last_area, area_t *); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
355 update_shape_geo(shape); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
356 cnt++; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
357 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
358 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
359 poses = (co_aix (*)[2])malloc(sizeof(co_aix [2]) * 2 * cnt); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
360 if(poses == NULL) |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
361 return ERR; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
362 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
363 pos_cnt = 0; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
364 for(shape = STAILQ_HEAD(coord->members); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
365 shape != NULL; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
366 shape = STAILQ_NEXT(shape_t, coord_mem_next, shape)) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
367 geo = shape->geo; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
368 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
369 area_to_positions(&geo->areas[0], poses + pos_cnt); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
370 pos_cnt += 2; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
371 area_to_positions(&geo->areas[1], poses + pos_cnt); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
372 pos_cnt += 2; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
373 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
374 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
375 for(i = 0; i < pos_cnt; i++) |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
376 coord_trans_pos(coord, &poses[i][0], &poses[i][1]); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
377 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
378 area_init(coord->cur_area, cnt, poses); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
379 free(poses); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
380 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
381 return OK; |
13 | 382 } |
383 | |
14 | 384 static void draw_shape(redraw_man_t *rdman, shape_t *shape) { |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
385 switch(shape->sh_type) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
386 case SHT_PATH: |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
387 sh_path_draw(shape, rdman->cr); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
388 break; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
389 } |
13 | 390 } |
391 | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
392 static void make_clip(redraw_man_t *rdman, int n_dirty_areas, |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
393 area_t **dirty_areas) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
394 int i; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
395 area_t *area; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
396 cairo_t *cr; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
397 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
398 cr = rdman->cr; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
399 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
400 cairo_reset_clip(cr); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
401 for(i = 0; i < n_dirty_areas; i++) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
402 area = dirty_areas[i]; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
403 cairo_rectangle(cr, area->x, area->y, area->w, area->h); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
404 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
405 cairo_clip(cr); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
406 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
407 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
408 static void draw_shapes_in_areas(redraw_man_t *rdman, |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
409 int n_areas, |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
410 area_t **areas) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
411 geo_t *visit_geo; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
412 int i; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
413 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
414 for(visit_geo = STAILQ_HEAD(rdman->all_geos); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
415 visit_geo != NULL; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
416 visit_geo = STAILQ_NEXT(geo_t, next, visit_geo)) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
417 if(visit_geo->flags & GEF_DIRTY) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
418 visit_geo->flags &= ~GEF_DIRTY; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
419 update_shape_geo(visit_geo->shape); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
420 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
421 for(i = 0; i < n_areas; i++) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
422 if(is_overlay(visit_geo->cur_area, areas[i])) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
423 draw_shape(rdman, visit_geo->shape); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
424 break; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
425 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
426 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
427 } |
13 | 428 } |
429 | |
430 /*! \brief Re-draw all changed shapes or shapes affected by changed coords. | |
431 * | |
432 * A coord object has a geo to keep track the range that it's members will | |
433 * draw on. Geo of a coord should be recomputed when the coord is changed. | |
434 * Geo of a coord used to accelerate finding overlay shape objects of | |
435 * a specified geo. A coord object also must be recomputed when one of | |
436 * it's members is changed. | |
437 * | |
438 * New and old geo values of a coord object that is recomputed for | |
439 * changing of it-self must be used to find overlay shape objects. | |
440 * New and old geo values of a shape should also be used to find | |
441 * overlay shape objects, too. If a shape's coord is changed, shape's | |
442 * geo object is not used to find overlay shape objects any more. | |
443 * | |
444 * steps: | |
445 * - update chagned coord objects | |
14 | 446 * - recompute area for changed coord objects |
13 | 447 * - recompute geo for members shape objects |
14 | 448 * - clear dirty of geo for members to prevent from |
449 * recomputing for change of shape objects. | |
450 * - add old and new area value to list of dirty areas. | |
13 | 451 * - recompute geo for changed shape objects |
14 | 452 * - only if a shape object is dirty. |
453 * - put new and old value of area of geo to list of dirty areas. | |
454 * - Scan all shapes and redraw shapes overlaid with dirty areas. | |
13 | 455 * |
14 | 456 * dirty flag of coord objects is cleared after update. |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
457 * dirty flag of geo objects is also cleared after recomputing. |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
458 * Clean dirty flag can prevent redundant computing for geo and |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
459 * corod objects. |
14 | 460 * |
13 | 461 */ |
462 int rdman_redraw_changed(redraw_man_t *rdman) { | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
463 int i, r; |
13 | 464 int n_dirty_coords; |
465 coord_t **dirty_coords; | |
466 coord_t *visit_coord; | |
14 | 467 geo_t *visit_geo, **dirty_geos; |
468 int n_dirty_geos; | |
13 | 469 int n_dirty_areas; |
14 | 470 area_t **dirty_areas; |
13 | 471 |
472 if(rdman->n_dirty_coords > 0) { | |
473 _insert_sort((void **)rdman->dirty_coords, | |
474 rdman->n_dirty_coords, | |
475 OFFSET(coord_t, order)); | |
476 n_dirty_coords = rdman->n_dirty_coords; | |
477 dirty_coords = rdman->dirty_coords; | |
478 for(i = 0; i < n_dirty_coords; i++) { | |
479 if(!(dirty_coords[i]->flags & COF_DIRTY)) | |
480 continue; | |
481 | |
482 update_aggr_matrix(dirty_coords[i]); | |
483 for(visit_coord = dirty_coords[i]; | |
484 visit_coord != NULL; | |
485 visit_coord = preorder_coord_subtree(dirty_coords[i], | |
486 visit_coord)) { | |
487 /* Dirty member, here, and members of this coord | |
488 * will not be visited anymore. */ | |
489 visit_coord->flags &= ~COF_DIRTY; | |
490 | |
491 SWAP(visit_coord->cur_area, visit_coord->last_area, area_t *); | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
492 r = compute_coord_area(visit_coord); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
493 if(r == ERR) |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
494 return ERR; |
13 | 495 add_dirty_area(rdman, visit_coord->cur_area); |
496 add_dirty_area(rdman, visit_coord->last_area); | |
497 } | |
498 } | |
499 rdman->n_dirty_coords = 0; | |
500 } | |
501 | |
14 | 502 n_dirty_geos = rdman->n_dirty_geos; |
503 if(n_dirty_geos > 0) { | |
504 dirty_geos = rdman->dirty_geos; | |
505 for(i = 0; i < n_dirty_geos; i++) { | |
506 visit_geo = dirty_geos[i]; | |
13 | 507 if(!(visit_geo->flags & GEF_DIRTY)) |
508 continue; | |
509 | |
14 | 510 visit_geo->flags &= ~GEF_DIRTY; |
13 | 511 SWAP(visit_geo->cur_area, visit_geo->last_area, area_t *); |
14 | 512 update_shape_geo(visit_geo->shape); |
13 | 513 add_dirty_area(rdman, visit_geo->cur_area); |
514 add_dirty_area(rdman, visit_geo->last_area); | |
515 } | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
516 rdman->n_dirty_geos = 0; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
517 } |
13 | 518 |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
519 n_dirty_areas = rdman->n_dirty_areas; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
520 dirty_areas = rdman->dirty_areas; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
521 if(n_dirty_areas > 0) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
522 make_clip(rdman, n_dirty_areas, dirty_areas); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
523 draw_shapes_in_areas(rdman, n_dirty_areas, dirty_areas); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
524 rdman->n_dirty_areas = 0; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
525 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
526 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
527 return OK; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
528 } |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
529 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
530 int rdman_redraw_all(redraw_man_t *rdman) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
531 geo_t *geo; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
532 |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
533 /* TODO: update dirty coord and it's members. */ |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
534 for(geo = STAILQ_HEAD(rdman->all_geos); |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
535 geo != NULL; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
536 geo = STAILQ_NEXT(geo_t, next, geo)) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
537 if(geo->flags & GEF_DIRTY) { |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
538 geo->flags &= ~GEF_DIRTY; |
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
539 update_shape_geo(geo->shape); |
13 | 540 } |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
541 draw_shape(rdman, geo->shape); |
13 | 542 } |
543 | |
544 return OK; | |
12 | 545 } |
546 | |
547 /* | |
548 * When redraw an area, the affected elements may also extend to | |
549 * outside of the area. Since the order of drawing will change | |
550 * the result, it will infect more and more elements to keep | |
551 * drawing order althrough they are overlaid directly with | |
552 * specified area. | |
553 * | |
554 * To fix the problem, we don't extend the set of redrawing to | |
555 * elements they are not overliad directly. The redrawing is | |
556 * performed on a temporary surface, clipped to fit the area, and | |
557 * update only specified area on the destinate surface. | |
558 */ | |
559 | |
560 /* | |
561 * To accelerate speed of transformation, when a matrix changed, | |
562 * transformation should be aggregated and computed in a loop. | |
563 * It can get intereset of higher hit rate of cache. | |
564 * - shapes prvoide list of positions needed to be transformed. | |
565 * - redraw_man transforms positions from shapes. | |
566 * - shapes drawing with result of transforms. | |
567 * - shapes should be called to give them a chance to update geometries. | |
568 */ | |
569 | |
13 | 570 /* |
571 * functions: | |
572 * - redraw all | |
573 * - redraw changed | |
574 */ | |
575 | |
12 | 576 #ifdef UNITTEST |
577 | |
578 #include <CUnit/Basic.h> | |
579 | |
580 struct _sh_dummy { | |
581 shape_t shape; | |
582 co_aix x, y; | |
583 co_aix w, h; | |
584 }; | |
585 typedef struct _sh_dummy sh_dummy_t; | |
586 | |
587 shape_t *sh_dummy_new(co_aix x, co_aix y, co_aix w, co_aix h) { | |
588 sh_dummy_t *dummy; | |
589 | |
590 dummy = (sh_dummy_t *)malloc(sizeof(sh_dummy_t)); | |
591 if(dummy == NULL) | |
592 return NULL; | |
593 | |
594 dummy->x = x; | |
595 dummy->y = y; | |
596 dummy->w = w; | |
597 dummy->h = h; | |
598 | |
599 return (shape_t *)dummy; | |
600 } | |
601 | |
602 void sh_dummy_free(shape_t *sh) { | |
603 free(sh); | |
604 } | |
605 | |
606 void sh_dummy_transform(shape_t *shape) { | |
607 sh_dummy_t *dummy = (sh_dummy_t *)shape; | |
608 co_aix poses[2][2]; | |
609 co_aix x1, y1, x2, y2; | |
610 | |
611 if(shape->geo && shape->coord) { | |
612 x1 = dummy->x; | |
613 y1 = dummy->y; | |
614 x2 = x1 + dummy->w; | |
615 y2 = y1 + dummy->h; | |
616 | |
617 coord_trans_pos(shape->coord, &x1, &y1); | |
618 coord_trans_pos(shape->coord, &x2, &y2); | |
619 poses[0][0] = x1; | |
620 poses[0][1] = y1; | |
621 poses[1][0] = x2; | |
622 poses[1][1] = y2; | |
623 | |
624 geo_init(shape->geo, 2, poses); | |
625 } | |
626 } | |
627 | |
628 void test_rdman_find_overlaid_shapes(void) { | |
629 redraw_man_t rdman; | |
630 geo_t geo; | |
631 coord_t *coords[3]; | |
632 shape_t *shapes[5]; | |
633 geo_t **overlays; | |
13 | 634 co_aix pos[2][2]; |
12 | 635 int n; |
636 int i; | |
637 | |
15
c2ce186a5c37
X_main uses rdman_redraw_all()
Thinker K.F. Li <thinker@branda.to>
parents:
14
diff
changeset
|
638 redraw_man_init(&rdman, NULL); |
12 | 639 coords[0] = rdman.root_coord; |
640 for(i = 1; i < 3; i++) { | |
641 coords[i] = rdman_coord_new(&rdman, rdman.root_coord); | |
642 } | |
643 for(i = 0; i < 5; i++) { | |
644 shapes[i] = sh_dummy_new(10 + i * 30, 10 + i * 20, 25, 15); | |
645 CU_ASSERT(shapes[i] != NULL); | |
646 } | |
647 for(i = 0; i < 3; i++) | |
648 rdman_add_shape(&rdman, shapes[i], coords[1]); | |
649 for(i = 3; i < 5; i++) | |
650 rdman_add_shape(&rdman, shapes[i], coords[2]); | |
651 | |
652 coords[1]->matrix[0] = 2; | |
653 coords[0]->matrix[4] = 2; | |
654 | |
655 update_aggr_matrix(coords[0]); | |
656 for(i = 0; i < 5; i++) | |
657 sh_dummy_transform(shapes[i]); | |
658 | |
13 | 659 pos[0][0] = 100; |
660 pos[0][1] = 120; | |
661 pos[1][0] = 100 + 140; | |
662 pos[1][1] = 120 + 40; | |
663 geo_init(&geo, 2, pos); | |
12 | 664 |
665 n = rdman_find_overlaid_shapes(&rdman, &geo, &overlays); | |
666 CU_ASSERT(n == 2); | |
667 CU_ASSERT(overlays != NULL); | |
668 CU_ASSERT(overlays[0] == shapes[2]->geo); | |
669 CU_ASSERT(overlays[1] == shapes[3]->geo); | |
670 | |
671 free(overlays); | |
672 for(i = 0; i < 5; i++) | |
673 sh_dummy_free(shapes[i]); | |
674 | |
675 redraw_man_destroy(&rdman); | |
676 } | |
677 | |
678 CU_pSuite get_redraw_man_suite(void) { | |
679 CU_pSuite suite; | |
680 | |
681 suite = CU_add_suite("Suite_redraw_man", NULL, NULL); | |
682 CU_ADD_TEST(suite, test_rdman_find_overlaid_shapes); | |
683 | |
684 return suite; | |
685 } | |
686 | |
687 #endif /* UNITTEST */ |