Skip to content

Commit

Permalink
Add (fake) alpha param to DrawBoxFilled, DrawPolygonFilled, DrawCircl…
Browse files Browse the repository at this point in the history
…eFilled

Optimize DrawFilledPolygon (and therefore DrawQuadFilled)
Rename BlockBlur to BoxBlur
  • Loading branch information
ollydev committed Nov 18, 2023
1 parent 8dcd0dc commit 25b5ec6
Show file tree
Hide file tree
Showing 11 changed files with 469 additions and 282 deletions.
21 changes: 20 additions & 1 deletion Source/colormath/simba.colormath.pas
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ interface
PColor = ^TColor;

TColorHelper = type helper for TColor
function R: Byte; inline;
function G: Byte; inline;
function B: Byte; inline;

function ToBGRA: TColorBGRA;
function ToRGB: TColorRGB;
function ToXYZ: TColorXYZ;
Expand Down Expand Up @@ -257,7 +261,7 @@ function TColorBGRA_Helper.ToHSL: TColorHSL;

function TColorBGRA_Helper.ToColor: TColor;
begin
Result := TSimbaColorConversion.RGBToColor(ToRGB());
Result := TSimbaColorConversion.BGRAToColor(Self);
end;

function TColorBGRA_Helper.Equals(const Other: TColorBGRA): Boolean;
Expand Down Expand Up @@ -305,6 +309,21 @@ function TColorRGB_Helper.ToColor: TColor;
Result := TSimbaColorConversion.RGBToColor(Self);
end;

function TColorHelper.R: Byte;
begin
Result := Self shr R_BIT and $FF;
end;

function TColorHelper.G: Byte;
begin
Result := Self shr G_BIT and $FF;
end;

function TColorHelper.B: Byte;
begin
Result := Self shr B_BIT and $FF;
end;

function TColorHelper.ToBGRA: TColorBGRA;
begin
Result := TSimbaColorConversion.ColorToBGRA(Self);
Expand Down
11 changes: 9 additions & 2 deletions Source/colormath/simba.colormath_conversion.pas
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
{$DEFINE B_BIT := 16}
{$DEFINE G_BIT := 8}
{$DEFINE R_BIT := 0}
{$DEFINE A_BIT := 24}

{$DEFINE SIMBA_MAX_OPTIMIZATION}

Expand Down Expand Up @@ -40,6 +41,7 @@ interface
TSimbaColorConversion = class
public
class function ColorToBGRA(const Color: TColor): TColorBGRA; static; inline;
class function BGRAToColor(const BGRA: TColorBGRA): TColor; static; inline;
class function ColorToRGB(const Color: TColor): TColorRGB; static; inline;
class function RGBToColor(const RGB: TColorRGB): TColor; static; inline;
class function BGRAToRGB(const RGB: TColorBGRA): TColorRGB; static; inline;
Expand All @@ -66,7 +68,12 @@ class function TSimbaColorConversion.ColorToBGRA(const Color: TColor): TColorBGR
Result.B := Color shr B_BIT and $FF;
Result.G := Color shr G_BIT and $FF;
Result.R := Color shr R_BIT and $FF;
Result.A := 0;
Result.A := Color shr A_BIT and $FF;
end;

class function TSimbaColorConversion.BGRAToColor(const BGRA: TColorBGRA): TColor;
begin
Result := TColor(BGRA.R or BGRA.G shl G_BIT or BGRA.B shl B_BIT or BGRA.A shl A_BIT);
end;

class function TSimbaColorConversion.ColorToRGB(const Color: TColor): TColorRGB;
Expand All @@ -78,7 +85,7 @@ class function TSimbaColorConversion.ColorToRGB(const Color: TColor): TColorRGB;

class function TSimbaColorConversion.RGBToColor(const RGB: TColorRGB): TColor;
begin
Result := RGB.R or RGB.G shl G_BIT or RGB.B shl B_BIT;
Result := TColor(RGB.R or RGB.G shl G_BIT or RGB.B shl B_BIT);
end;

class function TSimbaColorConversion.BGRAToRGB(const RGB: TColorBGRA): TColorRGB;
Expand Down
10 changes: 10 additions & 0 deletions Source/image/boxfilled.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Requires method `procedure _Row(const Y: Integer; X1, X2: Integer);`

procedure _BoxFilled(Box: TBox);
var
Y: Integer;
begin
for Y := Box.Y1 to Box.Y2 do
_Row(Y, Box.X1, Box.X2);
end;

4 changes: 3 additions & 1 deletion Source/image/drawcircle.inc → Source/image/circle.inc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// https://zingl.github.io/bresenham.js

procedure _DrawCircle(CenterX, CenterY, Radius: Integer);
// Requires method `procedure _SetPixel(X, Y: Integer);`

