216 lines
5.5 KiB
ObjectPascal
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.
|
|
|