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