2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Code for various operations on Regions and Rectangles
9 #include <exec/memory.h>
10 #include <graphics/regions.h>
11 #include <graphics/gfxbase.h>
12 #include <proto/exec.h>
13 #include <proto/graphics.h>
14 #include <proto/exec.h>
15 #include <clib/macros.h>
17 #include "graphics_intern.h"
18 #include "intregions.h"
20 #include <aros/debug.h>
23 void dumplist(struct GfxBase
*GfxBase
)
25 struct ChunkPool
*Pool
;
28 Pool
= (struct ChunkPool
*)GetHead(&PrivGBase(GfxBase
)->ChunkPoolList
);
32 struct ChunkExt
*ChunkE
;
35 kprintf("Pool N.%d - %ld Chunk Free\n", n
++, Pool
->NumChunkFree
);
37 ChunkE
= (struct ChunkExt
*)GetHead(&Pool
->ChunkList
);
41 kprintf(" Chunk N.%d\n", m
++);
42 ChunkE
= (struct ChunkExt
*)GetSucc(ChunkE
);
45 Pool
= (struct ChunkPool
*)GetSucc(Pool
);
50 static inline struct RegionRectangleExtChunk
*__NewRegionRectangleExtChunk
52 struct GfxBase
*GfxBase
55 struct ChunkPool
*Pool
;
56 struct ChunkExt
*ChunkE
;
58 ObtainSemaphore(&PrivGBase(GfxBase
)->regionsem
);
60 Pool
= (struct ChunkPool
*)GetHead(&PrivGBase(GfxBase
)->ChunkPoolList
);
62 if (!Pool
|| !Pool
->NumChunkFree
)
66 Pool
= AllocMem(sizeof(struct ChunkPool
), MEMF_ANY
);
70 ReleaseSemaphore(&PrivGBase(GfxBase
)->regionsem
);
75 NEWLIST(&Pool
->ChunkList
);
77 Pool
->NumChunkFree
= SIZECHUNKBUF
;
79 for (i
= 0; i
< SIZECHUNKBUF
; i
++)
81 ADDTAIL(&Pool
->ChunkList
, &Pool
->Chunks
[i
]);
84 ADDHEAD(&PrivGBase(GfxBase
)->ChunkPoolList
, Pool
);
87 ChunkE
= (struct ChunkExt
*)GetHead(&Pool
->ChunkList
);
91 if (!--Pool
->NumChunkFree
)
94 ADDTAIL(&PrivGBase(GfxBase
)->ChunkPoolList
, Pool
);
99 ReleaseSemaphore(&PrivGBase(GfxBase
)->regionsem
);
101 return &ChunkE
->Chunk
;
105 void __DisposeRegionRectangleExtChunk
107 struct RegionRectangleExtChunk
*Chunk
,
108 struct GfxBase
*GfxBase
111 struct ChunkPool
*Pool
= ((struct ChunkExt
*)Chunk
)->Owner
;
113 ObtainSemaphore(&PrivGBase(GfxBase
)->regionsem
);
117 if (++Pool
->NumChunkFree
== SIZECHUNKBUF
)
119 FreeMem(Pool
, sizeof(struct ChunkPool
));
123 ADDHEAD(&PrivGBase(GfxBase
)->ChunkPoolList
, Pool
);
124 ADDTAIL(&Pool
->ChunkList
, Chunk
);
127 ReleaseSemaphore(&PrivGBase(GfxBase
)->regionsem
);
131 struct RegionRectangle
*_NewRegionRectangle
133 struct RegionRectangle
**LastRectPtr
,
134 struct GfxBase
*GfxBase
137 struct RegionRectangleExt
*RRE
= RRE(*LastRectPtr
);
141 struct RegionRectangleExtChunk
*Chunk
;
143 Chunk
= _NewRegionRectangleExtChunk();
156 RRE
[SIZERECTBUF
- 1].RR
.Next
= NULL
; /* IMPORTANT !!! */
158 Chunk
->FirstChunk
= Chunk
;
162 if (RRE
->Counter
== SIZERECTBUF
- 1)
164 struct RegionRectangleExtChunk
*Chunk
;
166 Chunk
= _NewRegionRectangleExtChunk();
170 Chunk
->FirstChunk
= Chunk(RRE
)->FirstChunk
;
181 RRE
->RR
.Prev
= *LastRectPtr
;
183 (*LastRectPtr
)->Next
= &RRE
->RR
;
185 RRE
[SIZERECTBUF
- 1].RR
.Next
= NULL
; /* IMPORTANT !!! */
190 struct RegionRectangleExt
*Prev
= RRE
++;
193 RRE
->RR
.Prev
= &Prev
->RR
;
194 Prev
->RR
.Next
= &RRE
->RR
;
196 RRE
->Counter
= Prev
->Counter
+ 1;
199 return *LastRectPtr
= (struct RegionRectangle
*)RRE
;
203 void _DisposeRegionRectangleList
205 struct RegionRectangle
*RR
,
206 struct GfxBase
*GfxBase
209 struct RegionRectangleExtChunk
*NextChunk
;
218 RR
->Prev
->Next
= NULL
;
221 /* Is this the first rectangle in the chunk? */
224 /* If so then this chunk has to be deleted too */
225 NextChunk
= Chunk(RR
);
229 /* otherwise dispose all the chunks starting from the one after this one */
230 RR
= &Chunk(RR
)->Rects
[SIZERECTBUF
- 1].RR
;
231 NextChunk
= Chunk(RR
->Next
);
237 struct RegionRectangleExtChunk
*OldChunk
= NextChunk
;
239 NextChunk
= Chunk(NextChunk
->Rects
[SIZERECTBUF
- 1].RR
.Next
);
241 _DisposeRegionRectangleExtChunk(OldChunk
);
246 Takes all the rectangles from src and linkes them with the rectangle
247 to which *dstptr points. *dstptr at the end will hold the pointer
248 to the LAST rectangle in the resulting list.
249 If the system runs out of memory the function will deallocate any allocated
250 memory and will return FALSE. TRUE, otherwise.
253 BOOL _LinkRegionRectangleList
255 struct RegionRectangle
*src
,
256 struct RegionRectangle
**dstptr
,
257 struct GfxBase
*GfxBase
260 struct RegionRectangle
*prev
= *dstptr
;
262 for (; src
; src
= src
->Next
)
264 struct RegionRectangle
*new = _NewRegionRectangle(dstptr
, GfxBase
);
270 _DisposeRegionRectangleList(prev
->Next
, GfxBase
);
276 new->bounds
= src
->bounds
;
282 #define ADVANCE(nextbandptr, rr) \
284 if ((rr)->Next && MinY((rr)->Next) == MinY(rr)) \
289 *nextbandptr = (rr)->Next; \
294 #define NEWREG(prevptr, rr) \
296 rr = _NewRegionRectangle(prevptr, GfxBase); \
301 #define ADDRECT(minx, maxx) \
303 struct RegionRectangle *rr; \
304 NEWREG(DstPtr, rr); \
312 #define ADDRECTMERGE(minx, maxx) \
317 (MinY(*(DstPtr)) != MinY) || \
318 ((minx-1) > MaxX(*DstPtr)) \
321 ADDRECT((minx), (maxx)); \
324 if (MaxX(*DstPtr) < maxx) \
326 MaxX(*DstPtr) = maxx; \
330 #define DOBANDCHECKS(firstlastdst, lastdst, curdst) \
331 if (curdst != lastdst) \
335 firstlastdst = &Chunk(curdst)->FirstChunk->Rects[0].RR; \
336 DstBounds->MinY = MinY(firstlastdst); \
337 DstBounds->MinX = MinX(firstlastdst); \
338 DstBounds->MaxX = MaxX(curdst); \
342 if (DstBounds->MinX > MinX(lastdst->Next)) \
343 DstBounds->MinX = MinX(lastdst->Next); \
344 if (DstBounds->MaxX < MaxX(curdst)) \
345 DstBounds->MaxX = MaxX(curdst); \
347 if (MaxY(firstlastdst) == MinY(curdst) - 1) \
349 struct RegionRectangle *_one = firstlastdst; \
350 struct RegionRectangle *_two = lastdst->Next; \
352 while (_one != lastdst->Next && _two) \
356 MinX(_one) == MinX(_two) && \
357 MaxX(_one) == MaxX(_two) \
369 if (_one == lastdst->Next && !_two) \
371 LONG MaxY = MaxY(curdst); \
372 _one = firstlastdst; \
373 _DisposeRegionRectangleList(lastdst->Next, GfxBase); \
383 firstlastdst = lastdst->Next; \
386 firstlastdst = lastdst->Next; \
396 void dumprect(struct Rectangle
*rec
)
404 kprintf("(%d,%d)-(%d,%d)\n", (int)rec
->MinX
, (int)rec
->MinY
,
405 (int)rec
->MaxX
, (int)rec
->MaxY
);
409 void dumpregion(struct Region
*reg
)
411 struct RegionRectangle
*rr
;
419 kprintf("Bounds: "); dumprect(®
->bounds
);
421 for (rr
= reg
->RegionRectangle
; rr
;)
423 struct RegionRectangle
*rr2
= rr
;
425 kprintf(" Band: MinY = %d - %p\n", (int)MinY(rr
), rr
);
428 kprintf("\t");dumprect(Bounds(rr2
));
435 void dumpregionrectangles(struct RegionRectangle
*rr
)
440 kprintf("%p (prev: %p - next: %p): ", rr
, rr
->Prev
, rr
->Next
);
441 dumprect(&rr
->bounds
);
447 void dumpband(struct RegionRectangle
*rr
, LONG OffX
, LONG MinY
, LONG MaxY
)
454 r
.MinX
= MinX(rr
) + OffX
;
455 r
.MaxX
= MaxX(rr
) + OffX
;
458 kprintf("%p (prev: %p - next: %p): ", rr
, rr
->Prev
, rr
->Next
);
460 if (rr
->Next
&& MinY(rr
->Next
) == MinY(rr
)) rr
= rr
->Next
; else break;
475 struct RegionRectangle
*Src1
,
476 struct RegionRectangle
*Src2
,
477 struct RegionRectangle
**DstPtr
,
478 struct RegionRectangle
**NextSrc1Ptr
,
479 struct RegionRectangle
**NextSrc2Ptr
,
480 struct GfxBase
*GfxBase
485 if (MinX(Src1
) + OffX1
< MinX(Src2
) + OffX2
)
487 ADDRECTMERGE(MinX(Src1
) + OffX1
, MaxX(Src1
) + OffX1
);
488 ADVANCE(NextSrc1Ptr
, Src1
);
492 ADDRECTMERGE(MinX(Src2
) + OffX2
, MaxX(Src2
) + OffX2
);
493 ADVANCE(NextSrc2Ptr
, Src2
);
501 ADDRECTMERGE(MinX(Src1
) + OffX1
, MaxX(Src1
) + OffX1
);
502 ADVANCE(NextSrc1Ptr
, Src1
);
508 ADDRECTMERGE(MinX(Src2
) + OffX2
, MaxX(Src2
) + OffX2
);
509 ADVANCE(NextSrc2Ptr
, Src2
);
522 struct RegionRectangle
*Src1
,
523 struct RegionRectangle
*Src2
,
524 struct RegionRectangle
**DstPtr
,
525 struct RegionRectangle
**NextSrc1Ptr
,
526 struct RegionRectangle
**NextSrc2Ptr
,
527 struct GfxBase
*GfxBase
532 if (MinX(Src1
) + OffX1
< MinX(Src2
) + OffX2
)
534 if (MaxX(Src1
) + OffX1
>= MaxX(Src2
) + OffX2
)
536 /* Src1 totally covers Src2 */
537 ADDRECT(MinX(Src2
) + OffX2
, MaxX(Src2
) + OffX2
);
538 ADVANCE(NextSrc2Ptr
, Src2
);
542 if (MaxX(Src1
) + OffX1
>= MinX(Src2
) + OffX2
)
543 /* Src1 partially covers Src2 */
544 ADDRECT(MinX(Src2
) + OffX2
, MaxX(Src1
) + OffX1
);
546 ADVANCE(NextSrc1Ptr
, Src1
);
551 if (MaxX(Src2
) + OffX2
>= MaxX(Src1
) + OffX1
)
553 /* Src2 totally covers Src1 */
554 ADDRECT(MinX(Src1
) + OffX1
, MaxX(Src1
) + OffX1
);
555 ADVANCE(NextSrc1Ptr
, Src1
);
559 if (MaxX(Src2
) + OffX2
>= MinX(Src1
) + OffX1
)
560 /* Src2 partially covers Src1 */
561 ADDRECT(MinX(Src1
) + OffX1
, MaxX(Src2
) + OffX2
);
563 ADVANCE(NextSrc2Ptr
, Src2
);
570 do ADVANCE(NextSrc1Ptr
, Src1
) while (Src1
);
573 while (Src2
) ADVANCE(NextSrc2Ptr
, Src2
);
585 struct RegionRectangle
*Src1
,
586 struct RegionRectangle
*Src2
,
587 struct RegionRectangle
**DstPtr
,
588 struct RegionRectangle
**NextSrc1Ptr
,
589 struct RegionRectangle
**NextSrc2Ptr
,
590 struct GfxBase
*GfxBase
596 MinX
= MinX(Src2
) + OffX2
;
600 if (MaxX(Src1
) + OffX1
< MinX
)
602 /* Subtrahend doesn't overlap minuend. Just skip it */
603 ADVANCE(NextSrc1Ptr
, Src1
);
606 if (MinX(Src1
) + OffX1
<= MinX
)
608 /* Subtrahend precedes minuend: nuke left edge of minuend */
609 MinX
= MaxX(Src1
) + OffX1
+ 1;
611 if (MinX
> MaxX(Src2
) + OffX2
)
614 Subtrahend completely overlaps minuend, so advance
615 to the next minuend and reset MinX to its left
617 ADVANCE(NextSrc2Ptr
, Src2
);
619 MinX
= MinX(Src2
) + OffX2
;
623 /* Subtrahend doesn't extend beyond minuend, so advence to the next one */
624 ADVANCE(NextSrc1Ptr
, Src1
);
628 if (MinX(Src1
) + OffX1
<= MaxX(Src2
) + OffX2
)
631 Subtrahend covers part of minuend.
632 Add uncovered part of minuend to the band and jump to the next
636 ADDRECT(MinX
, MinX(Src1
) + OffX1
- 1);
638 MinX
= MaxX(Src1
) + OffX1
+ 1;
640 if (MinX
> MaxX(Src2
) + OffX2
)
642 /*Minuend used up: advance to the next one */
643 ADVANCE(NextSrc2Ptr
, Src2
);
645 MinX
= MinX(Src2
) + OffX2
;
649 /* Subtrahend used up */
650 ADVANCE(NextSrc1Ptr
, Src1
);
656 Minuend used up: add any remaining piece before advancing.
659 if (MaxX(Src2
) + OffX2
>= MinX
)
661 ADDRECT(MinX
, MaxX(Src2
) + OffX2
);
664 ADVANCE(NextSrc2Ptr
, Src2
);
666 MinX
= MinX(Src2
) + OffX2
;
672 do ADVANCE(NextSrc1Ptr
, Src1
) while (Src1
);
677 ADDRECT(MinX
, MaxX(Src2
) + OffX2
);
678 ADVANCE(NextSrc2Ptr
, Src2
);
681 MinX
= MinX(Src2
) + OffX2
;
689 BOOL _DoOperationBandBand
691 BandOperation
*Operation
,
696 struct RegionRectangle
*Src1
,
697 struct RegionRectangle
*Src2
,
698 struct RegionRectangle
**DstPtr
,
699 struct Rectangle
*DstBounds
,
700 struct GfxBase
*GfxBase
703 struct RegionRectangle
*Dst
, *LastDst
, *FirstLastDst
;
704 struct RegionRectangle
**NextSrc1Ptr
= (void *)~0;
705 struct RegionRectangle
**NextSrc2Ptr
= (void *)~0;
706 struct RegionRectangle
*Band1
= Src1
, *Band2
= Src2
;
710 LONG TopY1
= 0, TopY2
= 0;
712 FirstLastDst
= LastDst
= Dst
= *DstPtr
= NULL
;
720 TopY1
= MinY(Src1
) + OffY1
;
726 TopY2
= MinY(Src2
) + OffY2
;
733 MaxY
= MIN(MaxY(Src1
) + OffY1
, TopY2
- 1);
743 MaxY
= MIN(MaxY(Src2
) + OffY2
, TopY1
- 1);
752 MaxY
= MIN(MaxY(Src1
) + OffY1
, MaxY(Src2
) + OffY2
);
753 TopY1
= TopY2
= MaxY
+ 1;
759 NextSrc1Ptr
= (MaxY
== MaxY(Src1
) + OffY1
) ? &Src1
: NULL
;
760 NextSrc2Ptr
= (MaxY
== MaxY(Src2
) + OffY2
) ? &Src2
: NULL
;
770 NextSrc1Ptr
, NextSrc2Ptr
,
779 DOBANDCHECKS(FirstLastDst
, LastDst
, Dst
);
786 TopY1
= MinY(Src1
) + OffY1
;
788 NextSrc1Ptr
= (void *)~0;
796 TopY1
, MaxY(Src1
) + OffY1
,
808 DOBANDCHECKS(FirstLastDst
, LastDst
, Dst
);
814 TopY2
= MinY(Src2
) + OffY2
;
816 NextSrc2Ptr
= (void *)~0;
823 TopY2
, MaxY(Src2
) + OffY2
,
835 DOBANDCHECKS(FirstLastDst
, LastDst
, Dst
);
844 DstBounds
->MaxY
= MaxY(Dst
);
845 *DstPtr
= &Chunk(Dst
)->FirstChunk
->Rects
[0].RR
;
848 _DisposeRegionRectangleList(&Chunk(Dst
)->FirstChunk
->Rects
[0].RR
, GfxBase
);
858 #include <proto/graphics.h>
865 struct Region
*R1
= NewRegion();
866 struct Region
*R2
= NewRegion();
868 for (i
= 0; i
< 10; i
++)
872 struct Rectangle r
= {l
, 0, l
+11, 201};
873 OrRectRegion(R1
, &r
);
876 for (i
= 0; i
< 10; i
++)
880 struct Rectangle r
= {0, u
, 201, u
+11};
881 OrRectRegion(R2
, &r
);
884 for (i
= 0; i
<100000; i
++)
886 XorRegionRegion(R2
, R1
);