|
@@ -0,0 +1,245 @@
|
|
|
|
|
+unit Unit1;
|
|
|
|
|
+
|
|
|
|
|
+{$mode objfpc}{$H+}
|
|
|
|
|
+
|
|
|
|
|
+interface
|
|
|
|
|
+
|
|
|
|
|
+uses
|
|
|
|
|
+ Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls,
|
|
|
|
|
+ ComCtrls, BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes;
|
|
|
|
|
+
|
|
|
|
|
+const
|
|
|
|
|
+ wind = -0.5; //1 means 45 degrees rain
|
|
|
|
|
+ rainDensity = 2; //strictly positive
|
|
|
|
|
+
|
|
|
|
|
+type
|
|
|
|
|
+
|
|
|
|
|
+ { TForm1 }
|
|
|
|
|
+
|
|
|
|
|
+ TForm1 = class(TForm)
|
|
|
|
|
+ vsRain: TBGRAVirtualScreen;
|
|
|
|
|
+ Timer1: TTimer;
|
|
|
|
|
+ TrackBar1: TTrackBar;
|
|
|
|
|
+ procedure RainRedraw(Sender: TObject; Bitmap: TBGRABitmap);
|
|
|
|
|
+ procedure FormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
|
|
|
|
|
+ procedure FormCreate(Sender: TObject);
|
|
|
|
|
+ procedure FormDestroy(Sender: TObject);
|
|
|
|
|
+ procedure Timer1Timer(Sender: TObject);
|
|
|
|
|
+ private
|
|
|
|
|
+ { private declarations }
|
|
|
|
|
+ bkg,stretchedBkg: TBGRABitmap;
|
|
|
|
|
+ prevTime: TDateTime;
|
|
|
|
|
+ prevTimeDefined: boolean;
|
|
|
|
|
+ rainData: array of record
|
|
|
|
|
+ x,ystart,yend: single;
|
|
|
|
|
+ rainWidth, rainSpeed: single;
|
|
|
|
|
+ grad: TBGRACustomGradient;
|
|
|
|
|
+ active: boolean;
|
|
|
|
|
+ inactiveTime: double;
|
|
|
|
|
+ end;
|
|
|
|
|
+ procedure ClearRainData;
|
|
|
|
|
+ procedure PrepareRainArray(nbRain: integer; ScaleX: single);
|
|
|
|
|
+ function PrepareRainDrop(i: integer; rainSizeX, rainSizeY: single): single;
|
|
|
|
|
+ procedure NeedRainArray(w, h, rainProba: integer; rainSizeX, rainSizeY: single);
|
|
|
|
|
+ procedure RainElapse(elapsed: double; rainProba, w, h: integer);
|
|
|
|
|
+ procedure RenderRain(Bitmap: TBGRABitmap);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+var
|
|
|
|
|
+ Form1: TForm1;
|
|
|
|
|
+
|
|
|
|
|
+implementation
|
|
|
|
|
+
|
|
|
|
|
+uses BGRAGradientScanner, Math;
|
|
|
|
|
+
|
|
|
|
|
+{$R *.lfm}
|
|
|
|
|
+
|
|
|
|
|
+{ TForm1 }
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.RainRedraw(Sender: TObject; Bitmap: TBGRABitmap);
|
|
|
|
|
+var
|
|
|
|
|
+ elapsed: double;
|
|
|
|
|
+ ratio: single;
|
|
|
|
|
+ x,y,w,h: integer;
|
|
|
|
|
+begin
|
|
|
|
|
+ if not prevTimeDefined then
|
|
|
|
|
+ begin
|
|
|
|
|
+ elapsed := 0;
|
|
|
|
|
+ end else
|
|
|
|
|
+ begin
|
|
|
|
|
+ elapsed := (Now-prevTime)*86400*10;
|
|
|
|
|
+ if elapsed < 0 then elapsed := 0;
|
|
|
|
|
+ end;
|
|
|
|
|
+ prevTime := now;
|
|
|
|
|
+ prevTimeDefined := true;
|
|
|
|
|
+
|
|
|
|
|
+ if Assigned(stretchedBkg) and
|
|
|
|
|
+ ((stretchedBkg.Width <> Bitmap.Width) or (stretchedBkg.Height <> Bitmap.Height)) then
|
|
|
|
|
+ FreeAndNil(stretchedBkg);
|
|
|
|
|
+ if not Assigned(stretchedBkg) then
|
|
|
|
|
+ begin
|
|
|
|
|
+ ratio := max(Bitmap.Width/bkg.Width,Bitmap.Height/bkg.Height);
|
|
|
|
|
+ stretchedBkg := TBGRABitmap.Create(Bitmap.Width,Bitmap.Height,BGRABlack);
|
|
|
|
|
+ w := round(bkg.Width*ratio);
|
|
|
|
|
+ h := round(bkg.Height*ratio);
|
|
|
|
|
+ x := (Bitmap.Width-w) div 2;
|
|
|
|
|
+ y := (Bitmap.Height-h) div 2;
|
|
|
|
|
+ stretchedBkg.StretchPutImage(rect(x,y,x+w,y+h),bkg,dmDrawWithTransparency);
|
|
|
|
|
+ end;
|
|
|
|
|
+
|
|
|
|
|
+ RainElapse(elapsed,TrackBar1.Position,Bitmap.Width,Bitmap.Height);
|
|
|
|
|
+
|
|
|
|
|
+ Bitmap.PutImage(0,0,stretchedBkg,dmSet);
|
|
|
|
|
+ RenderRain(Bitmap);
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
|
|
|
|
|
+begin
|
|
|
|
|
+ Timer1.Enabled := False;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.FormCreate(Sender: TObject);
|
|
|
|
|
+begin
|
|
|
|
|
+ bkg := TBGRABitmap.Create('Lighthouse.jpg');
|
|
|
|
|
+ randomize;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.FormDestroy(Sender: TObject);
|
|
|
|
|
+begin
|
|
|
|
|
+ bkg.Free;
|
|
|
|
|
+ FreeAndNil(stretchedBkg);
|
|
|
|
|
+ ClearRainData;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.Timer1Timer(Sender: TObject);
|
|
|
|
|
+begin
|
|
|
|
|
+ Timer1.Enabled:= false;
|
|
|
|
|
+ vsRain.RedrawBitmap;
|
|
|
|
|
+ Timer1.Enabled:= true;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.ClearRainData;
|
|
|
|
|
+var i: integer;
|
|
|
|
|
+begin
|
|
|
|
|
+ for i := 0 to high(rainData) do
|
|
|
|
|
+ rainData[i].grad.Free;
|
|
|
|
|
+ rainData := nil;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.RenderRain(Bitmap: TBGRABitmap);
|
|
|
|
|
+var
|
|
|
|
|
+ i,h2: Integer;
|
|
|
|
|
+ scan: TBGRAGradientScanner;
|
|
|
|
|
+begin
|
|
|
|
|
+ h2 := Bitmap.Height div 2;
|
|
|
|
|
+ for i:= 0 to high(rainData) do
|
|
|
|
|
+ with rainData[i] do
|
|
|
|
|
+ if active then
|
|
|
|
|
+ begin
|
|
|
|
|
+ scan := TBGRAGradientScanner.Create(grad, gtLinear, PointF(0,ystart),PointF(0,yend));
|
|
|
|
|
+ Bitmap.DrawLineAntialias(x+(ystart-h2)*wind,ystart,x+(yend-h2)*wind,yend,scan,rainWidth,true);
|
|
|
|
|
+ scan.Free;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+//returns raindrop height
|
|
|
|
|
+function TForm1.PrepareRainDrop(i: integer; rainSizeX,rainSizeY: single): single;
|
|
|
|
|
+var dist: single;
|
|
|
|
|
+begin
|
|
|
|
|
+ with rainData[i] do
|
|
|
|
|
+ begin
|
|
|
|
|
+ dist := (random(100)+10)/10;
|
|
|
|
|
+ rainSpeed := 1/dist;
|
|
|
|
|
+ rainWidth := rainSizeX/dist;
|
|
|
|
|
+ if rainWidth < 1 then rainWidth := 1;
|
|
|
|
|
+ result := rainSizeY/dist*(random(50)+75)/100;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.NeedRainArray(w, h, rainProba: integer; rainSizeX,rainSizeY: single);
|
|
|
|
|
+var
|
|
|
|
|
+ nbRain: Integer;
|
|
|
|
|
+ i: Integer;
|
|
|
|
|
+begin
|
|
|
|
|
+ nbRain := (w+round(abs(wind)*h)) *rainDensity;
|
|
|
|
|
+ if length(rainData)<> nbRain then
|
|
|
|
|
+ begin
|
|
|
|
|
+ PrepareRainArray(nbRain,1/rainDensity);
|
|
|
|
|
+ for i := 0 to high(rainData) do
|
|
|
|
|
+ with rainData[i] do
|
|
|
|
|
+ begin
|
|
|
|
|
+ x -= abs(wind)*h/2;
|
|
|
|
|
+ if random(1000) < rainProba then
|
|
|
|
|
+ begin
|
|
|
|
|
+ active := true;
|
|
|
|
|
+ ystart := Random(h*2)-h/2;
|
|
|
|
|
+ yend := ystart + PrepareRainDrop(i, rainSizeX,rainSizeY);
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.RainElapse(elapsed: double; rainProba,w,h: integer);
|
|
|
|
|
+var
|
|
|
|
|
+ i: integer;
|
|
|
|
|
+ rainSizeY,rainSizeX: single;
|
|
|
|
|
+ delta: single;
|
|
|
|
|
+begin
|
|
|
|
|
+ rainSizeY := 2+h*TrackBar1.Position/1000;
|
|
|
|
|
+ rainSizeX := 7*TrackBar1.Position/1000;
|
|
|
|
|
+ if rainSizeX < 4 then rainSizeX := 4;
|
|
|
|
|
+
|
|
|
|
|
+ NeedRainArray(w,h, rainProba, rainSizeX,rainSizeY);
|
|
|
|
|
+ for i := 0 to high(rainData) do
|
|
|
|
|
+ with rainData[i] do
|
|
|
|
|
+ if active then
|
|
|
|
|
+ begin
|
|
|
|
|
+ delta := h*rainSpeed*elapsed;
|
|
|
|
|
+ ystart += delta;
|
|
|
|
|
+ yend += delta;
|
|
|
|
|
+ if ystart >= h then
|
|
|
|
|
+ begin
|
|
|
|
|
+ if random(1000) < rainProba then
|
|
|
|
|
+ begin
|
|
|
|
|
+ yend := -(ystart-h);
|
|
|
|
|
+ ystart := yend - PrepareRainDrop(i, rainSizeX,rainSizeY);
|
|
|
|
|
+ end else
|
|
|
|
|
+ begin
|
|
|
|
|
+ active := false;
|
|
|
|
|
+ inactiveTime:= 0;
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+ end else
|
|
|
|
|
+ begin
|
|
|
|
|
+ inactiveTime+= elapsed;
|
|
|
|
|
+ if inactiveTime > 0.5 then
|
|
|
|
|
+ begin
|
|
|
|
|
+ inactiveTime -= 0.5;
|
|
|
|
|
+ if random(1000) < rainProba then
|
|
|
|
|
+ begin
|
|
|
|
|
+ active := true;
|
|
|
|
|
+ ystart := -random(h)/2;
|
|
|
|
|
+ yend := ystart + PrepareRainDrop(i, rainSizeX,rainSizeY);
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+procedure TForm1.PrepareRainArray(nbRain: integer; ScaleX: single);
|
|
|
|
|
+var
|
|
|
|
|
+ i: Integer;
|
|
|
|
|
+begin
|
|
|
|
|
+ ClearRainData;
|
|
|
|
|
+ setlength(rainData, nbRain);
|
|
|
|
|
+ for i := 0 to high(rainData) do
|
|
|
|
|
+ with rainData[i] do
|
|
|
|
|
+ begin
|
|
|
|
|
+ x := i*scaleX;
|
|
|
|
|
+ grad := TBGRAMultiGradient.Create([BGRAPixelTransparent, BGRA(255,255,255,random(20)+50), BGRAPixelTransparent],[0,0.9,1],True);
|
|
|
|
|
+ active:= false;
|
|
|
|
|
+ inactiveTime := 0;
|
|
|
|
|
+ end;
|
|
|
|
|
+end;
|
|
|
|
|
+
|
|
|
|
|
+end.
|
|
|
|
|
+
|