procedure _Circle(CenterX, CenterY, Radius: Integer);
var
X, Y, Err: Integer;
begin
Expand Down
14 changes: 14 additions & 0 deletions Source/image/circlefilled.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Requires method `procedure _Row(const Y: Integer; X1, X2: Integer);`

procedure _CircleFilled(CenterX, CenterY, Radius: Integer);
var
X, Y: Integer;
Radius2: Integer;
begin
Radius2 := Radius * Radius;
for Y := -Radius to Radius do
begin
X := Round(Sqrt(Radius2 - Y * Y) + 0.5);
_Row(Y + CenterY, CenterX - X, CenterX + X);
end;
end;
30 changes: 0 additions & 30 deletions Source/image/drawcirclefilled.inc

This file was deleted.

122 changes: 122 additions & 0 deletions Source/image/polygonfilled.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Requires method `procedure _Row(const Y: Integer; X1, X2: Integer);`

(*
Calculates the intersection points of a vertical (ACoordIsX = true) or horizontal
(ACoordIsX = false) line with border of the polygon specified by APoints.
Returns the coordinates of the intersection points.
*)
function GetLinePolygonIntersectionPoints(const ACoord: Double; const APoints: TPointFArray; const ACoordIsX: Boolean): TPointFArray;
var
I, Count: Integer;
Arr: TDoubleArray;
dx, dy: Double;
begin
SetLength(Arr, Length(APoints));
Count := 0;

if ACoordIsX then
begin
for I := 0 to High(APoints) - 1 do
if ((APoints[I].X <= ACoord) and (ACoord < APoints[I+1].X)) or
((APoints[I+1].X <= ACoord) and (ACoord < APoints[I].X)) then
begin
dx := APoints[I+1].X - APoints[I].X;
dy := APoints[I+1].Y - APoints[I].Y;

Arr[Count] := APoints[I].Y + (ACoord - APoints[I].X) * dy / dx;
Inc(Count);
end;
end else
begin
for I := 0 to High(APoints) - 1 do
if ((APoints[I].Y <= ACoord) and (ACoord < APoints[I+1].Y)) or
((APoints[I+1].Y <= ACoord) and (ACoord < APoints[I].Y)) then
begin
dy := APoints[I+1].Y - APoints[I].Y;
dx := APoints[I+1].X - APoints[I].X;

Arr[Count] := APoints[I].X + (ACoord - APoints[I].Y) * dx / dy;
Inc(Count);
end;
end;

SetLength(Result, Count);
if (Count = 0) then
Exit;

specialize QuickSort<Double>(Arr, 0, Count - 1);

if ACoordIsX then
for I := 0 to High(Result) do
begin
Result[I].X := ACoord;
Result[I].Y := Arr[I];
end
else
for I := 0 to High(Result) do
begin
Result[I].X := Arr[I];
Result[I].Y := ACoord;
end;
end;

(*
Fills a polygon with the color of the current brush. The routine can handle
non-contiguous polygons (holes!) correctly using the ScanLine algorithm and
the even-odd rule
http://www.tutorialspoint.com/computer_graphics/polygon_filling_algorithm
*)
procedure _PolygonFilled(APoints: TPointArray; ARect: TRect);
var
scanlineY, scanLineY1, scanLineY2: Integer;
lPoints, pts: TPointFArray;
I: Integer;
begin
if (APoints[0] <> APoints[High(APoints)]) then
begin
SetLength(APoints, Length(APoints) + 1);
APoints[High(APoints)] := APoints[0];
end;

if (ARect.Top < ARect.Bottom) then
begin
scanLineY1 := ARect.Top;
scanLineY2 := ARect.Bottom;
end else
begin
scanLineY1 := ARect.Bottom;
scanLineY2 := ARect.Top;
end;

// Prepare points as needed by the GetLinePolygonIntersectionPoints procedure
SetLength(pts, Length(APoints));
for I := 0 to High(APoints) do
begin
pts[I].x := APoints[I].X;
pts[I].y := APoints[I].Y;
end;

// Fill polygon by drawing horizontal line segments
scanlineY := scanlineY1;
while (scanlineY <= scanlineY2) do
begin
// Find intersection points of horizontal scan line with polygon
// with polygon
lPoints := GetLinePolygonIntersectionPoints(scanlineY, pts, false);
if Length(lPoints) < 2 then
begin
inc(scanlineY);
Continue;
end;
// Draw lines between intersection points, skip every second pair
I := 0;
while I < High(lPoints) do
begin
_Row(Round(lPoints[I].Y), round(lPoints[I].X), round(lPoints[I+1].X));
inc(I, 2);
end;
// Proceed to next scan line
inc(scanlineY);
end;
end;

Loading

0 comments on commit 25b5ec6

Please sign in to comment.