216 lines
5.5 KiB
ObjectPascal

unit alpha_gradient_main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics,
Dialogs, BGRABitmapTypes, BGRABitmap, LMessages;
type
{ TForm1 }
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure FormPaint(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
ellipses: array of record
x,y,w,h: integer;
c: TBGRAPixel;
end;
pts: array[0..2] of TPointF;
MovingPointIndex: integer;
MovingOrigin: TPointF;
procedure WMEraseBkgnd(var Message: TLMEraseBkgnd); message LM_ERASEBKGND;
end;
var
Form1: TForm1;
implementation
uses BGRAGradientScanner, BGRATransform;
procedure NicePoint(bmp: TBGRABitmap; x, y: single);
begin
bmp.EllipseAntialias(x,y,4,4,BGRA(0,0,0,192),1);
bmp.EllipseAntialias(x,y,3,3,BGRA(255,255,255,192),1);
bmp.EllipseAntialias(x,y,2,2,BGRA(0,0,0,192),1);
end;
{$R *.lfm}
type
{ TMultiplyGradient }
TMultiplyGradient = class(TBGRACustomScanner)
function ScanAt(X, Y: Single): TBGRAPixel; override;
end;
{ TMultiplyGradient }
function TMultiplyGradient.ScanAt(X, Y: Single): TBGRAPixel;
var fvalue: single;
value: integer;
begin
fvalue := abs(x*y*255);
if fvalue > 255 then
value := 255
else
value := round(fvalue);
result := BGRA(value,value,value,255);
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
setlength(ellipses,100);
for i := 0 to high(ellipses) do
with ellipses[i] do
begin
x := random(65536);
y := random(65536);
w := random(100)+5;
h := random(100)+5;
c := BGRA(random(256),random(256),random(256),random(128)+64);
end;
pts[0] := PointF(250,200);
pts[1] := PointF(300,150);
pts[2] := PointF(300,250);
MovingPointIndex := -1;
end;
procedure TForm1.FormPaint(Sender: TObject);
const ellipseRadius = 160;
var bmp: TBGRABitmap;
tx,ty: integer;
i: Integer;
ellipseLayer: TBGRABitmap;
gradient: TBGRAGradientScanner;
multigrad: TBGRAMultiGradient;
affine: TBGRAAffineScannerTransform;
multiply: TMultiplyGradient;
mask: TBGRABitmap;
ellipseLayerOffset: TPointF;
begin
tx := ClientWidth;
ty := ClientHeight;
if (tx=0) or (ty=0) then exit;
//create background
bmp := TBGRABitmap.Create(tx,ty, BGRAWhite);
for i := 0 to high(ellipses) do
with ellipses[i] do
bmp.FillEllipseAntialias(x mod tx,y mod ty,w/2,h/2,c);
//create center red-yellow ellipse
ellipseLayerOffset := PointF((tx-(2*ellipseRadius+1))/2,(ty-(2*ellipseRadius+1))/2);
ellipseLayer := TBGRABitmap.Create(2*ellipseRadius +1 + 1,2*ellipseRadius +1 +1);
multiGrad := TBGRAMultiGradient.Create([BGRA(0,64,0),BGRA(160,160,0),BGRA(128,0,0)],[0,1/2,1],True);
gradient := TBGRAGradientScanner.Create(multiGrad,gtRadial,PointF(0,0),PointF(1,0));
affine := TBGRAAffineScannerTransform.Create(gradient);
affine.Scale(ellipseRadius*1.2,ellipseRadius*0.8);
affine.RotateDeg(30);
affine.Translate(ellipseRadius+frac(ellipseLayerOffset.X),ellipseRadius+frac(ellipseLayerOffset.Y));
ellipseLayer.FillEllipseAntialias(ellipseRadius+frac(ellipseLayerOffset.X),ellipseRadius+frac(ellipseLayerOffset.Y),
ellipseRadius,ellipseRadius,BGRA(192,128,0));
ellipseLayer.FillEllipseAntialias(ellipseRadius+frac(ellipseLayerOffset.X),ellipseRadius+frac(ellipseLayerOffset.Y),
ellipseRadius,ellipseRadius,affine);
affine.Free;
gradient.Free;
multiGrad.Free;
//apply multiply mask
multiply := TMultiplyGradient.Create;
affine := TBGRAAffineScannerTransform.Create(multiply);
affine.Fit(pts[0],pts[1],pts[2]);
affine.Translate(-trunc(ellipseLayerOffset.X),-trunc(ellipseLayerOffset.Y));
mask := TBGRABitmap.Create(ellipseLayer.Width,ellipseLayer.Height);
mask.Fill(affine);
ellipseLayer.ApplyMask(mask);
mask.Free;
affine.Free;
multiply.Free;
bmp.PutImage(trunc(ellipseLayerOffset.X),trunc(ellipseLayerOffset.Y),ellipseLayer,dmDrawWithTransparency);
ellipseLayer.Free;
for i := 0 to 2 do
NicePoint(bmp,pts[i].x,pts[i].y);
bmp.Draw(Canvas,0,0);
bmp.Free;
end;
procedure TForm1.WMEraseBkgnd(var Message: TLMEraseBkgnd);
begin
//
end;
procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var maxDist,dist: single;
mousePos,vect: TPointF;
i: Integer;
begin
if Button <> mbLeft then exit;
//select point to move
MovingPointIndex := -1;
maxDist := 10;
mousePos := PointF(X,Y);
for i := 0 to 2 do
begin
vect := pts[i] - mousePos;
dist := sqrt(vect*vect);
if dist < maxDist then
begin
maxDist := dist;
MovingPointIndex := i;
MovingOrigin := mousePos;
end;
end;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
mousePos: TPointF;
begin
if MovingPointIndex <> -1 then
begin
mousePos := PointF(X,Y);
pts[MovingPointIndex].Offset(mousePos-MovingOrigin);
Invalidate;
MovingOrigin := mousePos;
end;
end;
procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then MovingPointIndex := -1;
end;
end.