r4493@vps: verhaegs | 2007-04-19 14:44:00 -0400
[AROS.git] / rom / graphics / intregions.c
blob87a02f5f2aa4c0aade301baef451ebb2a75ad3ba
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code for various operations on Regions and Rectangles
6 Lang: English
7 */
10 #include <exec/types.h>
11 #include <exec/memory.h>
12 #include <graphics/regions.h>
13 #include <graphics/gfxbase.h>
14 #include <proto/exec.h>
15 #include <proto/graphics.h>
16 #include <proto/exec.h>
18 #include <clib/macros.h>
19 #include "intregions.h"
20 #include "graphics_intern.h"
22 #include <aros/debug.h>
24 #if DEBUG
25 void dumplist(struct GfxBase *GfxBase)
27 struct ChunkPool *Pool;
28 int n = 0;
30 Pool = (struct ChunkPool *)GetHead(&PrivGBase(GfxBase)->ChunkPoolList);
32 while (Pool)
34 struct ChunkExt *ChunkE;
35 int m = 0;
37 kprintf("Pool N.%d - %ld Chunk Free\n", n++, Pool->NumChunkFree);
39 ChunkE = GetHead(&Pool->ChunkList);
41 while (ChunkE)
43 kprintf(" Chunk N.%d\n", m++);
44 ChunkE = GetSucc(ChunkE);
47 Pool = (struct ChunkPool *)GetSucc(Pool);
50 #endif
52 inline struct RegionRectangleExtChunk *__NewRegionRectangleExtChunk
54 struct GfxBase *GfxBase
57 struct ChunkPool *Pool;
58 struct ChunkExt *ChunkE;
60 ObtainSemaphore(&PrivGBase(GfxBase)->regionsem);
62 Pool = (struct ChunkPool *)GetHead(&PrivGBase(GfxBase)->ChunkPoolList);
64 if (!Pool || !Pool->NumChunkFree)
66 int i;
68 Pool = AllocMem(sizeof(struct ChunkPool), MEMF_ANY);
70 if (!Pool)
72 ReleaseSemaphore(&PrivGBase(GfxBase)->regionsem);
74 return NULL;
77 NEWLIST(&Pool->ChunkList);
79 Pool->NumChunkFree = SIZECHUNKBUF;
81 for (i = 0; i < SIZECHUNKBUF; i++)
83 ADDTAIL(&Pool->ChunkList, &Pool->Chunks[i]);
86 ADDHEAD(&PrivGBase(GfxBase)->ChunkPoolList, Pool);
89 ChunkE = (struct ChunkExt *)GetHead(&Pool->ChunkList);
91 REMOVE(ChunkE);
93 if (!--Pool->NumChunkFree)
95 REMOVE(Pool);
96 ADDTAIL(&PrivGBase(GfxBase)->ChunkPoolList, Pool);
99 ChunkE->Owner = Pool;
101 ReleaseSemaphore(&PrivGBase(GfxBase)->regionsem);
103 return &ChunkE->Chunk;
107 void __DisposeRegionRectangleExtChunk
109 struct RegionRectangleExtChunk *Chunk,
110 struct GfxBase *GfxBase
113 struct ChunkPool *Pool = ((struct ChunkExt *)Chunk)->Owner;
115 ObtainSemaphore(&PrivGBase(GfxBase)->regionsem);
117 REMOVE(Pool);
119 if (++Pool->NumChunkFree == SIZECHUNKBUF)
121 FreeMem(Pool, sizeof(struct ChunkPool));
123 else
125 ADDHEAD(&PrivGBase(GfxBase)->ChunkPoolList, Pool);
126 ADDTAIL(&Pool->ChunkList, Chunk);
129 ReleaseSemaphore(&PrivGBase(GfxBase)->regionsem);
133 inline struct RegionRectangle *_NewRegionRectangle
135 struct RegionRectangle **LastRectPtr,
136 struct GfxBase *GfxBase
139 struct RegionRectangleExt *RRE = RRE(*LastRectPtr);
141 if (!RRE)
143 struct RegionRectangleExtChunk *Chunk;
145 Chunk = _NewRegionRectangleExtChunk();
147 if (Chunk)
149 RRE = Chunk->Rects;
152 if (RRE)
154 RRE->Counter = 0;
155 RRE->RR.Prev = NULL;
156 RRE->RR.Next = NULL;
158 RRE[SIZERECTBUF - 1].RR.Next = NULL; /* IMPORTANT !!! */
160 Chunk->FirstChunk = Chunk;
163 else
164 if (RRE->Counter == SIZERECTBUF - 1)
166 struct RegionRectangleExtChunk *Chunk;
168 Chunk = _NewRegionRectangleExtChunk();
170 if (Chunk)
172 Chunk->FirstChunk = Chunk(RRE)->FirstChunk;
173 RRE = Chunk->Rects;
175 else
177 RRE = NULL;
180 if (RRE)
182 RRE->Counter = 0;
183 RRE->RR.Prev = *LastRectPtr;
184 RRE->RR.Next = NULL;
185 (*LastRectPtr)->Next = &RRE->RR;
187 RRE[SIZERECTBUF - 1].RR.Next = NULL; /* IMPORTANT !!! */
190 else
192 struct RegionRectangleExt *Prev = RRE++;
194 RRE->RR.Next = NULL;
195 RRE->RR.Prev = &Prev->RR;
196 Prev->RR.Next = &RRE->RR;
198 RRE->Counter = Prev->Counter + 1;
201 return *LastRectPtr = (struct RegionRectangle *)RRE;
205 void _DisposeRegionRectangleList
207 struct RegionRectangle *RR,
208 struct GfxBase *GfxBase
211 struct RegionRectangleExtChunk *NextChunk;
213 if (!RR)
215 return;
218 if (RR->Prev)
220 RR->Prev->Next = NULL;
223 /* Is this the first rectangle in the chunk? */
224 if (!Counter(RR))
226 /* If so then this chunk has to be deleted too */
227 NextChunk = Chunk(RR);
229 else
231 /* otherwise dispose all the chunks starting from the one after this one */
232 RR = &Chunk(RR)->Rects[SIZERECTBUF - 1].RR;
233 NextChunk = Chunk(RR->Next);
234 RR->Next = NULL;
237 while (NextChunk)
239 struct RegionRectangleExtChunk *OldChunk = NextChunk;
241 NextChunk = Chunk(NextChunk->Rects[SIZERECTBUF - 1].RR.Next);
243 _DisposeRegionRectangleExtChunk(OldChunk);
248 Takes all the rectangles from src and linkes them with the rectangle
249 to which *dstptr points. *dstptr at the end will hold the pointer
250 to the LAST rectangle in the resulting list.
251 If the system runs out of memory the function will deallocate any allocated
252 memory and will return FALSE. TRUE, otherwise.
255 BOOL _LinkRegionRectangleList
257 struct RegionRectangle *src,
258 struct RegionRectangle **dstptr,
259 struct GfxBase *GfxBase
262 struct RegionRectangle *prev = *dstptr;
264 for (; src; src = src->Next)
266 struct RegionRectangle *new = _NewRegionRectangle(dstptr, GfxBase);
268 if (!new)
270 if (prev)
272 _DisposeRegionRectangleList(prev->Next, GfxBase);
275 return FALSE;
278 new->bounds = src->bounds;
281 return TRUE;
284 #define ADVANCE(nextbandptr, rr) \
286 if ((rr)->Next && MinY((rr)->Next) == MinY(rr)) \
287 rr = (rr)->Next; \
288 else \
290 if (nextbandptr) \
291 *nextbandptr = (rr)->Next; \
292 rr = NULL; \
296 #define NEWREG(prevptr, rr) \
298 rr = _NewRegionRectangle(prevptr, GfxBase); \
299 if (!rr) \
300 return FALSE; \
303 #define ADDRECT(minx, maxx) \
305 struct RegionRectangle *rr; \
306 NEWREG(DstPtr, rr); \
308 MinX(rr) = minx; \
309 MinY(rr) = MinY; \
310 MaxX(rr) = maxx; \
311 MaxY(rr) = MaxY; \
314 #define ADDRECTMERGE(minx, maxx) \
316 if \
318 !*(DstPtr) || \
319 (MinY(*(DstPtr)) != MinY) || \
320 ((minx-1) > MaxX(*DstPtr)) \
323 ADDRECT((minx), (maxx)); \
325 else \
326 if (MaxX(*DstPtr) < maxx) \
328 MaxX(*DstPtr) = maxx; \
332 #define DOBANDCHECKS(firstlastdst, lastdst, curdst) \
333 if (curdst != lastdst) \
335 if (!lastdst) \
337 firstlastdst = &Chunk(curdst)->FirstChunk->Rects[0].RR; \
338 DstBounds->MinY = MinY(firstlastdst); \
339 DstBounds->MinX = MinX(firstlastdst); \
340 DstBounds->MaxX = MaxX(curdst); \
342 else \
344 if (DstBounds->MinX > MinX(lastdst->Next)) \
345 DstBounds->MinX = MinX(lastdst->Next); \
346 if (DstBounds->MaxX < MaxX(curdst)) \
347 DstBounds->MaxX = MaxX(curdst); \
349 if (MaxY(firstlastdst) == MinY(curdst) - 1) \
351 struct RegionRectangle *_one = firstlastdst; \
352 struct RegionRectangle *_two = lastdst->Next; \
354 while (_one != lastdst->Next && _two) \
356 if \
358 MinX(_one) == MinX(_two) && \
359 MaxX(_one) == MaxX(_two) \
362 _one = _one->Next; \
363 _two = _two->Next; \
365 else \
367 break; \
371 if (_one == lastdst->Next && !_two) \
373 LONG MaxY = MaxY(curdst); \
374 _one = firstlastdst; \
375 _DisposeRegionRectangleList(lastdst->Next, GfxBase); \
376 while (_one) \
378 MaxY(_one) = MaxY; \
379 _one = _one->Next; \
382 curdst = lastdst; \
384 else \
385 firstlastdst = lastdst->Next; \
387 else \
388 firstlastdst = lastdst->Next; \
390 lastdst = curdst; \
393 #if DOTEST
394 # define DEBUG 1
395 #endif
397 #if DEBUG
398 void dumprect(struct Rectangle *rec)
400 if (!rec)
402 kprintf("NULL\n");
403 return;
406 kprintf("(%d,%d)-(%d,%d)\n", (int)rec->MinX, (int)rec->MinY,
407 (int)rec->MaxX, (int)rec->MaxY);
411 void dumpregion(struct Region *reg)
413 struct RegionRectangle *rr;
415 if (!reg)
417 kprintf("NULL\n");
418 return;
421 kprintf("Bounds: "); dumprect(&reg->bounds);
423 for (rr = reg->RegionRectangle; rr;)
425 struct RegionRectangle *rr2 = rr;
427 kprintf(" Band: MinY = %d - %p\n", (int)MinY(rr), rr);
430 kprintf("\t");dumprect(Bounds(rr2));
431 ADVANCE(&rr, rr2);
432 } while (rr2);
437 void dumpregionrectangles(struct RegionRectangle *rr)
440 while (rr)
442 kprintf("%p (prev: %p - next: %p): ", rr, rr->Prev, rr->Next);
443 dumprect(&rr->bounds);
444 rr = rr->Next;
449 void dumpband(struct RegionRectangle *rr, LONG OffX, LONG MinY, LONG MaxY)
451 if (rr)
453 while (1)
455 struct Rectangle r;
456 r.MinX = MinX(rr) + OffX;
457 r.MaxX = MaxX(rr) + OffX;
458 r.MinY = MinY;
459 r.MaxY = MaxY;
460 kprintf("%p (prev: %p - next: %p): ", rr, rr->Prev, rr->Next);
461 dumprect(&r);
462 if (rr->Next && MinY(rr->Next) == MinY(rr)) rr = rr->Next; else break;
465 else
466 kprintf("\n");
468 #endif
471 BOOL _OrBandBand
473 LONG OffX1,
474 LONG OffX2,
475 LONG MinY,
476 LONG MaxY,
477 struct RegionRectangle *Src1,
478 struct RegionRectangle *Src2,
479 struct RegionRectangle **DstPtr,
480 struct RegionRectangle **NextSrc1Ptr,
481 struct RegionRectangle **NextSrc2Ptr,
482 struct GfxBase *GfxBase
485 while (Src1 && Src2)
487 if (MinX(Src1) + OffX1 < MinX(Src2) + OffX2)
489 ADDRECTMERGE(MinX(Src1) + OffX1, MaxX(Src1) + OffX1);
490 ADVANCE(NextSrc1Ptr, Src1);
492 else
494 ADDRECTMERGE(MinX(Src2) + OffX2, MaxX(Src2) + OffX2);
495 ADVANCE(NextSrc2Ptr, Src2);
499 if (Src1)
503 ADDRECTMERGE(MinX(Src1) + OffX1, MaxX(Src1) + OffX1);
504 ADVANCE(NextSrc1Ptr, Src1);
505 } while (Src1);
507 else
508 while (Src2)
510 ADDRECTMERGE(MinX(Src2) + OffX2, MaxX(Src2) + OffX2);
511 ADVANCE(NextSrc2Ptr, Src2);
514 return TRUE;
518 BOOL _AndBandBand
520 LONG OffX1,
521 LONG OffX2,
522 LONG MinY,
523 LONG MaxY,
524 struct RegionRectangle *Src1,
525 struct RegionRectangle *Src2,
526 struct RegionRectangle **DstPtr,
527 struct RegionRectangle **NextSrc1Ptr,
528 struct RegionRectangle **NextSrc2Ptr,
529 struct GfxBase *GfxBase
532 while (Src1 && Src2)
534 if (MinX(Src1) + OffX1 < MinX(Src2) + OffX2)
536 if (MaxX(Src1) + OffX1 >= MaxX(Src2) + OffX2)
538 /* Src1 totally covers Src2 */
539 ADDRECT(MinX(Src2) + OffX2, MaxX(Src2) + OffX2);
540 ADVANCE(NextSrc2Ptr, Src2);
542 else
544 if (MaxX(Src1) + OffX1 >= MinX(Src2) + OffX2)
545 /* Src1 partially covers Src2 */
546 ADDRECT(MinX(Src2) + OffX2, MaxX(Src1) + OffX1);
548 ADVANCE(NextSrc1Ptr, Src1);
551 else
553 if (MaxX(Src2) + OffX2 >= MaxX(Src1) + OffX1)
555 /* Src2 totally covers Src1 */
556 ADDRECT(MinX(Src1) + OffX1, MaxX(Src1) + OffX1);
557 ADVANCE(NextSrc1Ptr, Src1);
559 else
561 if (MaxX(Src2) + OffX2 >= MinX(Src1) + OffX1)
562 /* Src2 partially covers Src1 */
563 ADDRECT(MinX(Src1) + OffX1, MaxX(Src2) + OffX2);
565 ADVANCE(NextSrc2Ptr, Src2);
570 if (Src1)
572 do ADVANCE(NextSrc1Ptr, Src1) while (Src1);
574 else
575 while (Src2) ADVANCE(NextSrc2Ptr, Src2);
577 return TRUE;
581 BOOL _ClearBandBand
583 LONG OffX1,
584 LONG OffX2,
585 LONG MinY,
586 LONG MaxY,
587 struct RegionRectangle *Src1,
588 struct RegionRectangle *Src2,
589 struct RegionRectangle **DstPtr,
590 struct RegionRectangle **NextSrc1Ptr,
591 struct RegionRectangle **NextSrc2Ptr,
592 struct GfxBase *GfxBase
595 LONG MinX = 0;
597 if (Src2)
598 MinX = MinX(Src2) + OffX2;
600 while (Src1 && Src2)
602 if (MaxX(Src1) + OffX1 < MinX)
604 /* Subtrahend doesn't overlap minuend. Just skip it */
605 ADVANCE(NextSrc1Ptr, Src1);
607 else
608 if (MinX(Src1) + OffX1 <= MinX)
610 /* Subtrahend precedes minuend: nuke left edge of minuend */
611 MinX = MaxX(Src1) + OffX1 + 1;
613 if (MinX > MaxX(Src2) + OffX2)
616 Subtrahend completely overlaps minuend, so advance
617 to the next minuend and reset MinX to its left
619 ADVANCE(NextSrc2Ptr, Src2);
620 if (Src2)
621 MinX = MinX(Src2) + OffX2;
623 else
625 /* Subtrahend doesn't extend beyond minuend, so advence to the next one */
626 ADVANCE(NextSrc1Ptr, Src1);
629 else
630 if (MinX(Src1) + OffX1 <= MaxX(Src2) + OffX2)
633 Subtrahend covers part of minuend.
634 Add uncovered part of minuend to the band and jump to the next
635 subtrahend
638 ADDRECT(MinX, MinX(Src1) + OffX1 - 1);
640 MinX = MaxX(Src1) + OffX1 + 1;
642 if (MinX > MaxX(Src2) + OffX2)
644 /*Minuend used up: advance to the next one */
645 ADVANCE(NextSrc2Ptr, Src2);
646 if (Src2)
647 MinX = MinX(Src2) + OffX2;
649 else
651 /* Subtrahend used up */
652 ADVANCE(NextSrc1Ptr, Src1);
655 else
658 Minuend used up: add any remaining piece before advancing.
661 if (MaxX(Src2) + OffX2 >= MinX)
663 ADDRECT(MinX, MaxX(Src2) + OffX2);
666 ADVANCE(NextSrc2Ptr, Src2);
667 if (Src2)
668 MinX = MinX(Src2) + OffX2;
672 if (Src1)
674 do ADVANCE(NextSrc1Ptr, Src1) while (Src1);
676 else
677 while (Src2)
679 ADDRECT(MinX, MaxX(Src2) + OffX2);
680 ADVANCE(NextSrc2Ptr, Src2);
681 if (Src2)
683 MinX = MinX(Src2) + OffX2;
687 return TRUE;
691 BOOL _DoOperationBandBand
693 BandOperation *Operation,
694 LONG OffX1,
695 LONG OffX2,
696 LONG OffY1,
697 LONG OffY2,
698 struct RegionRectangle *Src1,
699 struct RegionRectangle *Src2,
700 struct RegionRectangle **DstPtr,
701 struct Rectangle *DstBounds,
702 struct GfxBase *GfxBase
705 struct RegionRectangle *Dst, *LastDst, *FirstLastDst;
706 struct RegionRectangle **NextSrc1Ptr = (void *)~0;
707 struct RegionRectangle **NextSrc2Ptr = (void *)~0;
708 struct RegionRectangle *Band1 = Src1, *Band2 = Src2;
710 BOOL res = TRUE;
712 LONG TopY1 = 0, TopY2 = 0;
714 FirstLastDst = LastDst = Dst = *DstPtr = NULL;
716 while (Src1 && Src2)
718 LONG MinY, MaxY;
720 if (NextSrc1Ptr)
722 TopY1 = MinY(Src1) + OffY1;
723 NextSrc1Ptr = NULL;
726 if (NextSrc2Ptr)
728 TopY2 = MinY(Src2) + OffY2;
729 NextSrc2Ptr = NULL;
732 if (TopY1 < TopY2)
734 MinY = TopY1;
735 MaxY = MIN(MaxY(Src1) + OffY1, TopY2 - 1);
736 TopY1 = MaxY + 1;
738 Band1 = Src1;
739 Band2 = NULL;
741 else
742 if (TopY2 < TopY1)
744 MinY = TopY2;
745 MaxY = MIN(MaxY(Src2) + OffY2, TopY1 - 1);
746 TopY2 = MaxY + 1;
748 Band1 = NULL;
749 Band2 = Src2;
751 else
753 MinY = TopY1;
754 MaxY = MIN(MaxY(Src1) + OffY1, MaxY(Src2) + OffY2);
755 TopY1 = TopY2 = MaxY + 1;
757 Band1 = Src1;
758 Band2 = Src2;
761 NextSrc1Ptr = (MaxY == MaxY(Src1) + OffY1) ? &Src1 : NULL;
762 NextSrc2Ptr = (MaxY == MaxY(Src2) + OffY2) ? &Src2 : NULL;
766 !Operation
768 OffX1, OffX2,
769 MinY, MaxY,
770 Band1, Band2,
771 &Dst,
772 NextSrc1Ptr, NextSrc2Ptr,
773 GfxBase
777 res = FALSE;
778 goto end;
781 DOBANDCHECKS(FirstLastDst, LastDst, Dst);
785 while (Src1)
787 if (NextSrc1Ptr)
788 TopY1 = MinY(Src1) + OffY1;
790 NextSrc1Ptr = (void *)~0;
795 !Operation
797 OffX1, OffX2,
798 TopY1, MaxY(Src1) + OffY1,
799 Src1, NULL,
800 &Dst,
801 &Src1, NULL,
802 GfxBase
806 res = FALSE;
807 goto end;
810 DOBANDCHECKS(FirstLastDst, LastDst, Dst);
813 while (Src2)
815 if (NextSrc2Ptr)
816 TopY2 = MinY(Src2) + OffY2;
818 NextSrc2Ptr = (void *)~0;
822 !Operation
824 OffX1, OffX2,
825 TopY2, MaxY(Src2) + OffY2,
826 NULL, Src2,
827 &Dst,
828 NULL, &Src2,
829 GfxBase
833 res = FALSE;
834 goto end;
837 DOBANDCHECKS(FirstLastDst, LastDst, Dst);
840 end:
842 if (Dst)
844 if (res)
846 DstBounds->MaxY = MaxY(Dst);
847 *DstPtr = &Chunk(Dst)->FirstChunk->Rects[0].RR;
849 else
850 _DisposeRegionRectangleList(&Chunk(Dst)->FirstChunk->Rects[0].RR, GfxBase);
853 return res;
857 #if DOTEST
859 #undef GfxBase
860 #include <proto/graphics.h>
863 int main(void)
865 int i;
867 struct Region *R1 = NewRegion();
868 struct Region *R2 = NewRegion();
870 for (i = 0; i < 10; i++)
872 int l = i*20;
874 struct Rectangle r = {l, 0, l+11, 201};
875 OrRectRegion(R1, &r);
878 for (i = 0; i < 10; i++)
880 int u = i*20;
882 struct Rectangle r = {0, u, 201, u+11};
883 OrRectRegion(R2, &r);
886 for (i = 0; i<100000; i++)
888 XorRegionRegion(R2, R1);
891 DisposeRegion(R2);
892 DisposeRegion(R1);
893 return 0;
896 #endif