1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 2003 by the Free Pascal development team
- Pixel drawing routines.
- 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.
- **********************************************************************}
- {$mode objfpc}{$h+}
- unit PixTools;
- interface
- uses classes, FPCanvas, FPimage;
- procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
- procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern; const color:TFPColor);
- procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
- procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern; const color:TFPColor);
- procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
- procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern; const color:TFPColor);
- procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer);
- procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern);
- procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern);
- procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer);
- procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer);
- procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern);
- procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- procedure FillRectangleImage (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
- procedure FillRectangleImageRel (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
- procedure FillFloodImage (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
- procedure FillFloodImageRel (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
- implementation
- uses clipping, ellipses;
- procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer);
- begin
- FillRectangleColor (Canv, x1,y1, x2,y2, Canv.Brush.FPColor);
- end;
- procedure FillRectangleColor (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
- var x,y : integer;
- begin
- SortRect (x1,y1, x2,y2);
- with Canv do
- begin
- for x := x1 to x2 do
- for y := y1 to y2 do
- colors[x,y] := color;
- end;
- end;
- {procedure DrawSolidPolyLine (Canv : TFPCustomCanvas; points:array of TPoint; close:boolean);
- var i,a, r : integer;
- p : TPoint;
- begin
- i := low(points);
- a := high(points);
- p := points[i];
- with Canv do
- begin
- for r := i+1 to a do
- begin
- Line (p.x, p.y, points[r].x, points[r].y);
- p := points[r];
- end;
- if close then
- Line (p.x,p.y, points[i].x,points[i].y);
- end;
- end;
- }
- type
- TPutPixelProc = procedure (Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
- procedure PutPixelCopy(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
- begin
- with Canv do
- Colors[x,y] := color;
- end;
- procedure PutPixelXor(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
- begin
- with Canv do
- Colors[x,y] := Colors[x,y] xor color;
- end;
- procedure PutPixelOr(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
- begin
- with Canv do
- Colors[x,y] := Colors[x,y] or color;
- end;
- procedure PutPixelAnd(Canv:TFPCustomCanvas; x,y:integer; color:TFPColor);
- begin
- with Canv do
- Colors[x,y] := Colors[x,y] and color;
- end;
- procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer);
- begin
- DrawSolidLine (Canv, x1,y1, x2,y2, Canv.Pen.FPColor);
- end;
- procedure DrawSolidLine (Canv : TFPCustomCanvas; x1,y1, x2,y2:integer; const color:TFPColor);
- var PutPixelProc : TPutPixelProc;
- procedure HorizontalLine (x1,x2,y:integer);
- var x : integer;
- begin
- for x := x1 to x2 do
- PutPixelProc (Canv, x,y, color);
- end;
- procedure VerticalLine (x,y1,y2:integer);
- var y : integer;
- begin
- for y := y1 to y2 do
- PutPixelProc (Canv, x,y, color);
- end;
- procedure SlopedLine;
- var npixels,xinc1,yinc1,xinc2,yinc2,dx,dy,d,dinc1,dinc2 : integer;
- procedure initialize;
- begin // precalculations
- dx := abs(x2-x1);
- dy := abs(y2-y1);
- if dx > dy then // determining independent variable
- begin // x is independent
- npixels := dx + 1;
- d := (2 * dy) - dx;
- dinc1 := dy * 2;
- dinc2:= (dy - dx) * 2;
- xinc1 := 1;
- xinc2 := 1;
- yinc1 := 0;
- yinc2 := 1;
- end
- else
- begin // y is independent
- npixels := dy + 1;
- d := (2 * dx) - dy;
- dinc1 := dx * 2;
- dinc2:= (dx - dy) * 2;
- xinc1 := 0;
- xinc2 := 1;
- yinc1 := 1;
- yinc2 := 1;
- end;
- // going into the correct direction
- if x1 > x2 then
- begin
- xinc1 := - xinc1;
- xinc2 := - xinc2;
- end;
- if y1 > y2 then
- begin
- yinc1 := - yinc1;
- yinc2 := - yinc2;
- end;
- end;
- var r,x,y : integer;
- begin
- initialize;
- x := x1;
- y := y1;
- for r := 1 to nPixels do
- begin
- PutPixelProc (Canv, x,y, color);
- if d < 0 then
- begin
- d := d + dinc1;
- x := x + xinc1;
- y := y + yinc1;
- end
- else
- begin
- d := d + dinc2;
- x := x + xinc2;
- y := y + yinc2;
- end;
- end;
- end;
- begin
- with canv.pen do
- case mode of
- pmMerge : PutPixelProc := @PutPixelAnd;
- pmMask : PutPixelProc := @PutPixelOr;
- pmXor : PutPixelProc := @PutPixelXor;
- else PutPixelProc := @PutPixelCopy;
- end;
- if x1 = x2 then // vertical line
- if y1 < y2 then
- VerticalLine (x1, y1, y2)
- else
- VerticalLine (x1, y2, y1)
- else if y1 = y2 then
- if x1 < x2 then
- HorizontalLine (x1, x2, y1)
- else
- HorizontalLine (x2, x1, y1)
- else // sloped line
- SlopedLine;
- end;
- type
- TLinePoints = array[0..PatternBitCount-1] of boolean;
- PLinePoints = ^TLinePoints;
- procedure PatternToPoints (const APattern:TPenPattern; LinePoints:PLinePoints);
- var r : integer;
- i : longword;
- begin
- i := 1;
- for r := PatternBitCount-1 downto 1 do
- begin
- LinePoints^[r] := (APattern and i) <> 0;
- i := i shl 1;
- end;
- LinePoints^[0] := (APattern and i) <> 0;
- end;
- procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern);
- begin
- DrawPatternLine (Canv, x1,y1, x2,y2, pattern, Canv.Pen.FPColor);
- end;
- procedure DrawPatternLine (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; Pattern:TPenPattern; const color:TFPColor);
- // Is copy of DrawSolidLine with paterns added. Not the same procedure for faster solid lines
- var LinePoints : TLinePoints;
- PutPixelProc : TPutPixelProc;
- procedure HorizontalLine (x1,x2,y:integer);
- var x : integer;
- begin
- for x := x1 to x2 do
- if LinePoints[x mod PatternBitCount] then
- PutPixelProc (Canv, x,y, color);
- end;
- procedure VerticalLine (x,y1,y2:integer);
- var y : integer;
- begin
- for y := y1 to y2 do
- if LinePoints[y mod PatternBitCount] then
- PutPixelProc (Canv, x,y, color);
- end;
- procedure SlopedLine;
- var npixels,xinc1,yinc1,xinc2,yinc2,dx,dy,d,dinc1,dinc2 : integer;
- procedure initialize;
- begin // precalculations
- dx := abs(x2-x1);
- dy := abs(y2-y1);
- if dx > dy then // determining independent variable
- begin // x is independent
- npixels := dx + 1;
- d := (2 * dy) - dx;
- dinc1 := dy * 2;
- dinc2:= (dy - dx) * 2;
- xinc1 := 1;
- xinc2 := 1;
- yinc1 := 0;
- yinc2 := 1;
- end
- else
- begin // y is independent
- npixels := dy + 1;
- d := (2 * dx) - dy;
- dinc1 := dx * 2;
- dinc2:= (dx - dy) * 2;
- xinc1 := 0;
- xinc2 := 1;
- yinc1 := 1;
- yinc2 := 1;
- end;
- // going into the correct direction
- if x1 > x2 then
- begin
- xinc1 := - xinc1;
- xinc2 := - xinc2;
- end;
- if y1 > y2 then
- begin
- yinc1 := - yinc1;
- yinc2 := - yinc2;
- end;
- end;
- var r,x,y : integer;
- begin
- initialize;
- x := x1;
- y := y1;
- for r := 1 to nPixels do
- begin
- if LinePoints[r mod PatternBitCount] then
- PutPixelProc (Canv, x,y, color);
- if d < 0 then
- begin
- d := d + dinc1;
- x := x + xinc1;
- y := y + yinc1;
- end
- else
- begin
- d := d + dinc2;
- x := x + xinc2;
- y := y + yinc2;
- end;
- end;
- end;
- begin
- PatternToPoints (pattern, @LinePoints);
- with canv.pen do
- case mode of
- pmMask : PutPixelProc := @PutPixelAnd;
- pmMerge : PutPixelProc := @PutPixelOr;
- pmXor : PutPixelProc := @PutPixelXor;
- else PutPixelProc := @PutPixelCopy;
- end;
- if x1 = x2 then // vertical line
- if y1 < y2 then
- VerticalLine (x1, y1, y2)
- else
- VerticalLine (x1, y2, y1)
- else if y1 = y2 then
- if x1 < x2 then
- HorizontalLine (x1, x2, y1)
- else
- HorizontalLine (x2, x1, y1)
- else // sloped line
- SlopedLine;
- end;
- procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- begin
- FillRectangleHashHorizontal (Canv, rect, width, Canv.Brush.FPColor);
- end;
- procedure FillRectangleHashHorizontal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- var y : integer;
- begin
- with rect do
- begin
- y := Width + top;
- while y <= bottom do
- begin
- DrawSolidLine (Canv, left,y, right,y, c);
- inc (y,Width);
- end
- end;
- end;
- procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- begin
- FillRectangleHashVertical (Canv, rect, width, Canv.Brush.FPColor);
- end;
- procedure FillRectangleHashVertical (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- var x : integer;
- begin
- with rect do
- begin
- x := Width + left;
- while x <= right do
- begin
- DrawSolidLine (Canv, x,top, x,bottom, c);
- inc (x, Width);
- end;
- end;
- end;
- procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- begin
- FillRectangleHashDiagonal (Canv, rect, width, Canv.Brush.FPColor);
- end;
- procedure FillRectangleHashDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- function CheckCorner (Current, max, start : integer) : integer;
- begin
- if Current > max then
- result := Start + current - max
- else
- result := Start;
- end;
- var r, rx, ry : integer;
- begin
- with rect do
- begin
- // draw from bottom-left corner away
- ry := top + Width;
- rx := left + Width;
- while (rx < right) and (ry < bottom) do
- begin
- DrawSolidLine (Canv, left,ry, rx,top, c);
- inc (rx, Width);
- inc (ry, Width);
- end;
- // check which turn need to be taken: left-bottom, right-top, or both
- if (rx >= right) then
- begin
- if (ry >= bottom) then
- begin // Both corners reached
- r := CheckCorner (rx, right, top);
- rx := CheckCorner (ry, bottom, left);
- ry := r;
- end
- else
- begin // fill vertical
- r := CheckCorner (rx, right, top);
- while (ry < bottom) do
- begin
- DrawSolidLine (Canv, left,ry, right,r, c);
- inc (r, Width);
- inc (ry, Width);
- end;
- rx := CheckCorner (ry, bottom, left);
- ry := r;
- end
- end
- else
- if (ry >= bottom) then
- begin // fill horizontal
- r := checkCorner (ry, bottom, left);
- while (rx <= right) do
- begin
- DrawSolidLine (Canv, r,bottom, rx,top, c);
- inc (r, Width);
- inc (rx, Width);
- end;
- ry := CheckCorner (rx, right, top);
- rx := r;
- end;
- while (rx < right) do // fill lower right corner
- begin
- DrawSolidLine (Canv, rx,bottom, right,ry, c);
- inc (rx, Width);
- inc (ry, Width);
- end;
- end;
- end;
- procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer);
- begin
- FillRectangleHashBackDiagonal (Canv, rect, width, Canv.Brush.FPColor);
- end;
- procedure FillRectangleHashBackDiagonal (Canv:TFPCustomCanvas; const rect:TRect; width:integer; const c:TFPColor);
- function CheckInversCorner (Current, min, start : integer) : integer;
- begin
- if Current < min then
- result := Start - current + min
- else
- result := Start;
- end;
- function CheckCorner (Current, max, start : integer) : integer;
- begin
- if Current > max then
- result := Start - current + max
- else
- result := Start;
- end;
- var r, rx, ry : integer;
- begin
- with rect do
- begin
- // draw from bottom-left corner away
- ry := bottom - Width;
- rx := left + Width;
- while (rx < right) and (ry > top) do
- begin
- DrawSolidLine (Canv, left,ry, rx,bottom, c);
- inc (rx, Width);
- dec (ry, Width);
- end;
- // check which turn need to be taken: left-top, right-bottom, or both
- if (rx >= right) then
- begin
- if (ry <= top) then
- begin // Both corners reached
- r := CheckCorner (rx, right, bottom);
- rx := CheckInversCorner (ry, top, left);
- ry := r;
- end
- else
- begin // fill vertical
- r := CheckCorner (rx, right, bottom);
- while (ry > top) do
- begin
- DrawSolidLine (Canv, left,ry, right,r, c);
- dec (r, Width);
- dec (ry, Width);
- end;
- rx := CheckInversCorner (ry, top, left);
- ry := r;
- end
- end
- else
- if (ry <= top) then
- begin // fill horizontal
- r := checkInversCorner (ry, top, left);
- while (rx < right) do
- begin
- DrawSolidLine (Canv, r,top, rx,bottom, c);
- inc (r, Width);
- inc (rx, Width);
- end;
- ry := CheckCorner (rx, right, bottom);
- rx := r;
- end;
- while (rx < right) do // fill upper right corner
- begin
- DrawSolidLine (Canv, rx,top, right,ry, c);
- inc (rx, Width);
- dec (ry, Width);
- end;
- end;
- end;
- procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern);
- begin
- FillRectanglePattern (Canv, x1,y1, x2,y2, pattern, Canv.Brush.FPColor);
- end;
- procedure FillRectanglePattern (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const pattern:TBrushPattern; const color:TFPColor);
- var r : integer;
- begin
- for r := y1 to y2 do
- DrawPatternLine (Canv, x1,r, x2,r, pattern[r mod PatternBitCount], color);
- end;
- procedure FillRectangleImage (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
- var x,y : integer;
- begin
- with image do
- for x := x1 to x2 do
- for y := y1 to y2 do
- Canv.colors[x,y] := colors[x mod width, y mod height];
- end;
- procedure FillRectangleImageRel (Canv:TFPCustomCanvas; x1,y1, x2,y2:integer; const Image:TFPCustomImage);
- var x,y : integer;
- begin
- with image do
- for x := x1 to x2 do
- for y := y1 to y2 do
- Canv.colors[x,y] := colors[(x-x1) mod width, (y-y1) mod height];
- end;
- type
- TFuncSetColor = procedure (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- PDoneRec = ^TDoneRec;
- TDoneRec = record
- x, min, max : integer;
- next : PDoneRec;
- end;
- PFloodFillData = ^TFloodFillData;
- TFloodFillData = record
- Canv : TFPCustomCanvas;
- ReplColor : TFPColor;
- SetColor : TFuncSetColor;
- ExtraData : pointer;
- DoneList : TList;
- end;
- function FindDoneIndex (const data:PFloodFillData; x:integer; var index:integer):boolean;
- begin
- with data^.DoneList do
- begin
- index := 0;
- while (index < count) and (PDoneRec(items[index])^.x <> x) do
- inc (index);
- result := (index < count) and (PDoneRec(items[index])^.x = x);
- end;
- end;
- procedure FreeDoneList (const data:TFloodFillData);
- procedure FreeList (p:PDoneRec);
- var n : PDoneRec;
- begin
- while assigned(p) do
- begin
- n := p^.Next;
- dispose (p);
- p := n;
- end;
- end;
- var r : integer;
- begin
- with data do
- for r := 0 to DoneList.Count-1 do
- FreeList (PDoneRec(DoneList[r]));
- end;
- procedure CheckFloodFillColor (x,top,bottom,Direction:integer; data:PFloodFillData);
- procedure CheckRange;
- var r,t,b : integer;
- begin
- t := top;
- b := top -1;
- for r := top to bottom do
- with data^ do
- begin
- if canv.colors[x,r] = ReplColor then
- begin
- b := r;
- SetColor(Canv,x,r,ExtraData);
- end
- else
- begin
- if t < r then
- CheckFloodFillColor (x+Direction, t, r-1, Direction, data);
- t := r + 1;
- end;
- end;
- if t <= b then
- CheckFloodFillColor (x+Direction, t, b, Direction, data);
- end;
- procedure CheckAboveRange;
- var t,b : integer;
- begin
- with data^ do
- begin
- t := top - 1;
- while (t >= 0) and (Canv.colors[x,t]=ReplColor) do
- begin
- SetColor(Canv, x,t, ExtraData);
- dec (t);
- end;
- t := t + 1;
- b := top - 1;
- if t <= b then
- begin
- CheckFloodFillColor (x-1, t, b, -1, data);
- CheckFloodFillColor (x+1, t, b, 1, data);
- end;
- end;
- end;
- procedure CheckBelowRange;
- var r,t,b : integer;
- begin
- with data^ do
- begin
- r := Canv.Height;
- b := bottom + 1;
- t := b;
- while (b < r) and (Canv.colors[x,b]=ReplColor) do
- begin
- SetColor (Canv,x,b,ExtraData);
- inc (b);
- end;
- b := b - 1;
- if t <= b then
- begin
- CheckFloodFillColor (x-1, t, b, -1, data);
- CheckFloodFillColor (x+1, t, b, 1, data);
- end;
- end;
- end;
- var DoAbove, DoBelow : boolean;
- begin
- with data^ do
- begin
- if (x >= Canv.width) or (x < 0) then
- Exit;
- if top < 0 then
- top := 0;
- if bottom >= Canv.Height then
- bottom := Canv.Height-1;
- DoAbove := (Canv.colors[x,top] = ReplColor);
- DoBelow := (Canv.colors[x,bottom] = ReplColor);
- end;
- CheckRange;
- if DoAbove then
- CheckAboveRange;
- if DoBelow then
- CheckBelowRange;
- end;
- procedure CheckFloodFill (x,top,bottom,Direction:integer; data:PFloodFillData);
- var beforetop, ontop, chain, myrec : PDoneRec;
- doneindex : integer;
- procedure CheckRange;
- var r,t,b : integer;
- n : PDoneRec;
- begin
- ontop := nil;
- beforetop := nil;
- n := chain;
- while (n <> nil) and (n^.min <= top) do
- begin
- beforetop := ontop;
- ontop := n;
- n := n^.next;
- end;
- if assigned(ontop) and (ontop^.max < top) then
- begin
- beforetop := ontop;
- ontop := nil;
- end;
- // ontop is: nil OR rec before top OR rec containing top
- if assigned(ontop) then
- begin
- t := ontop^.max + 1;
- myrec := ontop;
- end
- else
- begin
- t := top;
- new(myrec);
- myrec^.x := x;
- myrec^.min := top;
- myrec^.max := top;
- myrec^.Next := n;
- if assigned(beforetop) then
- beforetop^.next := myrec
- else
- begin
- with data^.DoneList do
- if DoneIndex < Count then
- Items[DoneIndex] := myrec
- else
- Add (myrec);
- chain := myrec;
- end;
- end;
- ontop := myrec;
- // ontop is rec containing the top
- b := t-1;
- r := t;
- while (r <= bottom) do
- begin
- with data^ do
- begin
- if canv.colors[x,r] = ReplColor then
- begin
- b := r;
- SetColor(Canv,x,r,ExtraData);
- end
- else
- begin
- if t < r then
- begin
- myrec^.max := r;
- CheckFloodFill (x+Direction, t, r-1, Direction, data);
- end;
- t := r + 1;
- end;
- inc (r);
- end;
- if assigned(n) and (r >= n^.min) then
- begin
- if t < r then
- begin
- myrec^.max := n^.min-1;
- CheckFloodFill (x+Direction, t, r-1, Direction, data);
- end;
- while assigned(n) and (r >= n^.min) do
- begin
- myrec := n;
- r := myrec^.max + 1;
- n := n^.next;
- end;
- t := r;
- end;
- end;
- myrec^.max := r - 1;
- if t <= b then
- CheckFloodFill (x+Direction, t, b, Direction, data);
- end;
- procedure CheckAboveRange (highest:integer);
- var t,b : integer;
- begin
- with data^ do
- begin
- t := top - 1;
- while (t >= highest) and (Canv.colors[x,t]=ReplColor) do
- begin
- SetColor(Canv, x,t, ExtraData);
- dec (t);
- end;
- t := t + 1;
- b := top - 1;
- if t <= b then
- begin
- ontop^.min := t - 1;
- CheckFloodFill (x-1, t, b, -1, data);
- CheckFloodFill (x+1, t, b, 1, data);
- end;
- end;
- end;
- procedure CheckBelowRange (lowest : integer);
- var t,b : integer;
- begin
- with data^ do
- begin
- b := bottom + 1;
- t := b;
- while (b <= lowest) and (Canv.colors[x,b]=ReplColor) do
- begin
- SetColor (Canv,x,b,ExtraData);
- inc (b);
- end;
- b := b - 1;
- if t <= b then
- begin
- myrec^.max := b+1;
- CheckFloodFill (x-1, t, b, -1, data);
- CheckFloodFill (x+1, t, b, 1, data);
- end;
- end;
- end;
- var DoAbove, DoBelow : boolean;
- m : integer;
- begin
- with data^ do
- begin
- if (x >= Canv.width) or (x < 0) then
- Exit;
- if top < 0 then
- top := 0;
- if bottom >= Canv.Height then
- bottom := Canv.Height-1;
- DoAbove := (Canv.colors[x,top] = ReplColor);
- DoBelow := (Canv.colors[x,bottom] = ReplColor);
- end;
- if FindDoneIndex (data, x, DoneIndex) then
- begin
- chain := PDoneRec(data^.DoneList[DoneIndex]);
- myrec := chain;
- while assigned(myrec) do
- with myrec^ do
- myrec := next;
- end
- else
- chain := nil;
- CheckRange;
- // ontop: rec containing top
- // myrec: rec containing bottom
- if DoAbove and (ontop^.min = top) then
- begin
- if assigned (beforetop) then
- m := beforetop^.max + 1
- else
- m := 0;
- CheckAboveRange (m);
- end;
- if DoBelow and (myrec^.max = bottom) then
- begin
- if assigned (myrec^.next) then
- m := myrec^.next^.min - 1
- else
- m := data^.Canv.Height - 1;
- CheckBelowRange (m);
- end;
- end;
- procedure SetFloodColor (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- begin
- Canv.colors[x,y] := PFPColor(data)^;
- end;
- procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer; const color:TFPColor);
- var d : TFloodFillData;
- begin
- d.Canv := canv;
- d.ReplColor := Canv.colors[x,y];
- d.SetColor := @SetFloodColor;
- d.ExtraData := @color;
- CheckFloodFillColor (x, y, y, 1, @d);
- end;
- procedure FillFloodColor (Canv:TFPCustomCanvas; x,y:integer);
- begin
- FillFloodColor (Canv, x, y, Canv.Brush.FPColor);
- end;
- type
- TBoolPlane = array[0..PatternBitCount-1] of TLinePoints;
- TFloodPatternRec = record
- plane : TBoolPlane;
- color : TFPColor;
- end;
- PFloodPatternRec = ^TFloodPatternRec;
- procedure SetFloodPattern (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var p : PFloodPatternRec;
- begin
- p := PFloodPatternRec(data);
- if p^.plane[x mod PatternBitCount, y mod PatternBitCount] then
- Canv.colors[x,y] := p^.color;
- end;
- procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern; const color:TFPColor);
- var rec : TFloodPatternRec;
- d : TFloodFillData;
- procedure FillPattern;
- var r : integer;
- begin
- for r := 0 to PatternBitCount-1 do
- PatternToPoints (pattern[r], @rec.plane[r]);
- end;
- begin
- d.Canv := canv;
- d.ReplColor := Canv.colors[x,y];
- d.SetColor := @SetFloodPattern;
- d.ExtraData := @rec;
- d.DoneList := TList.Create;
- try
- FillPattern;
- rec.color := Color;
- CheckFloodFill (x, y, y, 1, @d);
- finally
- FreeDoneList (d);
- end;
- end;
- procedure FillFloodPattern (Canv:TFPCustomCanvas; x,y:integer; const pattern:TBrushPattern);
- begin
- FillFloodPattern (Canv, x, y, pattern, Canv.Brush.FPColor);
- end;
- type
- TFloodHashRec = record
- color : TFPColor;
- width : integer;
- end;
- PFloodHashRec = ^TFloodHashRec;
- procedure SetFloodHashHor(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodHashRec;
- begin
- r := PFloodHashRec(data);
- if (y mod r^.width) = 0 then
- Canv.colors[x,y] := r^.color;
- end;
- procedure SetFloodHashVer(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodHashRec;
- begin
- r := PFloodHashRec(data);
- if (x mod r^.width) = 0 then
- Canv.colors[x,y] := r^.color;
- end;
- procedure SetFloodHashDiag(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodHashRec;
- w : integer;
- begin
- r := PFloodHashRec(data);
- w := r^.width;
- if ((x mod w) + (y mod w)) = (w - 1) then
- Canv.colors[x,y] := r^.color;
- end;
- procedure SetFloodHashBDiag(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodHashRec;
- w : 0..PatternBitCount-1;
- begin
- r := PFloodHashRec(data);
- w := r^.width;
- if (x mod w) = (y mod w) then
- Canv.colors[x,y] := r^.color;
- end;
- procedure SetFloodHashCross(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodHashRec;
- w : 0..PatternBitCount-1;
- begin
- r := PFloodHashRec(data);
- w := r^.width;
- if ((x mod w) = 0) or ((y mod w) = 0) then
- Canv.colors[x,y] := r^.color;
- end;
- procedure SetFloodHashDiagCross(Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodHashRec;
- w : 0..PatternBitCount-1;
- begin
- r := PFloodHashRec(data);
- w := r^.width;
- if ( (x mod w) = (y mod w) ) or
- ( ((x mod w) + (y mod w)) = (w - 1) ) then
- Canv.colors[x,y] := r^.color;
- end;
- procedure FillFloodHash (Canv:TFPCustomCanvas; x,y:integer; width:integer; SetHashColor:TFuncSetColor; const c:TFPColor);
- var rec : TFloodHashRec;
- d : TFloodFillData;
- begin
- d.Canv := canv;
- d.ReplColor := Canv.colors[x,y];
- d.SetColor := SetHashColor;
- d.ExtraData := @rec;
- d.DoneList := TList.Create;
- rec.color := c;
- rec.width := Width;
- try
- CheckFloodFill (x, y, y, 1, @d);
- finally
- FreeDoneList (d);
- end;
- end;
- procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- begin
- FillFloodHash (canv, x, y, width, @SetFloodHashHor, c);
- end;
- procedure FillFloodHashHorizontal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- begin
- FillFloodHashHorizontal (Canv, x, y, width, Canv.Brush.FPColor);
- end;
- procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- begin
- FillFloodHash (canv, x, y, width, @SetFloodHashVer, c);
- end;
- procedure FillFloodHashVertical (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- begin
- FillFloodHashVertical (Canv, x, y, width, Canv.Brush.FPColor);
- end;
- procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- begin
- FillFloodHash (canv, x, y, width, @SetFloodHashDiag, c);
- end;
- procedure FillFloodHashDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- begin
- FillFloodHashDiagonal (Canv, x, y, width, Canv.Brush.FPColor);
- end;
- procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- begin
- FillFloodHash (canv, x, y, width, @SetFloodHashBDiag, c);
- end;
- procedure FillFloodHashBackDiagonal (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- begin
- FillFloodHashBackDiagonal (Canv, x, y, width, Canv.Brush.FPColor);
- end;
- procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- begin
- FillFloodHash (canv, x, y, width, @SetFloodHashDiagCross, c);
- end;
- procedure FillFloodHashDiagCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- begin
- FillFloodHashDiagCross (Canv, x, y, width, Canv.Brush.FPColor);
- end;
- procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer; const c:TFPColor);
- begin
- FillFloodHash (canv, x, y, width, @SetFloodHashCross, c);
- end;
- procedure FillFloodHashCross (Canv:TFPCustomCanvas; x,y:integer; width:integer);
- begin
- FillFloodHashCross (Canv, x, y, width, Canv.Brush.FPColor);
- end;
- type
- TFloodImageRec = record
- xo,yo : integer;
- image : TFPCustomImage;
- end;
- PFloodImageRec = ^TFloodImageRec;
- procedure SetFloodImage (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodImageRec;
- begin
- r := PFloodImageRec(data);
- with r^.image do
- Canv.colors[x,y] := colors[x mod width, y mod height];
- end;
- procedure FillFloodImage (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
- var rec : TFloodImageRec;
- d : TFloodFillData;
- begin
- d.Canv := canv;
- d.ReplColor := Canv.colors[x,y];
- d.SetColor := @SetFloodImage;
- d.ExtraData := @rec;
- d.DoneList := Tlist.Create;
- rec.image := image;
- try
- CheckFloodFill (x, y, y, 1, @d);
- finally
- FreeDoneList (d);
- end;
- end;
- procedure SetFloodImageRel (Canv:TFPCustomCanvas; x,y:integer; data:pointer);
- var r : PFloodImageRec;
- xi, yi : integer;
- begin
- r := PFloodImageRec(data);
- with r^, image do
- begin
- xi := (x - xo) mod width;
- if xi < 0 then
- xi := width - xi;
- yi := (y - yo) mod height;
- if yi < 0 then
- yi := height - yi;
- Canv.colors[x,y] := colors[xi,yi];
- end;
- end;
- procedure FillFloodImageRel (Canv:TFPCustomCanvas; x,y :integer; const Image:TFPCustomImage);
- var rec : TFloodImageRec;
- d : TFloodFillData;
- begin
- d.Canv := canv;
- d.ReplColor := Canv.colors[x,y];
- d.SetColor := @SetFloodImageRel;
- d.ExtraData := @rec;
- d.DoneList := TList.Create;
- rec.image := image;
- rec.xo := x;
- rec.yo := y;
- try
- CheckFloodFill (x, y, y, 1, @d);
- finally
- FreeDoneList (d);
- end;
- end;
- end.
|