Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / graphics / intregions.c
blob80095c02cb9a9b336abd6efc80571ad681ee1a3d
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Code for various operations on Regions and Rectangles
6 Lang: English
7 */
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>
22 #if DEBUG
23 void dumplist(struct GfxBase *GfxBase)
25 struct ChunkPool *Pool;
26 int n = 0;
28 Pool = (struct ChunkPool *)GetHead(&PrivGBase(GfxBase)->ChunkPoolList);
30 while (Pool)
32 struct ChunkExt *ChunkE;
33 int m = 0;
35 kprintf("Pool N.%d - %ld Chunk Free\n", n++, Pool->NumChunkFree);
37 ChunkE = (struct ChunkExt *)GetHead(&Pool->ChunkList);
39 while (ChunkE)
41 kprintf(" Chunk N.%d\n", m++);
42 ChunkE = (struct ChunkExt *)GetSucc(ChunkE);
45 Pool = (struct ChunkPool *)GetSucc(Pool);
48 #endif
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)
64 int i;
66 Pool = AllocMem(sizeof(struct ChunkPool), MEMF_ANY);
68 if (!Pool)
70 ReleaseSemaphore(&PrivGBase(GfxBase)->regionsem);
72 return NULL;
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);
89 REMOVE(ChunkE);
91 if (!--Pool->NumChunkFree)
93 REMOVE(Pool);
94 ADDTAIL(&PrivGBase(GfxBase)->ChunkPoolList, Pool);
97 ChunkE->Owner = 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);
115 REMOVE(Pool);
117 if (++Pool->NumChunkFree == SIZECHUNKBUF)
119 FreeMem(Pool, sizeof(struct ChunkPool));
121 else
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);
139 if (!RRE)
141 struct RegionRectangleExtChunk *Chunk;
143 Chunk = _NewRegionRectangleExtChunk();
145 if (Chunk)
147 RRE = Chunk->Rects;
150 if (RRE)
152 RRE->Counter = 0;
153 RRE->RR.Prev = NULL;
154 RRE->RR.Next = NULL;
156 RRE[SIZERECTBUF - 1].RR.Next = NULL; /* IMPORTANT !!! */
158 Chunk->FirstChunk = Chunk;
161 else
162 if (RRE->Counter == SIZERECTBUF - 1)
164 struct RegionRectangleExtChunk *Chunk;
166 Chunk = _NewRegionRectangleExtChunk();
168 if (Chunk)
170 Chunk->FirstChunk = Chunk(RRE)->FirstChunk;
171 RRE = Chunk->Rects;
173 else
175 RRE = NULL;
178 if (RRE)
180 RRE->Counter = 0;
181 RRE->RR.Prev = *LastRectPtr;
182 RRE->RR.Next = NULL;
183 (*LastRectPtr)->Next = &RRE->RR;
185 RRE[SIZERECTBUF - 1].RR.Next = NULL; /* IMPORTANT !!! */
188 else
190 struct RegionRectangleExt *Prev = RRE++;
192 RRE->RR.Next = NULL;
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;
211 if (!RR)
213 return;
216 if (RR->Prev)
218 RR->Prev->Next = NULL;
221 /* Is this the first rectangle in the chunk? */
222 if (!Counter(RR))
224 /* If so then this chunk has to be deleted too */
225 NextChunk = Chunk(RR);
227 else
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);
232 RR->Next = NULL;
235 while (NextChunk)
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);
266 if (!new)
268 if (prev)
270 _DisposeRegionRectangleList(prev->Next, GfxBase);
273 return FALSE;
276 new->bounds = src->bounds;
279 return TRUE;
282 #define ADVANCE(nextbandptr, rr) \
284 if ((rr)->Next && MinY((rr)->Next) == MinY(rr)) \
285 rr = (rr)->Next; \
286 else \
288 if (nextbandptr) \
289 *nextbandptr = (rr)->Next; \
290 rr = NULL; \
294 #define NEWREG(prevptr, rr) \
296 rr = _NewRegionRectangle(prevptr, GfxBase); \
297 if (!rr) \
298 return FALSE; \
301 #define ADDRECT(minx, maxx) \
303 struct RegionRectangle *rr; \
304 NEWREG(DstPtr, rr); \
306 MinX(rr) = minx; \
307 MinY(rr) = MinY; \
308 MaxX(rr) = maxx; \
309 MaxY(rr) = MaxY; \
312 #define ADDRECTMERGE(minx, maxx) \
314 if \
316 !*(DstPtr) || \
317 (MinY(*(DstPtr)) != MinY) || \
318 ((minx-1) > MaxX(*DstPtr)) \
321 ADDRECT((minx), (maxx)); \
323 else \
324 if (MaxX(*DstPtr) < maxx) \
326 MaxX(*DstPtr) = maxx; \
330 #define DOBANDCHECKS(firstlastdst, lastdst, curdst) \
331 if (curdst != lastdst) \
333 if (!lastdst) \
335 firstlastdst = &Chunk(curdst)->FirstChunk->Rects[0].RR; \
336 DstBounds->MinY = MinY(firstlastdst); \
337 DstBounds->MinX = MinX(firstlastdst); \
338 DstBounds->MaxX = MaxX(curdst); \
340 else \
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) \
354 if \
356 MinX(_one) == MinX(_two) && \
357 MaxX(_one) == MaxX(_two) \
360 _one = _one->Next; \
361 _two = _two->Next; \
363 else \
365 break; \
369 if (_one == lastdst->Next && !_two) \
371 LONG MaxY = MaxY(curdst); \
372 _one = firstlastdst; \
373 _DisposeRegionRectangleList(lastdst->Next, GfxBase); \
374 while (_one) \
376 MaxY(_one) = MaxY; \
377 _one = _one->Next; \
380 curdst = lastdst; \
382 else \
383 firstlastdst = lastdst->Next; \
385 else \
386 firstlastdst = lastdst->Next; \
388 lastdst = curdst; \
391 #if DOTEST
392 # define DEBUG 1
393 #endif
395 #if DEBUG
396 void dumprect(struct Rectangle *rec)
398 if (!rec)
400 kprintf("NULL\n");
401 return;
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;
413 if (!reg)
415 kprintf("NULL\n");
416 return;
419 kprintf("Bounds: "); dumprect(&reg->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));
429 ADVANCE(&rr, rr2);
430 } while (rr2);
435 void dumpregionrectangles(struct RegionRectangle *rr)
438 while (rr)
440 kprintf("%p (prev: %p - next: %p): ", rr, rr->Prev, rr->Next);
441 dumprect(&rr->bounds);
442 rr = rr->Next;
447 void dumpband(struct RegionRectangle *rr, LONG OffX, LONG MinY, LONG MaxY)
449 if (rr)
451 while (1)
453 struct Rectangle r;
454 r.MinX = MinX(rr) + OffX;
455 r.MaxX = MaxX(rr) + OffX;
456 r.MinY = MinY;
457 r.MaxY = MaxY;
458 kprintf("%p (prev: %p - next: %p): ", rr, rr->Prev, rr->Next);
459 dumprect(&r);
460 if (rr->Next && MinY(rr->Next) == MinY(rr)) rr = rr->Next; else break;
463 else
464 kprintf("\n");
466 #endif
469 BOOL _OrBandBand
471 LONG OffX1,
472 LONG OffX2,
473 LONG MinY,
474 LONG MaxY,
475 struct RegionRectangle *Src1,
476 struct RegionRectangle *Src2,
477 struct RegionRectangle **DstPtr,
478 struct RegionRectangle **NextSrc1Ptr,
479 struct RegionRectangle **NextSrc2Ptr,
480 struct GfxBase *GfxBase
483 while (Src1 && Src2)
485 if (MinX(Src1) + OffX1 < MinX(Src2) + OffX2)
487 ADDRECTMERGE(MinX(Src1) + OffX1, MaxX(Src1) + OffX1);
488 ADVANCE(NextSrc1Ptr, Src1);
490 else
492 ADDRECTMERGE(MinX(Src2) + OffX2, MaxX(Src2) + OffX2);
493 ADVANCE(NextSrc2Ptr, Src2);
497 if (Src1)
501 ADDRECTMERGE(MinX(Src1) + OffX1, MaxX(Src1) + OffX1);
502 ADVANCE(NextSrc1Ptr, Src1);
503 } while (Src1);
505 else
506 while (Src2)
508 ADDRECTMERGE(MinX(Src2) + OffX2, MaxX(Src2) + OffX2);
509 ADVANCE(NextSrc2Ptr, Src2);
512 return TRUE;
516 BOOL _AndBandBand
518 LONG OffX1,
519 LONG OffX2,
520 LONG MinY,
521 LONG MaxY,
522 struct RegionRectangle *Src1,
523 struct RegionRectangle *Src2,
524 struct RegionRectangle **DstPtr,
525 struct RegionRectangle **NextSrc1Ptr,
526 struct RegionRectangle **NextSrc2Ptr,
527 struct GfxBase *GfxBase
530 while (Src1 && Src2)
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);
540 else
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);
549 else
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);
557 else
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);
568 if (Src1)
570 do ADVANCE(NextSrc1Ptr, Src1) while (Src1);
572 else
573 while (Src2) ADVANCE(NextSrc2Ptr, Src2);
575 return TRUE;
579 BOOL _ClearBandBand
581 LONG OffX1,
582 LONG OffX2,
583 LONG MinY,
584 LONG MaxY,
585 struct RegionRectangle *Src1,
586 struct RegionRectangle *Src2,
587 struct RegionRectangle **DstPtr,
588 struct RegionRectangle **NextSrc1Ptr,
589 struct RegionRectangle **NextSrc2Ptr,
590 struct GfxBase *GfxBase
593 LONG MinX = 0;
595 if (Src2)
596 MinX = MinX(Src2) + OffX2;
598 while (Src1 && Src2)
600 if (MaxX(Src1) + OffX1 < MinX)
602 /* Subtrahend doesn't overlap minuend. Just skip it */
603 ADVANCE(NextSrc1Ptr, Src1);
605 else
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);
618 if (Src2)
619 MinX = MinX(Src2) + OffX2;
621 else
623 /* Subtrahend doesn't extend beyond minuend, so advence to the next one */
624 ADVANCE(NextSrc1Ptr, Src1);
627 else
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
633 subtrahend
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);
644 if (Src2)
645 MinX = MinX(Src2) + OffX2;
647 else
649 /* Subtrahend used up */
650 ADVANCE(NextSrc1Ptr, Src1);
653 else
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);
665 if (Src2)
666 MinX = MinX(Src2) + OffX2;
670 if (Src1)
672 do ADVANCE(NextSrc1Ptr, Src1) while (Src1);
674 else
675 while (Src2)
677 ADDRECT(MinX, MaxX(Src2) + OffX2);
678 ADVANCE(NextSrc2Ptr, Src2);
679 if (Src2)
681 MinX = MinX(Src2) + OffX2;
685 return TRUE;
689 BOOL _DoOperationBandBand
691 BandOperation *Operation,
692 LONG OffX1,
693 LONG OffX2,
694 LONG OffY1,
695 LONG OffY2,
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;
708 BOOL res = TRUE;
710 LONG TopY1 = 0, TopY2 = 0;
712 FirstLastDst = LastDst = Dst = *DstPtr = NULL;
714 while (Src1 && Src2)
716 LONG MinY, MaxY;
718 if (NextSrc1Ptr)
720 TopY1 = MinY(Src1) + OffY1;
721 NextSrc1Ptr = NULL;
724 if (NextSrc2Ptr)
726 TopY2 = MinY(Src2) + OffY2;
727 NextSrc2Ptr = NULL;
730 if (TopY1 < TopY2)
732 MinY = TopY1;
733 MaxY = MIN(MaxY(Src1) + OffY1, TopY2 - 1);
734 TopY1 = MaxY + 1;
736 Band1 = Src1;
737 Band2 = NULL;
739 else
740 if (TopY2 < TopY1)
742 MinY = TopY2;
743 MaxY = MIN(MaxY(Src2) + OffY2, TopY1 - 1);
744 TopY2 = MaxY + 1;
746 Band1 = NULL;
747 Band2 = Src2;
749 else
751 MinY = TopY1;
752 MaxY = MIN(MaxY(Src1) + OffY1, MaxY(Src2) + OffY2);
753 TopY1 = TopY2 = MaxY + 1;
755 Band1 = Src1;
756 Band2 = Src2;
759 NextSrc1Ptr = (MaxY == MaxY(Src1) + OffY1) ? &Src1 : NULL;
760 NextSrc2Ptr = (MaxY == MaxY(Src2) + OffY2) ? &Src2 : NULL;
764 !Operation
766 OffX1, OffX2,
767 MinY, MaxY,
768 Band1, Band2,
769 &Dst,
770 NextSrc1Ptr, NextSrc2Ptr,
771 GfxBase
775 res = FALSE;
776 goto end;
779 DOBANDCHECKS(FirstLastDst, LastDst, Dst);
783 while (Src1)
785 if (NextSrc1Ptr)
786 TopY1 = MinY(Src1) + OffY1;
788 NextSrc1Ptr = (void *)~0;
793 !Operation
795 OffX1, OffX2,
796 TopY1, MaxY(Src1) + OffY1,
797 Src1, NULL,
798 &Dst,
799 &Src1, NULL,
800 GfxBase
804 res = FALSE;
805 goto end;
808 DOBANDCHECKS(FirstLastDst, LastDst, Dst);
811 while (Src2)
813 if (NextSrc2Ptr)
814 TopY2 = MinY(Src2) + OffY2;
816 NextSrc2Ptr = (void *)~0;
820 !Operation
822 OffX1, OffX2,
823 TopY2, MaxY(Src2) + OffY2,
824 NULL, Src2,
825 &Dst,
826 NULL, &Src2,
827 GfxBase
831 res = FALSE;
832 goto end;
835 DOBANDCHECKS(FirstLastDst, LastDst, Dst);
838 end:
840 if (Dst)
842 if (res)
844 DstBounds->MaxY = MaxY(Dst);
845 *DstPtr = &Chunk(Dst)->FirstChunk->Rects[0].RR;
847 else
848 _DisposeRegionRectangleList(&Chunk(Dst)->FirstChunk->Rects[0].RR, GfxBase);
851 return res;
855 #if DOTEST
857 #undef GfxBase
858 #include <proto/graphics.h>
861 int main(void)
863 int i;
865 struct Region *R1 = NewRegion();
866 struct Region *R2 = NewRegion();
868 for (i = 0; i < 10; i++)
870 int l = i*20;
872 struct Rectangle r = {l, 0, l+11, 201};
873 OrRectRegion(R1, &r);
876 for (i = 0; i < 10; i++)
878 int u = i*20;
880 struct Rectangle r = {0, u, 201, u+11};
881 OrRectRegion(R2, &r);
884 for (i = 0; i<100000; i++)
886 XorRegionRegion(R2, R1);
889 DisposeRegion(R2);
890 DisposeRegion(R1);
891 return 0;
894 #endif