| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- 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.
|