174 lines
4.1 KiB
ObjectPascal
174 lines
4.1 KiB
ObjectPascal
unit Unit1;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
|
|
StdCtrls, Spin, BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes;
|
|
|
|
type
|
|
|
|
{ TForm1 }
|
|
|
|
TForm1 = class(TForm)
|
|
CheckBox1: TCheckBox;
|
|
Label1: TLabel;
|
|
Panel1: TPanel;
|
|
SpinEdit1: TSpinEdit;
|
|
VirtualScreen: TBGRAVirtualScreen;
|
|
Timer1: TTimer;
|
|
procedure FormDestroy(Sender: TObject);
|
|
procedure SpinEdit1Change(Sender: TObject);
|
|
procedure VirtualScreenRedraw(Sender: TObject; Bitmap: TBGRABitmap);
|
|
procedure FormCreate(Sender: TObject);
|
|
procedure Timer1Timer(Sender: TObject);
|
|
private
|
|
FInit: boolean;
|
|
procedure InitBalls(ACount: integer);
|
|
procedure Init;
|
|
function GetBallRect(AIndex: integer): TRect;
|
|
public
|
|
ballRadius: integer;
|
|
background: TBGRABitmap;
|
|
balls: array of record
|
|
ballPos: TPoint;
|
|
ballSpeed: TPoint;
|
|
ballColor: TBGRAPixel;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Form1: TForm1;
|
|
|
|
implementation
|
|
|
|
{$R *.lfm}
|
|
|
|
uses BGRAGradients;
|
|
|
|
{ TForm1 }
|
|
|
|
procedure TForm1.VirtualScreenRedraw(Sender: TObject; Bitmap: TBGRABitmap);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Init;
|
|
Bitmap.FillRect(rect(0,0,Bitmap.Width,Bitmap.Height), background, dmSet);
|
|
for i := 0 to high(balls) do
|
|
with balls[i] do
|
|
Bitmap.EllipseAntialias(ballPos.x,ballPos.y, ballRadius,ballRadius, BGRABlack, 1, ballColor);
|
|
end;
|
|
|
|
procedure TForm1.SpinEdit1Change(Sender: TObject);
|
|
begin
|
|
initBalls(SpinEdit1.Value);
|
|
end;
|
|
|
|
procedure TForm1.FormDestroy(Sender: TObject);
|
|
begin
|
|
background.Free;
|
|
end;
|
|
|
|
procedure TForm1.FormCreate(Sender: TObject);
|
|
begin
|
|
VirtualScreen.BitmapAutoScale:= false;
|
|
end;
|
|
|
|
procedure TForm1.Timer1Timer(Sender: TObject);
|
|
var
|
|
i: Integer;
|
|
rects: array of TRect;
|
|
nbRects: integer;
|
|
begin
|
|
if not FInit then exit;
|
|
Timer1.Enabled:= false;
|
|
setlength(rects, length(balls)*2);
|
|
nbRects := 0;
|
|
|
|
for i := 0 to high(balls) do
|
|
with balls[i] do
|
|
begin
|
|
//rect to clear
|
|
rects[nbRects] := GetBallRect(i);
|
|
inc(nbRects);
|
|
|
|
inc(ballSpeed.Y);
|
|
inc(ballPos.X, ballSpeed.x);
|
|
inc(ballPos.Y, ballSpeed.y);
|
|
if BallPos.Y >= VirtualScreen.BitmapHeight-ballRadius then
|
|
begin
|
|
ballPos.Y := VirtualScreen.BitmapHeight-ballRadius;
|
|
ballSpeed.Y := -abs(ballSpeed.Y);
|
|
|
|
if (BallPos.X < -ballRadius) or (BallPos.X > VirtualScreen.BitmapWidth+ballRadius) then
|
|
begin
|
|
ballPos := Point(random(VirtualScreen.BitmapWidth), - ballRadius);
|
|
ballSpeed.Y := 0;
|
|
Continue;
|
|
end;
|
|
end else
|
|
begin
|
|
if BallPos.X+ballRadius >= VirtualScreen.BitmapWidth then
|
|
begin
|
|
BallPos.X := VirtualScreen.BitmapWidth-ballRadius;
|
|
ballSpeed.X := -abs(ballSpeed.x);
|
|
end else
|
|
if BallPos.X <= ballRadius then
|
|
begin
|
|
BallPos.X := ballRadius;
|
|
ballSpeed.X := abs(ballSpeed.x);
|
|
end;
|
|
end;
|
|
|
|
//rect to redraw
|
|
rects[nbRects] := GetBallRect(i);
|
|
inc(nbRects);
|
|
end;
|
|
if CheckBox1.Checked then
|
|
VirtualScreen.RedrawBitmap
|
|
else
|
|
VirtualScreen.RedrawBitmap(slice(rects,nbRects));
|
|
Timer1.Enabled:= true;
|
|
end;
|
|
|
|
procedure TForm1.InitBalls(ACount: integer);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
randomize;
|
|
VirtualScreen.DiscardBitmap;
|
|
setlength(balls, ACount);
|
|
for i := 0 to high(balls) do
|
|
with balls[i] do
|
|
begin
|
|
ballPos := Point(random(VirtualScreen.BitmapWidth), (i*VirtualScreen.BitmapHeight div length(balls)) - ballRadius);
|
|
ballSpeed := Point(random(5)-2, 0);
|
|
ballColor := BGRA(random(256),random(256),random(256));
|
|
if ballColor.Lightness > 48000 then ballColor.Lightness:= 48000;
|
|
end;
|
|
end;
|
|
|
|
procedure TForm1.Init;
|
|
var
|
|
scale: Double;
|
|
begin
|
|
if FInit then exit;
|
|
FInit := true;
|
|
scale := VirtualScreen.BitmapScale*Screen.PixelsPerInch/96;
|
|
ballRadius := round(20*scale);
|
|
initBalls(SpinEdit1.Value);
|
|
background := CreateCyclicPerlinNoiseMap(round(256*scale),round(256*scale));
|
|
end;
|
|
|
|
function TForm1.GetBallRect(AIndex: integer): TRect;
|
|
begin
|
|
with balls[AIndex] do
|
|
result := Rect(ballPos.X-ballRadius, ballPos.Y-ballRadius,
|
|
ballPos.X+ballRadius+1, ballPos.Y+ballRadius+1);
|
|
end;
|
|
|
|
end.
|
|
|