summaryrefslogtreecommitdiff
path: root/src/corelib/gfx_wuline.pas
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/gfx_wuline.pas')
-rw-r--r--src/corelib/gfx_wuline.pas167
1 files changed, 167 insertions, 0 deletions
diff --git a/src/corelib/gfx_wuline.pas b/src/corelib/gfx_wuline.pas
new file mode 100644
index 00000000..ce5c403b
--- /dev/null
+++ b/src/corelib/gfx_wuline.pas
@@ -0,0 +1,167 @@
+{
+ fpGUI - Free Pascal GUI Library
+
+ Copyright (C) 2006 - 2007 See the file AUTHORS.txt, included in this
+ distribution, for details of the copyright.
+
+ See the file COPYING.modifiedLGPL, included in this distribution,
+ for details about redistributing fpGUI.
+
+ 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.
+
+ Description:
+
+ A Object Pascal implemenation of Wu Anti-Aliased Lines.
+ For details about the algorithm have a look at:
+ http://freespace.virgin.net/hugo.elias/graphics/x_wuline.htm
+ Here is an implementation in C++
+ http://www.codeproject.com/gdi/antialias.asp
+}
+unit gfx_wuline;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, gfxbase, fpgfx;
+
+
+procedure WuLine(ACanvas: TfpgCanvas; Point1, Point2: TPoint; AColor: TfpgColor);
+procedure DrawWuCircle(Canvas: TfpgCanvas; x, y, r: integer; AColor: TfpgColor);
+
+
+implementation
+
+
+type
+ // to get access to Protected fields
+ TCanvasHack = class(TfpgCanvas);
+
+
+// Blend a pixel with the current colour
+procedure AlphaBlendPixel(ACanvas: TfpgCanvas; X, Y: integer; R, G, B: word; ARatio: Double);
+var
+ LBack, LNew: TRGBTriple;
+ LMinusRatio: Double;
+begin
+ if (X < 0) or (X > TCanvasHack(ACanvas).FWindow.Width - 1) or (Y < 0) or
+ (Y > TCanvasHack(ACanvas).FWindow.Height - 1) then
+ Exit; // clipping
+
+ LMinusRatio := 1 - ARatio;
+ LBack := fpgColorToRGBTriple(ACanvas.Pixels[X, Y]);
+ LNew.Blue := round(B*ARatio + LBack.Blue*LMinusRatio);
+ LNew.Green := round(G*ARatio + LBack.Green*LMinusRatio);
+ LNew.Red := round(R*ARatio + LBack.Red*LMinusRatio);
+ ACanvas.Pixels[X, Y] := RGBTripleTofpgColor(LNew);
+end;
+
+// Draw a anti-aliased line
+procedure WuLine(ACanvas: TfpgCanvas; Point1, Point2: TPoint; AColor: TfpgColor);
+var
+ deltax, deltay, loop, start, finish: integer;
+ dx, dy, dydx: single; // fractional parts
+ LR, LG, LB: word;
+ x1, x2, y1, y2: integer;
+begin
+ x1 := Point1.X;
+ y1 := Point1.Y;
+ x2 := Point2.X;
+ y2 := Point2.Y;
+ deltax := abs(x2 - x1); // Calculate deltax and deltay for initialisation
+ deltay := abs(y2 - y1);
+
+ if (deltax = 0) or (deltay = 0) then // straight lines
+ begin
+ ACanvas.SetColor(AColor);
+ ACanvas.DrawLine(x1, y1, x2, y2);
+ Exit; //==>
+ end;
+ LR := fpgGetRed(AColor);
+ LG := fpgGetGreen(AColor);
+ LB := fpgGetBlue(AColor);
+ if deltax > deltay then
+ begin // horizontal or vertical
+ if y2 > y1 then // determine rise and run
+ dydx := -(deltay / deltax)
+ else
+ dydx := deltay / deltax;
+
+ if x2 < x1 then
+ begin
+ start := x2; // right to left
+ finish := x1;
+ dy := y2;
+ end
+ else
+ begin
+ start := x1; // left to right
+ finish := x2;
+ dy := y1;
+ dydx := -dydx; // inverse slope
+ end;
+
+ for loop := start to finish do
+ begin
+ AlphaBlendPixel(ACanvas, loop, trunc(dy), LR, LG, LB, 1 - frac(dy));
+ AlphaBlendPixel(ACanvas, loop, trunc(dy) + 1, LR, LG, LB, frac(dy));
+ dy := dy + dydx; // next point
+ end;
+ end
+ else
+ begin
+ if x2 > x1 then // determine rise and run
+ dydx := -(deltax / deltay)
+ else
+ dydx := deltax / deltay;
+
+ if y2 < y1 then
+ begin
+ start := y2; // right to left
+ finish := y1;
+ dx := x2;
+ end
+ else
+ begin
+ start := y1; // left to right
+ finish := y2;
+ dx := x1;
+ dydx := -dydx; // inverse slope
+ end;
+
+ for loop := start to finish do
+ begin
+ AlphaBlendPixel(ACanvas, trunc(dx), loop, LR, LG, LB, 1 - frac(dx));
+ AlphaBlendPixel(ACanvas, trunc(dx) + 1, loop, LR, LG, LB, frac(dx));
+ dx := dx + dydx; // next point
+ end;
+ end;
+end;
+
+// A very basic circle implementation. Not to pretty, but it works.
+procedure DrawWuCircle(Canvas: TfpgCanvas; x, y, r: integer; AColor: TfpgColor);
+var
+ x1, y1, x2, y2: integer;
+ dt: integer;
+ theta: integer;
+begin
+ theta := 0;
+ dt := 4;
+ while theta < 360 do
+ begin
+ x1 := round( r*cos(theta*pi/180.0)+x);
+ y1 := round(-r*sin(theta*pi/180.0)+y);
+
+ x2 := round( r*cos((theta+dt)*pi/180.0)+x);
+ y2 := round(-r*sin((theta+dt)*pi/180.0)+y);
+
+ WuLine(Canvas, Point(x1, y1), Point(x2, y2), AColor);
+ theta := theta + dt;
+ end;
+end;
+
+end.
+