2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Area support functions
10 #include <proto/alib.h>
11 #include <exec/types.h>
12 #include <exec/memory.h>
13 #include <proto/graphics.h>
14 #include <proto/exec.h>
15 #include <graphics/rastport.h>
16 #include <graphics/gfx.h>
17 #include <graphics/gfxbase.h>
20 #include <aros/debug.h>
22 #include "graphics_intern.h"
25 The algorithm was taken from:
27 A programming approach, 2n edition
34 The algorithm that follows the borderlines has to go hand in hand
35 with the algorithm that draws the line, such that no parts are
36 filled that aren't supposed to be filled.
39 void LineInTmpRas(struct RastPort
* rp
,
40 struct Rectangle
* bounds
,
45 struct GfxBase
* GfxBase
);
67 UWORD
Include (UWORD lastused
,
69 struct BoundLine
* AreaBound
,
73 while (lastused
< lastindex
&&
74 VctTbl
[AreaBound
[lastused
+1].StartIndex
+1] == scan
)
77 kprintf("including new one! ");
78 kprintf("(%d,%d)-(%d,%d)\n",VctTbl[AreaBound[lastused+1].StartIndex],
79 VctTbl[AreaBound[lastused+1].StartIndex+1],
80 VctTbl[AreaBound[lastused+1].EndIndex],
81 VctTbl[AreaBound[lastused+1].EndIndex]);
88 void FillScan(UWORD StartIndex
,
90 struct BoundLine
* AreaBound
,
93 struct Rectangle
* bounds
,
95 struct GfxBase
* GfxBase
)
101 /* simply draw a line */
102 while (!AreaBound
[i
].Valid
)
105 if (i
> EndIndex
) return;
107 x1
=AreaBound
[i
].RightX
+1;
109 while (!AreaBound
[i
+1].Valid
)
112 if (i
> EndIndex
) return;
115 if (x1
<= AreaBound
[i
+1].LeftX
-1)
121 AreaBound
[i
+1].LeftX
-1,
131 void XSort(UWORD StartIndex
,
133 struct BoundLine
* AreaBound
)
135 /* a simple bubble sort */
136 struct BoundLine tmpAreaBound
;
137 int i
= StartIndex
+1;
139 //kprintf("%d,%d\n",StartIndex,EndIndex);
141 //kprintf("%d ",AreaBound[StartIndex].LeftX);
143 while (i
<= EndIndex
)
145 if (AreaBound
[i
].LeftX
< AreaBound
[i
-1].LeftX
)
147 /* The one at index i needs to go more to smaller indices */
149 //kprintf("sorting!!\n");
150 tmpAreaBound
= AreaBound
[i
];
153 AreaBound
[i2
] = AreaBound
[i2
-1];
155 if (i2
== StartIndex
||
156 AreaBound
[i2
-1].LeftX
<= tmpAreaBound
.LeftX
)
158 AreaBound
[i2
] = tmpAreaBound
;
164 //kprintf("%d ",AreaBound[i].LeftX);
171 UWORD
UpdateXValues(UWORD StartIndex
,
174 struct BoundLine
* AreaBound
,
178 BOOL foundvalid
= FALSE
;
180 while (i
<= EndIndex
)
182 /* Test whether this one is still to be considered */
184 if ( VctTbl
[AreaBound
[i
].EndIndex
+1] <= scan
||
185 !AreaBound
[i
].Valid
)
188 if (!AreaBound[i].Valid)
189 kprintf ("already marked as invalid! ");
191 kprintf("marking %d as anvalid! ",i);
192 kprintf("(%d,%d)-(%d,%d)\n",VctTbl[AreaBound[i].StartIndex],
193 VctTbl[AreaBound[i].StartIndex+1],
194 VctTbl[AreaBound[i].EndIndex],
195 VctTbl[AreaBound[i].EndIndex+1]);
197 AreaBound
[i
].Valid
= FALSE
;
201 /* It is still to be considered!! */
203 /* calculate the new x-coordinates for the new line */
204 if (0 == AreaBound
[i
].DeltaX
)
206 /* a vertical line !!! easy!! */
211 AreaBound
[i
].RightX
+= AreaBound
[i
].NRightX
;
212 AreaBound
[i
].LeftX
+= AreaBound
[i
].NLeftX
;
213 AreaBound
[i
].NRightX
= 0;
214 AreaBound
[i
].NLeftX
= 0;
216 * If we're moving more in the horizontal
217 * than in the vertical, then the line
218 * has a pure horizontal component which I
219 * must take care of by not painting over it.
220 * This means that on a y coordinate the line
221 * can go from the LeftX to the RightX.
223 if (1 == AreaBound
[i
].horiz
) {
225 * More towards the horizontal than down
227 if (AreaBound
[i
].s1
> 0) {
228 AreaBound
[i
].LeftX
= AreaBound
[i
].RightX
;
230 AreaBound
[i
].RightX
= AreaBound
[i
].LeftX
;
236 if (AreaBound
[i
].Count
<= 0) {
237 AreaBound
[i
].Count
+= AreaBound
[i
].incrE
;
238 if (1 == AreaBound
[i
].t
) {
239 if (AreaBound
[i
].s1
> 0) {
243 AreaBound
[i
].RightX
++;
248 AreaBound
[i
].LeftX
--;
252 * Going to next Y coordinate
257 AreaBound
[i
].Count
+= AreaBound
[i
].incrNE
;
259 * Going to next Y coordinate
261 if (AreaBound
[i
].s1
> 0) {
265 AreaBound
[i
].NRightX
= 1;
270 AreaBound
[i
].NLeftX
= -1;
277 * If we're going more vertical than horizontal
278 * then the left and right are always the same.
280 if (0 == AreaBound
[i
].horiz
) {
281 if (AreaBound
[i
].s1
> 0) {
283 AreaBound[i].RightX += AreaBound[i].NRightX;
284 AreaBound[i].NRightX = 0;
286 AreaBound
[i
].LeftX
= AreaBound
[i
].RightX
;
289 AreaBound[i].LeftX += AreaBound[i].NLeftX;
290 AreaBound[i].NLeftX = 0;
292 AreaBound
[i
].RightX
= AreaBound
[i
].LeftX
;
302 /* functions for filling of the RastPort */
303 BOOL
areafillpolygon(struct RastPort
* rp
,
304 struct Rectangle
* bounds
,
308 struct GfxBase
* GfxBase
)
315 UWORD LastEdge
= last_idx
- first_idx
+ 1; // needed later on. Don't change!!
316 struct AreaInfo
* areainfo
= rp
->AreaInfo
;
317 UWORD
* StartVctTbl
= &areainfo
->VctrTbl
[first_idx
* 2];
319 struct BoundLine tmpAreaBound
;
320 struct BoundLine
* AreaBound
=
321 (struct BoundLine
*) AllocMem(sizeof(struct BoundLine
) * LastEdge
,
324 if (NULL
== AreaBound
)
327 /* first clear the buffer of the temporary rastport as far as necessary */
329 memset(rp
->TmpRas
->RasPtr
,
331 BytesPerRow
* (bounds
->MaxY
- bounds
->MinY
+ 1));
334 kprintf("first: %d, last: %d\n",first_idx,last_idx);
335 kprintf("(%d,%d)-(%d,%d)\n",bounds->MinX,bounds->MinY,
336 bounds->MaxX,bounds->MaxY);
337 kprintf("width: %d, bytesperrow: %d\n",bounds->MaxX - bounds->MinX + 1,
340 /* I need a list of sorted indices that represent the lines of the
341 ** polygon. Horizontal lines don't go into that list!!!
342 ** The lines are sorted by their start-y coordinates.
348 /* process all points of the polygon */
349 while (c
< (LastEdge
-1)*2)
352 /* is the next one starting point of a horizontal line??? If yes,
355 kprintf("current idx for y: %d, next idx for y: %d\n",c+1,c+3);
357 if (StartVctTbl
[c
+1] == StartVctTbl
[c
+3])
359 // kprintf("Found horizontal Line!!\n");
364 /* which coordinate of this line has the lower y value */
365 if (StartVctTbl
[c
+1] < StartVctTbl
[c
+3])
367 tmpAreaBound
.StartIndex
= c
;
368 tmpAreaBound
.EndIndex
= c
+2;
369 ymin
= StartVctTbl
[c
+1];
373 tmpAreaBound
.StartIndex
= c
+2;
374 tmpAreaBound
.EndIndex
= c
;
375 ymin
= StartVctTbl
[c
+3];
379 kprintf("line: (%d,%d)-(%d,%d) ",StartVctTbl[c],
383 kprintf("miny: %d\n",ymin);
387 ** search for the place where to put this entry into the sorted
388 ** (increasing start y-coordinates) list
395 kprintf("ymin: %d< %d?\n",ymin,StartVctTbl[AreaBound[i2].StartIndex+1]);
397 if (ymin
< StartVctTbl
[AreaBound
[i2
].StartIndex
+1])
400 /* found the place! */
404 kprintf("moving!\n");
406 AreaBound
[i3
].StartIndex
= AreaBound
[i3
-1].StartIndex
;
407 AreaBound
[i3
].EndIndex
= AreaBound
[i3
-1].EndIndex
;
410 AreaBound
[i2
].StartIndex
= tmpAreaBound
.StartIndex
;
411 AreaBound
[i2
].EndIndex
= tmpAreaBound
.EndIndex
;
418 kprintf("at end!\n");
420 AreaBound
[i
+1].StartIndex
= tmpAreaBound
.StartIndex
;
421 AreaBound
[i
+1].EndIndex
= tmpAreaBound
.EndIndex
;
426 else /* first one to insert into list */
428 AreaBound
[0].StartIndex
= tmpAreaBound
.StartIndex
;
429 AreaBound
[0].EndIndex
= tmpAreaBound
.EndIndex
;
441 while (i2 <= LastIndex)
443 kprintf("%d.: index %d (%d,%d)-(%d,%d)\n",i2,AreaBound[i2].StartIndex,
444 StartVctTbl[AreaBound[i2].StartIndex],
445 StartVctTbl[AreaBound[i2].StartIndex+1],
446 StartVctTbl[AreaBound[i2].EndIndex],
447 StartVctTbl[AreaBound[i2].EndIndex+1]);
453 while (i
<= LastIndex
)
455 int StartIndex
= AreaBound
[i
].StartIndex
;
456 int EndIndex
= AreaBound
[i
].EndIndex
;
458 if ((StartVctTbl
[EndIndex
] - StartVctTbl
[StartIndex
]) > 0) {
461 AreaBound
[i
].s1
= -1;
464 AreaBound
[i
].DeltaX
= abs(StartVctTbl
[EndIndex
] -
465 StartVctTbl
[StartIndex
]);
467 AreaBound
[i
].DeltaY
= abs(StartVctTbl
[EndIndex
+1] -
468 StartVctTbl
[StartIndex
+1]);
470 if (AreaBound
[i
].DeltaX
> AreaBound
[i
].DeltaY
) {
471 AreaBound
[i
].horiz
= 1;
475 if (AreaBound
[i
].DeltaX
< AreaBound
[i
].DeltaY
) {
476 WORD d
= AreaBound
[i
].DeltaX
;
477 AreaBound
[i
].DeltaX
= AreaBound
[i
].DeltaY
;
478 AreaBound
[i
].DeltaY
= d
;
484 AreaBound
[i
].Count
= (AreaBound
[i
].DeltaY
* 2) - AreaBound
[i
].DeltaX
;
485 AreaBound
[i
].incrE
= AreaBound
[i
].DeltaY
* 2;
486 AreaBound
[i
].incrNE
= (AreaBound
[i
].DeltaY
- AreaBound
[i
].DeltaX
) * 2;
488 AreaBound
[i
].LeftX
= AreaBound
[i
].RightX
= StartVctTbl
[StartIndex
];
489 AreaBound
[i
].Valid
= TRUE
;
493 /* indexlist now contains i+1 indices into the vector table.
494 Either the coordinate at the index as declared in the indexlist
495 contains the lower y value or the following coordinate */
502 EndEdge
= Include(1, LastIndex
, AreaBound
, scan
, StartVctTbl
);
503 StartEdge
= UpdateXValues(StartEdge
, EndEdge
, scan
, AreaBound
, StartVctTbl
);
505 while (scan
< bounds
->MaxY
)
507 XSort(StartEdge
, EndEdge
, AreaBound
);
509 if (scan
> bounds
->MinY
)
520 kprintf("scanline: %d StartEdge: %d, EndEdge: %d\n",scan,StartEdge,EndEdge);
526 if (AreaBound[x].Valid)
528 kprintf("(%d,%d)-(%d,%d) currently at: Left: %d Right: %d\n",
529 StartVctTbl[AreaBound[x].StartIndex],
530 StartVctTbl[AreaBound[x].StartIndex+1],
531 StartVctTbl[AreaBound[x].EndIndex],
532 StartVctTbl[AreaBound[x].EndIndex+1],
534 AreaBound[x].RightX);
537 kprintf("invalid\n");
543 EndEdge
= Include(EndEdge
, LastIndex
, AreaBound
, scan
, StartVctTbl
);
544 StartEdge
= UpdateXValues(StartEdge
, EndEdge
, scan
, AreaBound
, StartVctTbl
);
546 kprintf("StartEdge: %d, EndEdge: %d\n",StartEdge,EndEdge);
550 FreeMem( AreaBound
, sizeof(struct BoundLine
) * LastEdge
);
556 void areafillellipse(struct RastPort
* rp
,
557 struct Rectangle
* bounds
,
560 struct GfxBase
* GfxBase
)
562 /* the ellipse drawing algorithm is taken from DrawEllipse() */
563 LONG x
= CurVctr
[2], y
= 0; /* ellipse points */
565 /* intermediate terms to speed up loop */
566 LONG t1
= CurVctr
[2] * CurVctr
[2], t2
= t1
<< 1, t3
= t2
<< 1;
567 LONG t4
= CurVctr
[3] * CurVctr
[3], t5
= t4
<< 1, t6
= t5
<< 1;
568 LONG t7
= CurVctr
[2] * t5
, t8
= t7
<< 1, t9
= 0;
569 LONG d1
= t2
- t7
+ (t4
>> 1); /* error terms */
570 LONG d2
= (t1
>> 1) - t8
+ t5
;
572 memset(rp
->TmpRas
->RasPtr
,
574 BytesPerRow
* (bounds
->MaxY
- bounds
->MinY
+ 1) );
576 kprintf("filled bytes: %d\n",BytesPerRow * (bounds->MaxY - bounds->MinY + 1));
578 kprintf("Filling ellipse with center at (%d,%d) and radius in x: %d and in y: %d\n",
579 CurVctr[0],CurVctr[1],CurVctr[2],CurVctr[3]);
581 while (d2
< 0 && y
< CurVctr
[3])
583 /* draw 2 lines using symmetry */
603 y
++; /* always move up here */
605 if (d1
< 0) /* move straight up */
614 d1
= d1
+ t9
+ t2
- t8
;
615 d2
= d2
+ t9
+ t5
- t8
;
619 do /* rest of the right quadrant */
621 /* draw 2 lines using symmetry */
623 x
--; /* always move left here */
625 if (d2
< 0) /* move up and left */
650 d2
= d2
+ t9
+ t5
- t8
;
652 else /* move straight left */
656 } while ( x
> 0 && y
< CurVctr
[3] );
660 ** Draw a horizontal line into a temporary rastport.
663 void LineInTmpRas(struct RastPort
* rp
,
664 struct Rectangle
* bounds
,
669 struct GfxBase
* GfxBase
)
675 UWORD
* RasPtr
= (WORD
*)rp
->TmpRas
->RasPtr
;
678 //kprintf("(%d/%d) to (%d/%d)\n",xleft,y,xright,y);
680 /* adjust the coordinates */
681 xleft
-= bounds
->MinX
;
682 xright
-= bounds
->MinX
;
685 //kprintf("line from %d to %d y = %d\n",xleft,xright,y);
687 if (xleft
> xright
) return;
689 an algorithm that tries to minimize the number of accesses to the
693 /* Fill the first word */
696 /* determine the number of pixels to set at the beginning */
697 NumPixels
= xright
- xleft
+ 1;
701 /* create enough pixels */
702 PixelMask
>>= (NumPixels
- 1);
704 index
= (y
* (BytesPerRow
>> 1)) + (xleft
>> 4);
705 /* Adjust the pixelmask so we hit the very first pixel */
706 PixelMask2
= PixelMask
& 0xffff;
707 if (0 != (shift
= (xleft
& 0x0f))) {
708 PixelMask2
>>= shift
;
711 #if (AROS_BIG_ENDIAN == 0)
712 /* Endianess conversion*/
713 PixelMask2
= PixelMask2
<< 8 | PixelMask2
>> 8;
715 RasPtr
[index
] |= PixelMask2
;
716 //kprintf("%x (left)\n",PixelMask2);
720 xleft
= xleft
+ (16 - shift
);
722 if ((xright
- xleft
) < 16)
725 /* fill the middle with 0xffff's */
726 while ((xleft
+ 15) < xright
)
728 RasPtr
[index
] = (WORD
)0xffff;
737 /* Create enough pixels - one pixel is already there! */
738 if (0 != (shift
= (xright
- xleft
+ 0))) {
742 PixelMask2
= PixelMask
& 0xffff;
744 #if (AROS_BIG_ENDIAN == 0)
745 /* Endianess conversion*/
746 PixelMask2
= PixelMask2
<< 8 | PixelMask2
>> 8;
749 RasPtr
[index
] |= PixelMask2
;
750 //kprintf("%x (right)\n",PixelMask2);
756 void areaclosepolygon(struct AreaInfo
*areainfo
)
758 /* Note: the caller must make sure, that this
759 function is only called if areainfo->Count > 0
760 and that there is place for one vector
761 (areainfo->Count < areainfo->MaxCount) */
763 if ( areainfo
->FlagPtr
[-1] == AREAINFOFLAG_DRAW
)
765 if ((areainfo
->VctrPtr
[-1] != areainfo
->FirstY
) ||
766 (areainfo
->VctrPtr
[-2] != areainfo
->FirstX
))
769 areainfo
->VctrPtr
[0] = areainfo
->FirstX
;
770 areainfo
->VctrPtr
[1] = areainfo
->FirstY
;
771 areainfo
->FlagPtr
[0] = AREAINFOFLAG_CLOSEDRAW
;
773 areainfo
->VctrPtr
= &areainfo
->VctrPtr
[2];
778 areainfo
->FlagPtr
[-1] = AREAINFOFLAG_CLOSEDRAW
;