mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-16 01:50:38 +01:00
476 lines
13 KiB
Plaintext
476 lines
13 KiB
Plaintext
{
|
||
$Id$
|
||
This file is part of the Free Pascal run time library.
|
||
Copyright (c) 1993,97 by the Free Pascal development team.
|
||
|
||
See the file COPYING.FPC, included in this distribution,
|
||
for details about the copyright.
|
||
|
||
This program is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
||
**********************************************************************}
|
||
|
||
{$ifopt S+}
|
||
{$define StackCkeckOn}
|
||
{$endif opt S+}
|
||
|
||
procedure floodfill(x,y:integer; border:longint);
|
||
|
||
var bordercol : longint;
|
||
fillcol,fillbkcol : longint;
|
||
viewport : viewporttype;
|
||
offset : longint;
|
||
test_bkfill : boolean;
|
||
|
||
{$S+}
|
||
{ Fill is very recursive !! }
|
||
{ And it fails sometimes !! }
|
||
|
||
procedure fill(x,y:integer);
|
||
var start,ende,xx : integer;
|
||
col : longint;
|
||
|
||
begin
|
||
{$ifdef GraphDebug}
|
||
if (x>viewport.x2) or (x<viewport.x1) or
|
||
(y>viewport.y2) or (y<viewport.y1) then
|
||
begin
|
||
Writeln(stderr,'Wrong value in Fill(',x,',',y,')');
|
||
exit;
|
||
end;
|
||
{$endif def GraphDebug}
|
||
xx:=x; col:=getpixeli(xx,y);
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Fill ',x,' ',y,' ',hexstr(col,8));
|
||
{$endif def GraphDebug}
|
||
if (col=bordercol) or (col=fillcol) or
|
||
(test_bkfill and (col=fillbkcol)) then
|
||
exit;
|
||
while (col<>bordercol) and (xx > viewport.x1) and
|
||
(col<>fillcol) and (not test_bkfill or (col<>fillbkcol))
|
||
do begin
|
||
xx:=xx-1; col:=getpixeli(xx,y);
|
||
end;
|
||
if (col<>bordercol) and (col<>fillcol) and
|
||
(not test_bkfill or (col<>fillbkcol)) then
|
||
start:=xx
|
||
else
|
||
start:=xx+1;
|
||
|
||
xx:=x;
|
||
col:=getpixeli(xx,y);
|
||
while (col<>bordercol) and (xx < viewport.x2) and (col<>fillcol)
|
||
and (not test_bkfill or (col<>fillbkcol))
|
||
do begin
|
||
xx:=xx+1; col:=getpixeli(xx,y);
|
||
end;
|
||
if (col<>bordercol) and (col<>fillcol) and
|
||
(not test_bkfill or (col<>fillbkcol)) then
|
||
ende:=xx
|
||
else
|
||
ende:=xx-1;
|
||
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Pattern ',start,' ',ende,' ',y);
|
||
{$endif def GraphDebug}
|
||
patternline(start,ende,y);
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Fill after Patterline ',x,' ',y,' ',hexstr(getpixel(x,y),8));
|
||
{$endif def GraphDebug}
|
||
offset:=(y * _maxy + start) shr 8;
|
||
|
||
if (y > viewport.y1)
|
||
then begin
|
||
xx:=start;
|
||
repeat
|
||
col:=getpixeli(xx,y-1);
|
||
if (col<>bordercol) and (col<>fillcol) and
|
||
(not test_bkfill or (col<>fillbkcol))
|
||
then begin
|
||
fill(xx,y-1);
|
||
break;
|
||
end;
|
||
xx:=xx+1;
|
||
until xx > ende;
|
||
end;
|
||
|
||
if (y<viewport.y2) then
|
||
begin
|
||
xx:=start;
|
||
repeat
|
||
col:=getpixeli(xx,y+1);
|
||
if (col<>bordercol) and (col<>fillcol) and
|
||
(not test_bkfill or (col<>fillbkcol)) then
|
||
fill(xx,y+1);
|
||
xx:=xx+1;
|
||
until xx > ende;
|
||
end;
|
||
|
||
end;
|
||
|
||
begin
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'FloodFill start ',x,' ',y);
|
||
{$endif def GraphDebug}
|
||
{$ifdef NOFILL}
|
||
exit;
|
||
{$endif NOFILL}
|
||
{fillchar(buffermem^,buffersize,0);
|
||
not used !! }
|
||
if aktviewport.clip then viewport:=aktviewport else viewport:=aktscreen;
|
||
{ reject invalid points !! }
|
||
|
||
viewport.x2:=viewport.x2-viewport.x1;
|
||
viewport.y2:=viewport.y2-viewport.y1;
|
||
viewport.x1:=0;
|
||
viewport.y1:=0;
|
||
|
||
if (x>viewport.x2) or (x<viewport.x1) or
|
||
(y>viewport.y2) or (y<viewport.y1) then
|
||
begin
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Error Wrong values for FloodFill');
|
||
Writeln(stderr,'xmax ',viewport.x2);
|
||
Writeln(stderr,'ymax ',viewport.y2);
|
||
{$endif def GraphDebug}
|
||
exit;
|
||
end;
|
||
bordercol:=convert(border) and ColorMask;
|
||
fillcol:=aktfillsettings.color and ColorMask;
|
||
fillbkCol:=aktfillbkcolor and ColorMask;
|
||
if aktfillsettings.pattern=emptyfill then
|
||
begin
|
||
fillcol:=fillbkcol;
|
||
test_bkfill:=false;
|
||
end
|
||
else if aktfillsettings.pattern=solidfill then
|
||
test_bkfill:=false
|
||
else
|
||
test_bkfill:=true;
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'FloodFill(',x,',',y,') Fillcol ',hexstr(unconvert(fillcol),8));
|
||
Writeln(stderr,' bordercol ',hexstr(unconvert(bordercol),8),
|
||
' fillbkcol ',hexstr(unconvert(fillbkcol),8));
|
||
{$endif def GraphDebug}
|
||
fill(x,y);
|
||
end;
|
||
|
||
{$ifndef StackCkeckOn}
|
||
{$S-} { return to normal state }
|
||
{$else }
|
||
{$undef StackCheckOn}
|
||
{$endif }
|
||
|
||
procedure GetFillSettings(var Fillinfo:Fillsettingstype);
|
||
begin
|
||
_graphresult:=grOk;
|
||
if not isgraphmode then
|
||
begin
|
||
_graphresult:=grnoinitgraph;
|
||
exit;
|
||
end;
|
||
Fillinfo:=aktfillsettings;
|
||
Fillinfo.color:=unconvert(aktfillsettings.color);
|
||
end;
|
||
|
||
procedure GetFillPattern(var FillPattern:FillPatternType);
|
||
begin
|
||
_graphresult:=grOk;
|
||
if not isgraphmode then
|
||
begin
|
||
_graphresult:=grnoinitgraph;
|
||
exit;
|
||
end;
|
||
FillPattern:=aktfillpattern;
|
||
end;
|
||
|
||
procedure SetFillPattern(pattern : FillPatternType;color : longint);
|
||
begin
|
||
_graphresult:=grOk;
|
||
if not isgraphmode then
|
||
begin
|
||
_graphresult:=grnoinitgraph;
|
||
exit;
|
||
end;
|
||
fillpattern[12]:=pattern;
|
||
SetFillStyle(12,color);
|
||
end;
|
||
|
||
procedure SetFillStyle(pattern : word ;color : longint);
|
||
var i,j:Integer;
|
||
mask:Byte;
|
||
begin
|
||
_graphresult:=grOk;
|
||
if not isgraphmode then
|
||
begin
|
||
_graphresult:=grnoinitgraph;
|
||
exit;
|
||
end;
|
||
{ g<>ltige Paramter ? }
|
||
if (pattern<0) or (pattern>12) then
|
||
begin
|
||
_graphresult:=grError;
|
||
exit;
|
||
end;
|
||
{ Muster laden }
|
||
aktfillpattern:=fillpattern[pattern];
|
||
aktfillsettings.pattern:=pattern;
|
||
aktfillsettings.color:=convert(color);
|
||
aktfillbkcolor:=aktbackcolor;
|
||
i:=1; j:=0;
|
||
repeat
|
||
mask:=$80;
|
||
repeat
|
||
if (aktfillpattern[i] and mask) = 0
|
||
then PatternBuffer[j]:=aktbackcolor else PatternBuffer[j]:=aktfillsettings.color;
|
||
mask:=mask shr 1;
|
||
j:=j+1;
|
||
until mask=0;
|
||
i:=i+1;
|
||
until i > 8;
|
||
end;
|
||
|
||
procedure GetLineSettings(var LineInfo : LineSettingsType);
|
||
begin
|
||
_graphresult:=grOk;
|
||
if not isgraphmode then
|
||
begin
|
||
_graphresult:=grnoinitgraph;
|
||
exit;
|
||
end;
|
||
lineinfo:=aktlineinfo;
|
||
end;
|
||
|
||
{ this procedure is rather confuse
|
||
but I admit that I wrote it by try-error !! PM }
|
||
|
||
procedure FillPoly(points : word;var polypoints);
|
||
{$R-}
|
||
type PointTypeArray = Array[0..0] of PointType;
|
||
|
||
{ Used to find the horizontal lines that
|
||
must be filled }
|
||
TLineSegmentInfo = Record
|
||
{range for check }
|
||
ymin,ymax,
|
||
{ line equation consts }
|
||
xcoef,ycoef,_const,
|
||
lastvalue : longint;
|
||
use_in_line : boolean;
|
||
End;
|
||
LineSegmentInfoArray = Array[0..0] of TLineSegmentInfo;
|
||
|
||
var
|
||
xmin,xmax,ymin,ymax : longint;
|
||
x1,x2,y1,y2,y,xdeb : longint;
|
||
i,j,curx,cury : longint;
|
||
newvalue : longint;
|
||
LineInfo : ^LineSegmentInfoArray;
|
||
PreviousInside,inside,side : boolean;
|
||
viewport : viewporttype;
|
||
begin
|
||
GetMem(LineInfo,(points+1)*SizeOf(TlineSegmentInfo));
|
||
xmax:=$80000000;xmin:=$7fffffff;
|
||
ymax:=$80000000;ymin:=$7fffffff;
|
||
for i:=0 to points-1 do
|
||
begin
|
||
if i=points-1 then
|
||
j:=0
|
||
else
|
||
j:=i+1;
|
||
x1:=PointTypeArray(polypoints)[i].x;
|
||
y1:=PointTypeArray(polypoints)[i].y;
|
||
x2:=PointTypeArray(polypoints)[j].x;
|
||
y2:=PointTypeArray(polypoints)[j].y;
|
||
if x1>xmax then
|
||
xmax:=x1;
|
||
if x1<xmin then
|
||
xmin:=x1;
|
||
if y1>ymax then
|
||
ymax:=y1;
|
||
if y1<ymin then
|
||
ymin:=y1;
|
||
if y1<y2 then
|
||
begin
|
||
LineInfo^[i].ymin:=y1;
|
||
LineInfo^[i].ymax:=y2;
|
||
end
|
||
else
|
||
begin
|
||
LineInfo^[i].ymin:=y2;
|
||
LineInfo^[i].ymax:=y1;
|
||
end;
|
||
LineInfo^[i].xcoef:=y2-y1;
|
||
LineInfo^[i].ycoef:=x1-x2;
|
||
LineInfo^[i]._const:=y1*x2-x1*y2;
|
||
end; { setting of LineInfo }
|
||
|
||
side:=true;
|
||
for i:=0 to points-1 do
|
||
begin
|
||
cury:=LineInfo^[i].ymin;
|
||
newvalue:=LineInfo^[i].xcoef*(xmin-1)+
|
||
LineInfo^[i].ycoef*cury+LineInfo^[i]._const;
|
||
if (newvalue<0) then
|
||
side:=not side;
|
||
end;
|
||
if aktviewport.clip then viewport:=aktviewport else viewport:=aktscreen;
|
||
{ reject invalid points !! }
|
||
|
||
viewport.x2:=viewport.x2-viewport.x1;
|
||
viewport.y2:=viewport.y2-viewport.y1;
|
||
viewport.x1:=0;
|
||
viewport.y1:=0;
|
||
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Rectangle (',xmin,',',ymin,'),(',xmax,',',ymax,')');
|
||
{$endif def GraphDebug}
|
||
if xmin<0 then xmin:=0;
|
||
if ymin<0 then ymin:=0;
|
||
if xmax>viewport.x2 then xmax:=viewport.x2;
|
||
if ymax>viewport.y2 then ymax:=viewport.y2;
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Rectangle (',xmin,',',ymin,'),(',xmax,',',ymax,')');
|
||
{$endif def GraphDebug}
|
||
|
||
for cury:=ymin to ymax do
|
||
begin
|
||
xdeb:=xmin;
|
||
PreviousInside:=true;
|
||
for i:=0 to points-1 do
|
||
begin
|
||
if cury<LineInfo^[i].ymin then
|
||
y:=LineInfo^[i].ymin
|
||
else if cury>LineInfo^[i].ymax then
|
||
y:=LineInfo^[i].ymax
|
||
else
|
||
y:=cury;
|
||
newvalue:=LineInfo^[i].xcoef*(xmin-1)+
|
||
LineInfo^[i].ycoef*y+LineInfo^[i]._const;
|
||
LineInfo^[i].lastvalue:=newvalue;
|
||
if (newvalue<0) then
|
||
PreviousInside:=not PreviousInside;
|
||
if (cury<LineInfo^[i].ymin) or (cury>=LineInfo^[i].ymax) then
|
||
LineInfo^[i].use_in_line:=false
|
||
else
|
||
LineInfo^[i].use_in_line:=true;
|
||
end;
|
||
PreviousInside:=(side<>PreviousInside);
|
||
inside:=PreviousInside;
|
||
for curx:=xmin to xmax do
|
||
begin
|
||
for i:=0 to points-1 do
|
||
if LineInfo^[i].use_in_line then
|
||
begin
|
||
newvalue:=LineInfo^[i].lastvalue+LineInfo^[i].xcoef;
|
||
if ((LineInfo^[i].lastvalue<0) and (newvalue>=0)) or
|
||
((LineInfo^[i].lastvalue>0) and (newvalue<=0)) then
|
||
begin
|
||
inside:=not inside;
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Line ',i,' crossed (',curx,',',cury,')');
|
||
Writeln(stderr,'Line x*',LineInfo^[i].xcoef,'+y*',
|
||
LineInfo^[i].ycoef,'+',LineInfo^[i]._const,'=0');
|
||
Writeln(stderr,'Old ',LineInfo^[i].lastvalue,' new ',newvalue);
|
||
{$endif def GraphDebug}
|
||
end;
|
||
LineInfo^[i].lastvalue:=newvalue;
|
||
end;
|
||
if inside<>PreviousInside then
|
||
if inside then
|
||
xdeb:=curx
|
||
else
|
||
begin
|
||
patternline(xdeb,curx,cury);
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Pattern (',xdeb,',',curx,') at ',cury);
|
||
{$endif def GraphDebug}
|
||
end;
|
||
PreviousInside:=inside;
|
||
end;
|
||
if inside then
|
||
begin
|
||
patternline(xdeb,xmax,cury);
|
||
{$ifdef GraphDebug}
|
||
Writeln(stderr,'Pattern (',xdeb,',',xmax,') at ',cury);
|
||
{$endif def GraphDebug}
|
||
end;
|
||
end;
|
||
|
||
FreeMem(LineInfo,(points+1)*SizeOf(TlineSegmentInfo));
|
||
{ simply call drawpoly instead (PM) }
|
||
DrawPoly(points,polypoints);
|
||
end;
|
||
|
||
|
||
{
|
||
$Log$
|
||
Revision 1.1 1998-12-21 13:07:03 peter
|
||
* use -FE
|
||
|
||
Revision 1.8 1998/11/25 22:59:24 pierre
|
||
* fillpoly works
|
||
|
||
Revision 1.7 1998/11/25 13:04:44 pierre
|
||
+ added multi page support
|
||
|
||
Revision 1.6 1998/11/20 18:42:07 pierre
|
||
* many bugs related to floodfill and ellipse fixed
|
||
|
||
Revision 1.5 1998/11/19 15:09:37 pierre
|
||
* several bugfixes for sector/ellipse/floodfill
|
||
+ graphic driver mode const in interface G800x600x256...
|
||
+ added backput mode as in linux graph.pp
|
||
(clears the background of textoutput)
|
||
|
||
Revision 1.4 1998/11/19 09:48:48 pierre
|
||
+ added some functions missing like sector ellipse getarccoords
|
||
(the filling of sector and ellipse is still buggy
|
||
I use floodfill but sometimes the starting point
|
||
is outside !!)
|
||
* fixed a bug in floodfill for patterns
|
||
(still has problems !!)
|
||
|
||
Revision 1.3 1998/11/18 13:23:34 pierre
|
||
* floodfill got into an infinite loop !!
|
||
+ added partial support for fillpoly
|
||
(still wrong if the polygon is not convex)
|
||
Simply make a floodfill from the barycenter !
|
||
* some 24BPP code changed (still does not work for my S3VBE program !)
|
||
|
||
Revision 1.2 1998/11/18 09:31:33 pierre
|
||
* changed color scheme
|
||
all colors are in RGB format if more than 256 colors
|
||
+ added 24 and 32 bits per pixel mode
|
||
(compile with -dDEBUG)
|
||
24 bit mode with banked still as problems on pixels across
|
||
the bank boundary, but works in LinearFrameBufferMode
|
||
Look at install/demo/nmandel.pp
|
||
|
||
Revision 1.1.1.1 1998/03/25 11:18:42 root
|
||
* Restored version
|
||
|
||
Revision 1.3 1998/01/26 11:57:57 michael
|
||
+ Added log at the end
|
||
|
||
|
||
|
||
Working file: rtl/dos/ppi/fill.ppi
|
||
description:
|
||
----------------------------
|
||
revision 1.2
|
||
date: 1997/12/01 12:21:29; author: michael; state: Exp; lines: +13 -1
|
||
+ added copyright reference in header.
|
||
----------------------------
|
||
revision 1.1
|
||
date: 1997/11/27 08:33:51; author: michael; state: Exp;
|
||
Initial revision
|
||
----------------------------
|
||
revision 1.1.1.1
|
||
date: 1997/11/27 08:33:51; author: michael; state: Exp; lines: +0 -0
|
||
FPC RTL CVS start
|
||
=============================================================================
|
||
}
|