2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Code for various operations on Regions and Rectangles
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>
25 void dumplist(struct GfxBase
*GfxBase
)
27 struct ChunkPool
*Pool
;
30 Pool
= (struct ChunkPool
*)GetHead(&PrivGBase(GfxBase
)->ChunkPoolList
);
34 struct ChunkExt
*ChunkE
;
37 kprintf("Pool N.%d - %ld Chunk Free\n", n
++, Pool
->NumChunkFree
);
39 ChunkE
= GetHead(&Pool
->ChunkList
);
43 kprintf(" Chunk N.%d\n", m
++);
44 ChunkE
= GetSucc(ChunkE
);
47 Pool
= (struct ChunkPool
*)GetSucc(Pool
);
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
)
68 Pool
= AllocMem(sizeof(struct ChunkPool
), MEMF_ANY
);
72 ReleaseSemaphore(&PrivGBase(GfxBase
)->regionsem
);
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
);
93 if (!--Pool
->NumChunkFree
)
96 ADDTAIL(&PrivGBase(GfxBase
)->ChunkPoolList
, 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
);
119 if (++Pool
->NumChunkFree
== SIZECHUNKBUF
)
121 FreeMem(Pool
, sizeof(struct ChunkPool
));
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
);
143 struct RegionRectangleExtChunk
*Chunk
;
145 Chunk
= _NewRegionRectangleExtChunk();
158 RRE
[SIZERECTBUF
- 1].RR
.Next
= NULL
; /* IMPORTANT !!! */
160 Chunk
->FirstChunk
= Chunk
;
164 if (RRE
->Counter
== SIZERECTBUF
- 1)
166 struct RegionRectangleExtChunk
*Chunk
;
168 Chunk
= _NewRegionRectangleExtChunk();
172 Chunk
->FirstChunk
= Chunk(RRE
)->FirstChunk
;
183 RRE
->RR
.Prev
= *LastRectPtr
;
185 (*LastRectPtr
)->Next
= &RRE
->RR
;
187 RRE
[SIZERECTBUF
- 1].RR
.Next
= NULL
; /* IMPORTANT !!! */
192 struct RegionRectangleExt
*Prev
= RRE
++;
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
;
220 RR
->Prev
->Next
= NULL
;
223 /* Is this the first rectangle in the chunk? */
226 /* If so then this chunk has to be deleted too */
227 NextChunk
= Chunk(RR
);
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
);
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
);
272 _DisposeRegionRectangleList(prev
->Next
, GfxBase
);
278 new->bounds
= src
->bounds
;
284 #define ADVANCE(nextbandptr, rr) \
286 if ((rr)->Next && MinY((rr)->Next) == MinY(rr)) \
291 *nextbandptr = (rr)->Next; \
296 #define NEWREG(prevptr, rr) \
298 rr = _NewRegionRectangle(prevptr, GfxBase); \
303 #define ADDRECT(minx, maxx) \
305 struct RegionRectangle *rr; \
306 NEWREG(DstPtr, rr); \
314 #define ADDRECTMERGE(minx, maxx) \
319 (MinY(*(DstPtr)) != MinY) || \
320 ((minx-1) > MaxX(*DstPtr)) \
323 ADDRECT((minx), (maxx)); \
326 if (MaxX(*DstPtr) < maxx) \
328 MaxX(*DstPtr) = maxx; \
332 #define DOBANDCHECKS(firstlastdst, lastdst, curdst) \
333 if (curdst != lastdst) \
337 firstlastdst = &Chunk(curdst)->FirstChunk->Rects[0].RR; \
338 DstBounds->MinY = MinY(firstlastdst); \
339 DstBounds->MinX = MinX(firstlastdst); \
340 DstBounds->MaxX = MaxX(curdst); \
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) \
358 MinX(_one) == MinX(_two) && \
359 MaxX(_one) == MaxX(_two) \
371 if (_one == lastdst->Next && !_two) \
373 LONG MaxY = MaxY(curdst); \
374 _one = firstlastdst; \
375 _DisposeRegionRectangleList(lastdst->Next, GfxBase); \
385 firstlastdst = lastdst->Next; \
388 firstlastdst = lastdst->Next; \
398 void dumprect(struct Rectangle
*rec
)
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
;
421 kprintf("Bounds: "); dumprect(®
->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
));
437 void dumpregionrectangles(struct RegionRectangle
*rr
)
442 kprintf("%p (prev: %p - next: %p): ", rr
, rr
->Prev
, rr
->Next
);
443 dumprect(&rr
->bounds
);
449 void dumpband(struct RegionRectangle
*rr
, LONG OffX
, LONG MinY
, LONG MaxY
)
456 r
.MinX
= MinX(rr
) + OffX
;
457 r
.MaxX
= MaxX(rr
) + OffX
;
460 kprintf("%p (prev: %p - next: %p): ", rr
, rr
->Prev
, rr
->Next
);
462 if (rr
->Next
&& MinY(rr
->Next
) == MinY(rr
)) rr
= rr
->Next
; else break;
477 struct RegionRectangle
*Src1
,
478 struct RegionRectangle
*Src2
,
479 struct RegionRectangle
**DstPtr
,
480 struct RegionRectangle
**NextSrc1Ptr
,
481 struct RegionRectangle
**NextSrc2Ptr
,
482 struct GfxBase
*GfxBase
487 if (MinX(Src1
) + OffX1
< MinX(Src2
) + OffX2
)
489 ADDRECTMERGE(MinX(Src1
) + OffX1
, MaxX(Src1
) + OffX1
);
490 ADVANCE(NextSrc1Ptr
, Src1
);
494 ADDRECTMERGE(MinX(Src2
) + OffX2
, MaxX(Src2
) + OffX2
);
495 ADVANCE(NextSrc2Ptr
, Src2
);
503 ADDRECTMERGE(MinX(Src1
) + OffX1
, MaxX(Src1
) + OffX1
);
504 ADVANCE(NextSrc1Ptr
, Src1
);
510 ADDRECTMERGE(MinX(Src2
) + OffX2
, MaxX(Src2
) + OffX2
);
511 ADVANCE(NextSrc2Ptr
, Src2
);
524 struct RegionRectangle
*Src1
,
525 struct RegionRectangle
*Src2
,
526 struct RegionRectangle
**DstPtr
,
527 struct RegionRectangle
**NextSrc1Ptr
,
528 struct RegionRectangle
**NextSrc2Ptr
,
529 struct GfxBase
*GfxBase
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
);
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
);
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
);
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
);
572 do ADVANCE(NextSrc1Ptr
, Src1
) while (Src1
);
575 while (Src2
) ADVANCE(NextSrc2Ptr
, Src2
);
587 struct RegionRectangle
*Src1
,
588 struct RegionRectangle
*Src2
,
589 struct RegionRectangle
**DstPtr
,
590 struct RegionRectangle
**NextSrc1Ptr
,
591 struct RegionRectangle
**NextSrc2Ptr
,
592 struct GfxBase
*GfxBase
598 MinX
= MinX(Src2
) + OffX2
;
602 if (MaxX(Src1
) + OffX1
< MinX
)
604 /* Subtrahend doesn't overlap minuend. Just skip it */
605 ADVANCE(NextSrc1Ptr
, Src1
);
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
);
621 MinX
= MinX(Src2
) + OffX2
;
625 /* Subtrahend doesn't extend beyond minuend, so advence to the next one */
626 ADVANCE(NextSrc1Ptr
, Src1
);
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
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
);
647 MinX
= MinX(Src2
) + OffX2
;
651 /* Subtrahend used up */
652 ADVANCE(NextSrc1Ptr
, Src1
);
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
);
668 MinX
= MinX(Src2
) + OffX2
;
674 do ADVANCE(NextSrc1Ptr
, Src1
) while (Src1
);
679 ADDRECT(MinX
, MaxX(Src2
) + OffX2
);
680 ADVANCE(NextSrc2Ptr
, Src2
);
683 MinX
= MinX(Src2
) + OffX2
;
691 BOOL _DoOperationBandBand
693 BandOperation
*Operation
,
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
;
712 LONG TopY1
= 0, TopY2
= 0;
714 FirstLastDst
= LastDst
= Dst
= *DstPtr
= NULL
;
722 TopY1
= MinY(Src1
) + OffY1
;
728 TopY2
= MinY(Src2
) + OffY2
;
735 MaxY
= MIN(MaxY(Src1
) + OffY1
, TopY2
- 1);
745 MaxY
= MIN(MaxY(Src2
) + OffY2
, TopY1
- 1);
754 MaxY
= MIN(MaxY(Src1
) + OffY1
, MaxY(Src2
) + OffY2
);
755 TopY1
= TopY2
= MaxY
+ 1;
761 NextSrc1Ptr
= (MaxY
== MaxY(Src1
) + OffY1
) ? &Src1
: NULL
;
762 NextSrc2Ptr
= (MaxY
== MaxY(Src2
) + OffY2
) ? &Src2
: NULL
;
772 NextSrc1Ptr
, NextSrc2Ptr
,
781 DOBANDCHECKS(FirstLastDst
, LastDst
, Dst
);
788 TopY1
= MinY(Src1
) + OffY1
;
790 NextSrc1Ptr
= (void *)~0;
798 TopY1
, MaxY(Src1
) + OffY1
,
810 DOBANDCHECKS(FirstLastDst
, LastDst
, Dst
);
816 TopY2
= MinY(Src2
) + OffY2
;
818 NextSrc2Ptr
= (void *)~0;
825 TopY2
, MaxY(Src2
) + OffY2
,
837 DOBANDCHECKS(FirstLastDst
, LastDst
, Dst
);
846 DstBounds
->MaxY
= MaxY(Dst
);
847 *DstPtr
= &Chunk(Dst
)->FirstChunk
->Rects
[0].RR
;
850 _DisposeRegionRectangleList(&Chunk(Dst
)->FirstChunk
->Rects
[0].RR
, GfxBase
);
860 #include <proto/graphics.h>
867 struct Region
*R1
= NewRegion();
868 struct Region
*R2
= NewRegion();
870 for (i
= 0; i
< 10; i
++)
874 struct Rectangle r
= {l
, 0, l
+11, 201};
875 OrRectRegion(R1
, &r
);
878 for (i
= 0; i
< 10; i
++)
882 struct Rectangle r
= {0, u
, 201, u
+11};
883 OrRectRegion(R2
, &r
);
886 for (i
= 0; i
<100000; i
++)
888 XorRegionRegion(R2
, R1
);