aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/lib/engines/common/evas_tiler.c
diff options
context:
space:
mode:
authorDavid Walter Seikel2013-01-13 17:29:19 +1000
committerDavid Walter Seikel2013-01-13 17:29:19 +1000
commit07274513e984f0b5544586c74508ccd16e7dcafa (patch)
treeb32ff2a9136fbc1a4a6a0ed1e4d79cde0f5f16d9 /libraries/evas/src/lib/engines/common/evas_tiler.c
parentAdded Irrlicht 1.8, but without all the Windows binaries. (diff)
downloadSledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.zip
SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.gz
SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.bz2
SledjHamr-07274513e984f0b5544586c74508ccd16e7dcafa.tar.xz
Remove EFL, since it's been released now.
Diffstat (limited to 'libraries/evas/src/lib/engines/common/evas_tiler.c')
-rw-r--r--libraries/evas/src/lib/engines/common/evas_tiler.c1439
1 files changed, 0 insertions, 1439 deletions
diff --git a/libraries/evas/src/lib/engines/common/evas_tiler.c b/libraries/evas/src/lib/engines/common/evas_tiler.c
deleted file mode 100644
index bc5e99c..0000000
--- a/libraries/evas/src/lib/engines/common/evas_tiler.c
+++ /dev/null
@@ -1,1439 +0,0 @@
1#include "evas_common.h"
2#ifdef EVAS_RECT_SPLIT
3
4static inline void rect_list_node_pool_set_max(int max);
5static inline void rect_list_node_pool_flush(void);
6static inline list_node_t *rect_list_node_pool_get(void);
7static inline void rect_list_node_pool_put(list_node_t *node);
8static inline void rect_init(rect_t *r, int x, int y, int w, int h);
9static inline void rect_list_append_node(list_t *rects, list_node_t *node);
10static inline void rect_list_append(list_t *rects, const rect_t r);
11static inline void rect_list_append_xywh(list_t *rects, int x, int y, int w, int h);
12static inline void rect_list_concat(list_t *rects, list_t *other);
13static inline list_node_t *rect_list_unlink_next(list_t *rects, list_node_t *parent_node);
14static inline void rect_list_del_next(list_t *rects, list_node_t *parent_node);
15static inline void rect_list_clear(list_t *rects);
16static inline void rect_list_del_split_strict(list_t *rects, const rect_t del_r);
17static inline void rect_list_add_split_strict(list_t *rects, list_node_t *node);
18static inline list_node_t *rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error);
19static inline void rect_list_merge_rects(list_t *rects, list_t *to_merge, int accepted_error);
20static inline void rect_list_add_split_fuzzy_and_merge(list_t *rects, list_node_t *node, int split_accepted_error, int merge_accepted_error);
21static inline void rect_print(const rect_t r);
22#if 0
23static inline void rect_list_print(const list_t rects);
24#endif
25
26static const list_node_t list_node_zeroed = { NULL };
27static const list_t list_zeroed = { NULL, NULL };
28
29typedef struct list_node_pool
30{
31 list_node_t *node;
32 int len;
33 int max;
34} list_node_pool_t;
35
36static list_node_pool_t list_node_pool = { NULL, 0, 1024 };
37
38static inline void
39rect_list_node_pool_set_max(int max)
40{
41 int diff;
42
43 diff = list_node_pool.len - max;
44 for (; diff > 0 && list_node_pool.node; diff--)
45 {
46 list_node_t *node;
47
48 node = list_node_pool.node;
49 list_node_pool.node = node->next;
50 list_node_pool.len--;
51
52 free(node);
53 }
54
55 list_node_pool.max = max;
56}
57
58static inline void
59rect_list_node_pool_flush(void)
60{
61 while (list_node_pool.node)
62 {
63 list_node_t *node;
64
65 node = list_node_pool.node;
66 list_node_pool.node = node->next;
67 list_node_pool.len--;
68
69 free(node);
70 }
71}
72
73static inline list_node_t *
74rect_list_node_pool_get(void)
75{
76 if (list_node_pool.node)
77 {
78 list_node_t *node;
79
80 node = list_node_pool.node;
81 list_node_pool.node = node->next;
82 list_node_pool.len--;
83
84 return node;
85 }
86 else return malloc(sizeof(rect_node_t));
87}
88
89static inline void
90rect_list_node_pool_put(list_node_t *node)
91{
92 if (list_node_pool.len < list_node_pool.max)
93 {
94 node->next = list_node_pool.node;
95 list_node_pool.node = node;
96 list_node_pool.len++;
97 }
98 else free(node);
99}
100
101static inline void
102rect_init(rect_t *r, int x, int y, int w, int h)
103{
104 r->area = w * h;
105
106 r->left = x;
107 r->top = y;
108
109 r->right = x + w;
110 r->bottom = y + h;
111
112 r->width = w;
113 r->height = h;
114}
115
116static inline void
117rect_print(const rect_t r)
118{
119 INF("<rect(%d, %d, %d, %d)>", r.left, r.top, r.width, r.height);
120}
121
122#if 0
123static inline void
124rect_list_print(const list_t rects)
125{
126 list_node_t *node;
127 int len;
128
129 len = 0;
130 for (node = rects.head; node; node = node->next) len++;
131
132 putchar('[');
133 for (node = rects.head; node; node = node->next)
134 {
135 rect_print(((rect_node_t *)node)->rect);
136 if (node->next)
137 {
138 putchar(',');
139 if (len < 4) putchar(' ');
140 else
141 {
142 putchar('\n');
143 putchar(' ');
144 }
145 }
146 }
147 putchar(']');
148}
149#endif
150
151static inline void
152rect_list_append_node(list_t *rects, list_node_t *node)
153{
154 if (rects->tail)
155 {
156 rects->tail->next = node;
157 rects->tail = node;
158 }
159 else
160 {
161 rects->head = node;
162 rects->tail = node;
163 }
164}
165
166static inline void
167rect_list_append(list_t *rects, const rect_t r)
168{
169 rect_node_t *rect_node;
170
171 rect_node = (rect_node_t *)rect_list_node_pool_get();
172 rect_node->rect = r;
173 rect_node->_lst = list_node_zeroed;
174
175 rect_list_append_node(rects, (list_node_t *)rect_node);
176}
177
178static inline void
179rect_list_append_xywh(list_t *rects, int x, int y, int w, int h)
180{
181 rect_t r;
182
183 rect_init(&r, x, y, w, h);
184 rect_list_append(rects, r);
185}
186
187static inline void
188rect_list_concat(list_t *rects, list_t *other)
189{
190 if (!other->head)
191 return;
192
193 if (rects->tail)
194 {
195 rects->tail->next = other->head;
196 rects->tail = other->tail;
197 }
198 else
199 {
200 rects->head = other->head;
201 rects->tail = other->tail;
202 }
203 *other = list_zeroed;
204}
205
206static inline list_node_t *
207rect_list_unlink_next(list_t *rects, list_node_t *parent_node)
208{
209 list_node_t *node;
210
211 if (parent_node)
212 {
213 node = parent_node->next;
214 parent_node->next = node->next;
215 }
216 else
217 {
218 node = rects->head;
219 rects->head = node->next;
220 }
221
222 if (rects->tail == node) rects->tail = parent_node;
223 *node = list_node_zeroed;
224 return node;
225}
226
227static inline void
228rect_list_del_next(list_t *rects, list_node_t *parent_node)
229{
230 list_node_t *node;
231
232 node = rect_list_unlink_next(rects, parent_node);
233 rect_list_node_pool_put(node);
234}
235
236static inline void
237rect_list_clear(list_t *rects)
238{
239 list_node_t *node;
240
241 node = rects->head;
242 while (node)
243 {
244 list_node_t *aux;
245
246 aux = node->next;
247 rect_list_node_pool_put(node);
248 node = aux;
249 }
250 *rects = list_zeroed;
251}
252
253static inline void
254_calc_intra_rect_area(const rect_t a, const rect_t b, int *width, int *height)
255{
256 int max_left, min_right, max_top, min_bottom;
257
258 if (a.left < b.left) max_left = b.left;
259 else max_left = a.left;
260
261 if (a.right < b.right) min_right = a.right;
262 else min_right = b.right;
263
264 *width = min_right - max_left;
265
266 if (a.top < b.top) max_top = b.top;
267 else max_top = a.top;
268
269 if (a.bottom < b.bottom) min_bottom = a.bottom;
270 else min_bottom = b.bottom;
271
272 *height = min_bottom - max_top;
273}
274
275static inline void
276_split_strict(list_t *dirty, const rect_t current, rect_t r)
277{
278 int h_1, h_2, w_1, w_2;
279
280 h_1 = current.top - r.top;
281 h_2 = r.bottom - current.bottom;
282 w_1 = current.left - r.left;
283 w_2 = r.right - current.right;
284
285 if (h_1 > 0)
286 {
287 /* .--.r (b) .---.r2
288 * | | | |
289 * .-------.cur (a) .---.r '---'
290 * | | | | -> | | +
291 * | `--' | `---'
292 * `-------'
293 */
294 rect_list_append_xywh(dirty, r.left, r.top, r.width, h_1);
295 r.height -= h_1;
296 r.top = current.top;
297 }
298
299 if (h_2 > 0)
300 {
301 /* .-------.cur (a)
302 * | .---. | .---.r
303 * | | | | -> | |
304 * `-------' `---' + .---.r2
305 * | | | |
306 * `---'r (b) `---'
307 */
308 rect_list_append_xywh(dirty, r.left, current.bottom, r.width, h_2);
309 r.height -= h_2;
310 }
311
312 if (w_1 > 0)
313 {
314 /* (b) r .----.cur (a)
315 * .--|-. | .--.r2 .-.r
316 * | | | | -> | | + | |
317 * `--|-' | `--' `-'
318 * `----'
319 */
320 rect_list_append_xywh(dirty, r.left, r.top, w_1, r.height);
321 /* not necessary to keep these, r (b) will be destroyed */
322 /* r.width -= w_1; */
323 /* r.left = current.left; */
324 }
325
326 if (w_2 > 0)
327 {
328 /* .----.cur (a)
329 * | |
330 * | .-|--.r (b) .-.r .--.r2
331 * | | | | -> | | + | |
332 * | `-|--' `-' `--'
333 * `----'
334 */
335 rect_list_append_xywh(dirty, current.right, r.top, w_2, r.height);
336 /* not necessary to keep this, r (b) will be destroyed */
337 /* r.width -= w_2; */
338 }
339}
340
341static inline void
342rect_list_del_split_strict(list_t *rects, const rect_t del_r)
343{
344 list_t modified = list_zeroed;
345 list_node_t *cur_node, *prev_node;
346
347 prev_node = NULL;
348 cur_node = rects->head;
349 while (cur_node)
350 {
351 int intra_width, intra_height;
352 rect_t current;
353
354 current = ((rect_node_t*)cur_node)->rect;
355
356 _calc_intra_rect_area(del_r, current, &intra_width, &intra_height);
357 if ((intra_width <= 0) || (intra_height <= 0))
358 {
359 /* .---.current .---.del_r
360 * | | | |
361 * `---+---.del_r `---+---.current
362 * | | | |
363 * `---' `---'
364 * no interception, nothing to do
365 */
366 prev_node = cur_node;
367 cur_node = cur_node->next;
368 }
369 else if ((intra_width == current.width) &&
370 (intra_height == current.height))
371 {
372 /* .-------.del_r
373 * | .---. |
374 * | | | |
375 * | `---'current
376 * `-------'
377 * current is contained, remove from rects
378 */
379 cur_node = cur_node->next;
380 rect_list_del_next(rects, prev_node);
381 }
382 else
383 {
384 _split_strict(&modified, del_r, current);
385 cur_node = cur_node->next;
386 rect_list_del_next(rects, prev_node);
387 }
388 }
389
390 rect_list_concat(rects, &modified);
391}
392
393static inline void
394rect_list_add_split_strict(list_t *rects, list_node_t *node)
395{
396 list_t dirty = list_zeroed;
397 list_t new_dirty = list_zeroed;
398 list_node_t *cur_node;
399
400 if (!rects->head)
401 {
402 rect_list_append_node(rects, node);
403 return;
404 }
405
406 rect_list_append_node(&dirty, node);
407
408 cur_node = rects->head;
409 while (dirty.head)
410 {
411 rect_t current;
412
413 if (!cur_node)
414 {
415 rect_list_concat(rects, &dirty);
416 break;
417 }
418
419 current = ((rect_node_t*)cur_node)->rect;
420
421 while (dirty.head)
422 {
423 int intra_width, intra_height;
424 rect_t r;
425
426 r = ((rect_node_t *)dirty.head)->rect;
427 _calc_intra_rect_area(r, current, &intra_width, &intra_height);
428 if ((intra_width == r.width) && (intra_height == r.height))
429 /* .-------.cur
430 * | .---.r|
431 * | | | |
432 * | `---' |
433 * `-------'
434 */
435 rect_list_del_next(&dirty, NULL);
436 else if ((intra_width <= 0) || (intra_height <= 0))
437 {
438 /* .---.cur .---.r
439 * | | | |
440 * `---+---.r `---+---.cur
441 * | | | |
442 * `---' `---'
443 */
444 list_node_t *tmp;
445 tmp = rect_list_unlink_next(&dirty, NULL);
446 rect_list_append_node(&new_dirty, tmp);
447 }
448 else
449 {
450 _split_strict(&new_dirty, current, r);
451 rect_list_del_next(&dirty, NULL);
452 }
453 }
454 dirty = new_dirty;
455 new_dirty = list_zeroed;
456
457 cur_node = cur_node->next;
458 }
459}
460
461static inline void
462_calc_intra_outer_rect_area(const rect_t a, const rect_t b,
463 rect_t *intra, rect_t *outer)
464{
465 int min_left, max_left, min_right, max_right;
466 int min_top, max_top, min_bottom, max_bottom;
467
468 if (a.left < b.left)
469 {
470 max_left = b.left;
471 min_left = a.left;
472 }
473 else
474 {
475 max_left = a.left;
476 min_left = b.left;
477 }
478
479 if (a.right < b.right)
480 {
481 min_right = a.right;
482 max_right = b.right;
483 }
484 else
485 {
486 min_right = b.right;
487 max_right = a.right;
488 }
489
490 intra->left = max_left;
491 intra->right = min_right;
492 intra->width = min_right - max_left;
493
494 outer->left = min_left;
495 outer->right = max_right;
496 outer->width = max_right - min_left;
497
498 if (a.top < b.top)
499 {
500 max_top = b.top;
501 min_top = a.top;
502 }
503 else
504 {
505 max_top = a.top;
506 min_top = b.top;
507 }
508
509 if (a.bottom < b.bottom)
510 {
511 min_bottom = a.bottom;
512 max_bottom = b.bottom;
513 }
514 else
515 {
516 min_bottom = b.bottom;
517 max_bottom = a.bottom;
518 }
519
520 intra->top = max_top;
521 intra->bottom = min_bottom;
522 intra->height = min_bottom - max_top;
523 if ((intra->width > 0) && (intra->height > 0))
524 intra->area = intra->width * intra->height;
525 else
526 intra->area = 0;
527
528 outer->top = min_top;
529 outer->bottom = max_bottom;
530 outer->height = max_bottom - min_top;
531 outer->area = outer->width * outer->height;
532}
533
534enum
535{
536 SPLIT_FUZZY_ACTION_NONE,
537 SPLIT_FUZZY_ACTION_SPLIT,
538 SPLIT_FUZZY_ACTION_MERGE
539};
540
541static inline int
542_split_fuzzy(list_t *dirty, const rect_t a, rect_t *b)
543{
544 int h_1, h_2, w_1, w_2, action;
545
546 h_1 = a.top - b->top;
547 h_2 = b->bottom - a.bottom;
548 w_1 = a.left - b->left;
549 w_2 = b->right - a.right;
550
551 action = SPLIT_FUZZY_ACTION_NONE;
552
553 if (h_1 > 0)
554 {
555 /* .--.r (b) .---.r2
556 * | | | |
557 * .-------.cur (a) .---.r '---'
558 * | | | | -> | | +
559 * | `--' | `---'
560 * `-------'
561 */
562 rect_list_append_xywh(dirty, b->left, b->top, b->width, h_1);
563 b->height -= h_1;
564 b->top = a.top;
565 action = SPLIT_FUZZY_ACTION_SPLIT;
566 }
567
568 if (h_2 > 0)
569 {
570 /* .-------.cur (a)
571 * | .---. | .---.r
572 * | | | | -> | |
573 * `-------' `---' + .---.r2
574 * | | | |
575 * `---'r (b) `---'
576 */
577 rect_list_append_xywh(dirty, b->left, a.bottom, b->width, h_2);
578 b->height -= h_2;
579 action = SPLIT_FUZZY_ACTION_SPLIT;
580 }
581
582 if (((w_1 > 0) || (w_2 > 0)) && (a.height == b->height))
583 return SPLIT_FUZZY_ACTION_MERGE;
584
585 if (w_1 > 0)
586 {
587 /* (b) r .----.cur (a)
588 * .--|-. | .--.r2 .-.r
589 * | | | | -> | | + | |
590 * `--|-' | `--' `-'
591 * `----'
592 */
593 rect_list_append_xywh(dirty, b->left, b->top, w_1, b->height);
594 /* not necessary to keep these, r (b) will be destroyed */
595 /* b->width -= w_1; */
596 /* b->left = a.left; */
597 action = SPLIT_FUZZY_ACTION_SPLIT;
598 }
599
600 if (w_2 > 0)
601 {
602 /* .----.cur (a)
603 * | |
604 * | .-|--.r (b) .-.r .--.r2
605 * | | | | -> | | + | |
606 * | `-|--' `-' `--'
607 * `----'
608 */
609 rect_list_append_xywh(dirty, a.right, b->top, w_2, b->height);
610 /* not necessary to keep these, r (b) will be destroyed */
611 /* b->width -= w_2; */
612 action = SPLIT_FUZZY_ACTION_SPLIT;
613 }
614
615 return action;
616}
617
618static inline list_node_t *
619rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error)
620{
621 list_t dirty = list_zeroed;
622 list_node_t *old_last;
623
624 old_last = rects->tail;
625
626 if (!rects->head)
627 {
628 rect_list_append_node(rects, node);
629 return old_last;
630 }
631
632 rect_list_append_node(&dirty, node);
633 while (dirty.head)
634 {
635 list_node_t *d_node, *cur_node, *prev_cur_node;
636 int keep_dirty;
637 rect_t r;
638
639 d_node = rect_list_unlink_next(&dirty, NULL);
640 r = ((rect_node_t *)d_node)->rect;
641
642 prev_cur_node = NULL;
643 cur_node = rects->head;
644 keep_dirty = 1;
645 while (cur_node)
646 {
647 int area, action;
648 rect_t current, intra, outer;
649
650 current = ((rect_node_t *)cur_node)->rect;
651
652 _calc_intra_outer_rect_area(r, current, &intra, &outer);
653 area = current.area + r.area - intra.area;
654
655 if ((intra.width == r.width) && (intra.height == r.height))
656 {
657 /* .-------.cur
658 * | .---.r|
659 * | | | |
660 * | `---' |
661 * `-------'
662 */
663 keep_dirty = 0;
664 break;
665 }
666 else if ((intra.width == current.width) &&
667 (intra.height == current.height))
668 {
669 /* .-------.r
670 * | .---.cur
671 * | | | |
672 * | `---' |
673 * `-------'
674 */
675 if (old_last == cur_node)
676 old_last = prev_cur_node;
677 cur_node = cur_node->next;
678 rect_list_del_next(rects, prev_cur_node);
679 }
680 else if ((outer.area - area) <= accepted_error)
681 {
682 /* .-----------. bounding box (outer)
683 * |.---. .---.|
684 * ||cur| |r ||
685 * || | | ||
686 * |`---' `---'|
687 * `-----------'
688 * merge them, remove both and add merged
689 */
690 rect_node_t *n;
691
692 if (old_last == cur_node)
693 old_last = prev_cur_node;
694
695 n = (rect_node_t *)rect_list_unlink_next(rects, prev_cur_node);
696 n->rect = outer;
697 rect_list_append_node(&dirty, (list_node_t *)n);
698
699 keep_dirty = 0;
700 break;
701 }
702 else if (intra.area <= accepted_error)
703 {
704 /* .---.cur .---.r
705 * | | | |
706 * `---+---.r `---+---.cur
707 * | | | |
708 * `---' `---'
709 * no split, no merge
710 */
711 prev_cur_node = cur_node;
712 cur_node = cur_node->next;
713 }
714 else
715 {
716 /* split is required */
717 action = _split_fuzzy(&dirty, current, &r);
718 if (action == SPLIT_FUZZY_ACTION_MERGE)
719 {
720 /* horizontal merge is possible: remove both, add merged */
721 rect_node_t *n;
722
723 if (old_last == cur_node)
724 old_last = prev_cur_node;
725
726 n = (rect_node_t *)
727 rect_list_unlink_next(rects, prev_cur_node);
728
729 n->rect.left = outer.left;
730 n->rect.width = outer.width;
731 n->rect.right = outer.right;
732 n->rect.area = outer.width * r.height;
733 rect_list_append_node(&dirty, (list_node_t *)n);
734 }
735 else if (action == SPLIT_FUZZY_ACTION_NONE)
736 {
737 /*
738 * this rect check was totally useless,
739 * should never happen
740 */
741 /* prev_cur_node = cur_node; */
742 /* cur_node = cur_node->next; */
743 WRN("Should not get here!");
744 abort();
745 }
746
747 keep_dirty = 0;
748 break;
749 }
750 }
751
752 if (UNLIKELY(keep_dirty)) rect_list_append_node(rects, d_node);
753 else rect_list_node_pool_put(d_node);
754 }
755
756 return old_last;
757}
758
759static inline void
760_calc_outer_rect_area(const rect_t a, const rect_t b, rect_t *outer)
761{
762 int min_left, max_right;
763 int min_top, max_bottom;
764
765 if (a.left < b.left) min_left = a.left;
766 else min_left = b.left;
767
768 if (a.right < b.right) max_right = b.right;
769 else max_right = a.right;
770
771 outer->left = min_left;
772 outer->right = max_right;
773 outer->width = max_right - min_left;
774
775 if (a.top < b.top) min_top = a.top;
776 else min_top = b.top;
777
778 if (a.bottom < b.bottom) max_bottom = b.bottom;
779 else max_bottom = a.bottom;
780
781 outer->top = min_top;
782 outer->bottom = max_bottom;
783 outer->height = max_bottom - min_top;
784
785 outer->area = outer->width * outer->height;
786}
787
788static inline void
789rect_list_merge_rects(list_t *rects, list_t *to_merge, int accepted_error)
790{
791 while (to_merge->head)
792 {
793 list_node_t *node, *parent_node;
794 rect_t r1;
795 int merged;
796
797 r1 = ((rect_node_t *)to_merge->head)->rect;
798
799 merged = 0;
800 parent_node = NULL;
801 node = rects->head;
802 while (node)
803 {
804 rect_t r2, outer;
805 int area;
806
807 r2 = ((rect_node_t *)node)->rect;
808
809 _calc_outer_rect_area(r1, r2, &outer);
810 area = r1.area + r2.area; /* intra area is taken as 0 */
811 if (outer.area - area <= accepted_error)
812 {
813 /*
814 * remove both r1 and r2, create r3
815 * actually r3 uses r2 instance, saves memory
816 */
817 rect_node_t *n;
818
819 n = (rect_node_t *)rect_list_unlink_next(rects, parent_node);
820 n->rect = outer;
821 rect_list_append_node(to_merge, (list_node_t *)n);
822 merged = 1;
823 break;
824 }
825
826 parent_node = node;
827 node = node->next;
828 }
829
830 if (!merged)
831 {
832 list_node_t *n;
833 n = rect_list_unlink_next(to_merge, NULL);
834 rect_list_append_node(rects, n);
835 }
836 else
837 rect_list_del_next(to_merge, NULL);
838 }
839}
840
841static inline void
842rect_list_add_split_fuzzy_and_merge(list_t *rects,
843 list_node_t *node,
844 int split_accepted_error,
845 int merge_accepted_error)
846{
847 list_node_t *n;
848
849 n = rect_list_add_split_fuzzy(rects, node, split_accepted_error);
850 if (n && n->next)
851 {
852 list_t to_merge;
853
854 /* split list into 2 segments, already merged and to merge */
855 to_merge.head = n->next;
856 to_merge.tail = rects->tail;
857 rects->tail = n;
858 n->next = NULL;
859
860 rect_list_merge_rects(rects, &to_merge, merge_accepted_error);
861 }
862}
863#endif /* EVAS_RECT_SPLIT */
864
865#define TILE(tb, x, y) ((tb)->tiles.tiles[((y) * (tb)->tiles.w) + (x)])
866
867#ifdef RECTUPDATE
868#elif defined(EVAS_RECT_SPLIT)
869#else
870/*
871static int tilebuf_x_intersect(Tilebuf *tb, int x, int w, int *x1, int *x2, int *x1_fill, int *x2_fill);
872static int tilebuf_y_intersect(Tilebuf *tb, int y, int h, int *y1, int *y2, int *y1_fill, int *y2_fill);
873static int tilebuf_intersect(int tsize, int tlen, int tnum, int x, int w, int *x1, int *x2, int *x1_fill, int *x2_fill);
874 */
875#endif
876/*
877static void tilebuf_setup(Tilebuf *tb);
878 */
879
880EAPI void
881evas_common_tilebuf_init(void)
882{
883}
884
885EAPI Tilebuf *
886evas_common_tilebuf_new(int w, int h)
887{
888 Tilebuf *tb;
889
890 tb = calloc(1, sizeof(Tilebuf));
891 if (!tb) return NULL;
892
893 tb->tile_size.w = 8;
894 tb->tile_size.h = 8;
895 tb->outbuf_w = w;
896 tb->outbuf_h = h;
897
898 return tb;
899}
900
901EAPI void
902evas_common_tilebuf_free(Tilebuf *tb)
903{
904#ifdef RECTUPDATE
905/*
906 evas_common_regionbuf_free(tb->rb);
907 */
908#elif defined(EVAS_RECT_SPLIT)
909 rect_list_clear(&tb->rects);
910 rect_list_node_pool_flush();
911#else
912/*
913 if (tb->tiles.tiles) free(tb->tiles.tiles);
914 */
915#endif
916 free(tb);
917}
918
919EAPI void
920evas_common_tilebuf_set_tile_size(Tilebuf *tb, int tw, int th)
921{
922 tb->tile_size.w = tw;
923 tb->tile_size.h = th;
924/*
925 tilebuf_setup(tb);
926 */
927}
928
929EAPI void
930evas_common_tilebuf_get_tile_size(Tilebuf *tb, int *tw, int *th)
931{
932 if (tw) *tw = tb->tile_size.w;
933 if (th) *th = tb->tile_size.h;
934}
935
936#ifdef EVAS_RECT_SPLIT
937static inline int
938_add_redraw(list_t *rects, int x, int y, int w, int h)
939{
940 rect_node_t *rn;
941/* we dont need to do this fuzz stuff - it actually creates overdraw bugs
942 * when evas shouldnt draw at all.
943 x >>= 1;
944 y >>= 1;
945 w += 2;
946 w >>= 1;
947 h += 2;
948 h >>= 1;
949 */
950 rn = (rect_node_t *)rect_list_node_pool_get();
951 rn->_lst = list_node_zeroed;
952 rect_init(&rn->rect, x, y, w, h);
953 //INF("ACCOUNTING: add_redraw: %4d,%4d %3dx%3d", x, y, w, h);
954 //testing on my core2 duo desktop - fuzz of 32 or 48 is best.
955#define FUZZ 32
956 rect_list_add_split_fuzzy_and_merge(rects, (list_node_t *)rn,
957 FUZZ * FUZZ, FUZZ * FUZZ);
958 return 1;
959}
960#endif
961
962EAPI int
963evas_common_tilebuf_add_redraw(Tilebuf *tb, int x, int y, int w, int h)
964{
965#ifdef RECTUPDATE
966/*
967 int i;
968
969 if ((w <= 0) || (h <= 0)) return 0;
970 RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h);
971 if ((w <= 0) || (h <= 0)) return 0;
972 for (i = 0; i < h; i++)
973 evas_common_regionbuf_span_add(tb->rb, x, x + w - 1, y + i);
974 return 1;
975 */
976#elif defined(EVAS_RECT_SPLIT)
977 if ((w <= 0) || (h <= 0)) return 0;
978 RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h);
979 if ((w <= 0) || (h <= 0)) return 0;
980 // optimize a common case -> adding the exact same rect 2x in a row
981 if ((tb->prev_add.x == x) && (tb->prev_add.y == y) &&
982 (tb->prev_add.w == w) && (tb->prev_add.h == h)) return 1;
983 tb->prev_add.x = x; tb->prev_add.y = y;
984 tb->prev_add.w = w; tb->prev_add.h = h;
985 tb->prev_del.w = 0; tb->prev_del.h = 0;
986 return _add_redraw(&tb->rects, x, y, w, h);
987#else
988/*
989 int tx1, tx2, ty1, ty2, tfx1, tfx2, tfy1, tfy2, xx, yy;
990 int num;
991
992 if ((w <= 0) || (h <= 0)) return 0;
993 RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h);
994 if ((w <= 0) || (h <= 0)) return 0;
995 num = 0;
996 // wipes out any motion vectors in tiles it touches into redraws
997 if (tilebuf_x_intersect(tb, x, w, &tx1, &tx2, &tfx1, &tfx2) &&
998 tilebuf_y_intersect(tb, y, h, &ty1, &ty2, &tfy1, &tfy2))
999 {
1000 Tilebuf_Tile *tbt;
1001 int delta_x;
1002 int delta_y;
1003
1004 tbt = &(TILE(tb, tx1, ty1));
1005 delta_x = tx2 - tx1 + 1;
1006 delta_y = ty2 - ty1 + 1;
1007 for (yy = delta_y; yy > 0; yy--)
1008 {
1009 Tilebuf_Tile *tbti;
1010
1011 tbti = tbt;
1012 for (xx = delta_x; xx > 0; xx--)
1013 {
1014 tbti->redraw = 1;
1015 tbti++;
1016 }
1017 tbt += tb->tiles.w;
1018 }
1019 num = (tx2 - tx1 + 1) * (ty2 - ty1 + 1);
1020 }
1021 return num;
1022 */
1023#endif
1024}
1025
1026EAPI int
1027evas_common_tilebuf_del_redraw(Tilebuf *tb, int x, int y, int w, int h)
1028{
1029#ifdef RECTUPDATE
1030/*
1031 int i;
1032
1033 for (i = 0; i < h; i++)
1034 evas_common_regionbuf_span_del(tb->rb, x, x + w - 1, y + i);
1035 */
1036#elif defined(EVAS_RECT_SPLIT)
1037 rect_t r;
1038
1039 if (!tb->rects.head) return 0;
1040 if ((w <= 0) || (h <= 0)) return 0;
1041 RECTS_CLIP_TO_RECT(x, y, w, h, 0, 0, tb->outbuf_w, tb->outbuf_h);
1042 if ((w <= 0) || (h <= 0)) return 0;
1043
1044/* we dont need to do this fuzz stuff - it actually creates overdraw bugs
1045 * when evas shouldnt draw at all.
1046 x += 1;
1047 y += 1;
1048 x >>= 1;
1049 y >>= 1;
1050 w -= 1;
1051 w >>= 1;
1052 h -= 1;
1053 h >>= 1;
1054
1055 if ((w <= 0) || (h <= 0)) return 0;
1056 */
1057
1058 // optimize a common case -> deleting the exact same rect 2x in a row
1059 if ((tb->prev_del.x == x) && (tb->prev_del.y == y) &&
1060 (tb->prev_del.w == w) && (tb->prev_del.h == h)) return 1;
1061 tb->prev_del.x = x; tb->prev_del.y = y;
1062 tb->prev_del.w = w; tb->prev_del.h = h;
1063 tb->prev_add.w = 0; tb->prev_add.h = 0;
1064 rect_init(&r, x, y, w, h);
1065
1066 rect_list_del_split_strict(&tb->rects, r);
1067 tb->need_merge = 1;
1068 return 0;
1069#else
1070/*
1071 int tx1, tx2, ty1, ty2, tfx1, tfx2, tfy1, tfy2, xx, yy;
1072 int num;
1073
1074 num = 0;
1075 // wipes out any motion vectors in tiles it touches into redraws
1076 if (tilebuf_x_intersect(tb, x, w, &tx1, &tx2, &tfx1, &tfx2) &&
1077 tilebuf_y_intersect(tb, y, h, &ty1, &ty2, &tfy1, &tfy2))
1078 {
1079 Tilebuf_Tile *tbt;
1080 int delta_y;
1081 int delta_x;
1082
1083 if (!tfx1) tx1++;
1084 if (!tfx2) tx2--;
1085 if (!tfy1) ty1++;
1086 if (!tfy2) ty2--;
1087
1088 tbt = &(TILE(tb, tx1, ty1));
1089 delta_x = tx2 - tx1 + 1;
1090 delta_y = ty2 - ty1 + 1;
1091 for (yy = delta_y; yy > 0; yy--)
1092 {
1093 Tilebuf_Tile *tbti;
1094
1095 tbti = tbt;
1096 for (xx = delta_x; xx > 0; xx--)
1097 {
1098 tbti->redraw = 0;
1099 tbti++;
1100 }
1101 tbt += tb->tiles.w;
1102 }
1103 num = (tx2 - tx1 + 1) * (ty2 - ty1 + 1);
1104 }
1105 return num;
1106 */
1107#endif
1108}
1109
1110EAPI int
1111evas_common_tilebuf_add_motion_vector(Tilebuf *tb __UNUSED__, int x __UNUSED__, int y __UNUSED__, int w __UNUSED__, int h __UNUSED__, int dx __UNUSED__, int dy __UNUSED__, int alpha __UNUSED__)
1112{
1113#ifdef EVAS_RECT_SPLIT
1114/* motion vector handling never has been used -> disable it
1115 list_t lr = list_zeroed;
1116 int num;
1117
1118 num = _add_redraw(&lr, x, y, w, h);
1119 num += _add_redraw(&lr, x + dx, y + dy, w, h);
1120 while (lr.head)
1121 {
1122 list_node_t *node = rect_list_unlink_next(&lr, NULL);
1123 rect_list_add_split_fuzzy_and_merge(&tb->rects, node,
1124 FUZZ * FUZZ, FUZZ * FUZZ);
1125 }
1126 return num;
1127 */
1128 return 0;
1129#else
1130/*
1131 int num;
1132
1133 num = evas_common_tilebuf_add_redraw(tb, x, y, w, h);
1134 num += evas_common_tilebuf_add_redraw(tb, x + dx, y + dy, w, h);
1135 return num;
1136 */
1137#endif
1138}
1139
1140EAPI void
1141evas_common_tilebuf_clear(Tilebuf *tb)
1142{
1143#ifdef RECTUPDATE
1144/*
1145 evas_common_regionbuf_clear(tb->rb);
1146 */
1147#elif defined(EVAS_RECT_SPLIT)
1148 tb->prev_add.x = tb->prev_add.y = tb->prev_add.w = tb->prev_add.h = 0;
1149 tb->prev_del.x = tb->prev_del.y = tb->prev_del.w = tb->prev_del.h = 0;
1150 rect_list_clear(&tb->rects);
1151 tb->need_merge = 0;
1152#else
1153/*
1154 if (!tb->tiles.tiles) return;
1155 memset(tb->tiles.tiles, 0, tb->tiles.w * tb->tiles.h * sizeof(Tilebuf_Tile));
1156 */
1157#endif
1158}
1159
1160EAPI Tilebuf_Rect *
1161evas_common_tilebuf_get_render_rects(Tilebuf *tb)
1162{
1163#ifdef RECTUPDATE
1164/*
1165 return evas_common_regionbuf_rects_get(tb->rb);
1166 */
1167#elif defined(EVAS_RECT_SPLIT)
1168 list_node_t *n;
1169 Tilebuf_Rect *rects = NULL;
1170 int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0, num = 0;
1171
1172 if (tb->need_merge)
1173 {
1174 list_t to_merge;
1175 to_merge = tb->rects;
1176 tb->rects = list_zeroed;
1177 rect_list_merge_rects(&tb->rects, &to_merge, FUZZ * FUZZ);
1178 tb->need_merge = 0;
1179 }
1180
1181 n = tb->rects.head;
1182 if (n)
1183 {
1184 bx1 = ((rect_node_t *)n)->rect.left;
1185 bx2 = bx1 + ((rect_node_t *)n)->rect.width;
1186 by1 = ((rect_node_t *)n)->rect.top;
1187 by2 = by1 + ((rect_node_t *)n)->rect.height;
1188 n = n->next;
1189 for (; n; n = n->next)
1190 {
1191
1192 int x1, x2, y1, y2;
1193
1194 x1 = ((rect_node_t *)n)->rect.left;
1195 if (x1 < bx1) bx1 = x1;
1196 x2 = x1 + ((rect_node_t *)n)->rect.width;
1197 if (x2 > bx2) bx2 = x2;
1198
1199 y1 = ((rect_node_t *)n)->rect.top;
1200 if (y1 < by1) by1 = y1;
1201 y2 = y1 + ((rect_node_t *)n)->rect.height;
1202 if (y2 > by2) by2 = y2;
1203 num++;
1204 }
1205 }
1206#define MAXREG 24
1207 /* magic number - but if we have > MAXREG regions to update, take bounding box */
1208 if (num > MAXREG)
1209 {
1210 Tilebuf_Rect *r;
1211
1212 r = malloc(sizeof(Tilebuf_Rect));
1213 r->x = bx1;
1214 r->y = by1;
1215 r->w = bx2 - bx1;
1216 r->h = by2 - by1;
1217
1218 rects = (Tilebuf_Rect *)eina_inlist_append(EINA_INLIST_GET(rects), EINA_INLIST_GET(r));
1219 return rects;
1220 }
1221
1222 for (n = tb->rects.head; n; n = n->next)
1223 {
1224 rect_t cur;
1225
1226 cur = ((rect_node_t *)n)->rect;
1227/* disable fuzz - created bugs.
1228 cur.left <<= 1;
1229 cur.top <<= 1;
1230 cur.width <<= 1;
1231 cur.height <<= 1;
1232 */
1233 RECTS_CLIP_TO_RECT(cur.left, cur.top, cur.width, cur.height,
1234 0, 0, tb->outbuf_w, tb->outbuf_h);
1235 if ((cur.width > 0) && (cur.height > 0))
1236 {
1237 Tilebuf_Rect *r;
1238
1239 r = malloc(sizeof(Tilebuf_Rect));
1240 r->x = cur.left;
1241 r->y = cur.top;
1242 r->w = cur.width;
1243 r->h = cur.height;
1244
1245 rects = (Tilebuf_Rect *)eina_inlist_append(EINA_INLIST_GET(rects), EINA_INLIST_GET(r));
1246 }
1247 }
1248 return rects;
1249
1250#else
1251/*
1252 Tilebuf_Rect *rects = NULL;
1253 Tilebuf_Tile *tbt;
1254 int x, y;
1255
1256 tbt = &(TILE(tb, 0, 0));
1257 for (y = 0; y < tb->tiles.h; y++)
1258 {
1259 for (x = 0; x < tb->tiles.w; x++, tbt++)
1260 {
1261 if (tbt->redraw)
1262 {
1263 Tilebuf_Tile *tbti;
1264 int can_expand_x = 1, can_expand_y = 1;
1265 Tilebuf_Rect *r = NULL;
1266 int xx = 0, yy = 0;
1267 r = malloc(sizeof(Tilebuf_Rect));
1268 r->_list_data.next = NULL;
1269 r->_list_data.prev = NULL;
1270 r->_list_data.last = NULL;
1271
1272 // amalgamate tiles
1273#if 1
1274 tbti = tbt;
1275 while (can_expand_x)
1276 {
1277 tbti++;
1278 xx++;
1279 if ((x + xx) >= tb->tiles.w)
1280 can_expand_x = 0;
1281 else if (!(tbti->redraw))
1282 can_expand_x = 0;
1283 if (can_expand_x)
1284 tbti->redraw = 0;
1285 }
1286 tbti = tbt;
1287 while (can_expand_y)
1288 {
1289 int i;
1290
1291 tbti += tb->tiles.w;
1292 yy++;
1293 if ((y + yy) >= tb->tiles.h)
1294 can_expand_y = 0;
1295 if (can_expand_y)
1296 {
1297 Tilebuf_Tile *tbtj;
1298
1299 tbtj = tbti;
1300 for (i = x; i < x + xx; i++, tbtj++)
1301 {
1302 if (!(tbtj->redraw))
1303 {
1304 can_expand_y = 0;
1305 break;
1306 }
1307 }
1308 }
1309 if (can_expand_y)
1310 {
1311 Tilebuf_Tile *tbtj;
1312
1313 tbtj = tbti;
1314 for (i = x; i < x + xx; i++, tbtj++)
1315 tbtj->redraw = 0;
1316 }
1317 }
1318 tbt->redraw = 0;
1319#else
1320 xx = 1;
1321 yy = 1;
1322#endif
1323 r->x = x * tb->tile_size.w;
1324 r->y = y * tb->tile_size.h;
1325 r->w = (xx) * tb->tile_size.w;
1326 r->h = (yy) * tb->tile_size.h;
1327 rects = eina_inlist_append(rects, r);
1328 x = x + (xx - 1);
1329 tbt += xx - 1;
1330 }
1331 }
1332 }
1333 return rects;
1334 */
1335#endif
1336}
1337
1338EAPI void
1339evas_common_tilebuf_free_render_rects(Tilebuf_Rect *rects)
1340{
1341 while (rects)
1342 {
1343 Tilebuf_Rect *r;
1344
1345 r = rects;
1346 rects = (Tilebuf_Rect *)eina_inlist_remove(EINA_INLIST_GET(rects), EINA_INLIST_GET(r));
1347 free(r);
1348 }
1349}
1350
1351/* need a way of getting rectangles to: blit, re-render */
1352
1353
1354
1355
1356
1357/* internal usage */
1358/*
1359static void
1360tilebuf_setup(Tilebuf *tb)
1361{
1362 if ((tb->outbuf_w <= 0) || (tb->outbuf_h <= 0)) return;
1363#ifdef RECTUPDATE
1364 tb->rb = evas_common_regionbuf_new(tb->outbuf_w, tb->outbuf_h);
1365#elif defined(EVAS_RECT_SPLIT)
1366 tb->rects = list_zeroed;
1367#else
1368 if (tb->tiles.tiles) free(tb->tiles.tiles);
1369 tb->tiles.tiles = NULL;
1370
1371 tb->tiles.w = (tb->outbuf_w + (tb->tile_size.w - 1)) / tb->tile_size.w;
1372 tb->tiles.h = (tb->outbuf_h + (tb->tile_size.h - 1)) / tb->tile_size.h;
1373
1374 tb->tiles.tiles = malloc(tb->tiles.w * tb->tiles.h * sizeof(Tilebuf_Tile));
1375
1376 if (!tb->tiles.tiles)
1377 {
1378 tb->tiles.w = 0;
1379 tb->tiles.h = 0;
1380 return;
1381 }
1382 memset(tb->tiles.tiles, 0, tb->tiles.w * tb->tiles.h * sizeof(Tilebuf_Tile));
1383#endif
1384}
1385*/
1386
1387#ifdef RECTUPDATE
1388#elif defined(EVAS_RECT_SPLIT)
1389#else
1390/*
1391static int
1392tilebuf_x_intersect(Tilebuf *tb, int x, int w, int *x1, int *x2, int *x1_fill, int *x2_fill)
1393{
1394 return tilebuf_intersect(tb->tile_size.w, tb->outbuf_w, tb->tiles.w,
1395 x, w, x1, x2, x1_fill, x2_fill);
1396}
1397
1398static int
1399tilebuf_y_intersect(Tilebuf *tb, int y, int h, int *y1, int *y2, int *y1_fill, int *y2_fill)
1400{
1401 return tilebuf_intersect(tb->tile_size.h, tb->outbuf_h, tb->tiles.h,
1402 y, h, y1, y2, y1_fill, y2_fill);
1403}
1404
1405static int
1406tilebuf_intersect(int tsize, int tlen, int tnum, int x, int w, int *x1, int *x2, int *x1_fill, int *x2_fill)
1407{
1408 int p1, p2;
1409
1410 // initial clip out of region
1411 if ((x + w) <= 0) return 0;
1412 if (x >= tlen) return 0;
1413
1414 // adjust x & w so it all fits in region
1415 if (x < 0)
1416 {
1417 w += x;
1418 x = 0;
1419 }
1420 if (w < 0) return 0;
1421 if ((x + w) > tlen) w = tlen - x;
1422
1423 // now figure if the first edge is fully filling its tile
1424 p1 = (x) / tsize;
1425 if ((p1 * tsize) == (x)) *x1_fill = 1;
1426 else *x1_fill = 0;
1427 *x1 = p1;
1428
1429 // now figure if the last edge is fully filling its tile
1430 p2 = (x + w - 1) / tsize;
1431 if (((p2 + 1) * tsize) == (x + w)) *x2_fill = 1;
1432 else *x2_fill = 0;
1433 *x2 = p2;
1434
1435 return 1;
1436 tnum = 0;
1437}
1438*/
1439#endif