Demo Scene Picture sinwave lazarus / 39-Graphics ---------------------------------------------------------------------- Gigatron · 2024-04-23 19:00 Hi, Let's continue with the Bitmap.PutImagePart from BGRA component, usefull now to make flag wave or ... under 70 lines of code running for me at 60 fps, so play with.... Picture  by TorinoGT; Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen,BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private   public   end; var  Form1: TForm1;  Plasma: TBGRABitmap;  acc : integer; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Plasma := TBGRABitmap.Create('warrior1.png');    acc := 0; end;// wobble or sinwave !!procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  i : integer;  w : integer;begin     i:=0;     w:=0;      Bitmap.Fill(BGRAPixelTransparent);     acc := acc +1;      for i:=0 to 120 do     begin     w := round(50 + (10 * sin((i+acc) * 8 * PI / 180)));     Bitmap.PutImagePart(0, i*5-4 , Plasma,  Rect(w,  i*5-4,  600*w ,i*10+4), dmSet);     end;end; procedure TForm1.Timer1Timer(Sender: TObject);begin        BGRAVirtualScreen1.RedrawBitmap;end; end.  ** Edit drawMode to dmSet thx to @KodeZwerg; ---------------------------------------------------------------------- KodeZwerg · 2024-04-23 20:26 Quote from: Gigatron on April 23, 2024, 09:00:25 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i      Bitmap.PutImagePart(0, i*5-4 , Plasma,  Rect(w,  i*5-4,  600*w ,i*10+4), dmDrawWithTransparency);Should be Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i      Bitmap.PutImagePart(0, i*5-4 , Plasma,  Rect(w,  i*5-4,  600*w ,i*10+4), dmSet);for best performance. Nice wiggle effect! ---------------------------------------------------------------------- circular · 2024-04-24 17:27 Nice effect with PutImagePart.  About optimization, there is mistake in the rectangular area provided to PutImagePart, it would rather be: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Bitmap.PutImagePart(0, i*5-4 , Plasma,  Rect(w,  i*5-4,  600*w ,(i+1)*5-4), dmSet); Also you don't need to call Bitmap.Fill because it is already cleared by the component. Another way to do the effect is to define a scanner: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes, BGRATransform; type  TWaveScanner = class(TBGRABitmapScanner)    Time: integer;    function GetOffset({%H-}X, Y: Single): Single;    { fast integer scanning (used by PutImage) }    procedure ScanMoveTo(X, Y: Integer); override;    { slow floating point scanning }    function ScanAt(X, Y: Single): TBGRAPixel; override;    constructor Create(ASource: TBGRACustomBitmap;      ARepeatX,ARepeatY: boolean; AOrigin: TPoint);  end;   { TForm1 }   TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    Image: TBGRABitmap;    WaveScanner: TWaveScanner;  public  end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Image := TBGRABitmap.Create('warrior1.png');  WaveScanner := TWaveScanner.Create(Image,              true, true, Point(0, 0));end; // wobble or sinwave !!procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);begin  WaveScanner.Time := WaveScanner.Time + 1;  Bitmap.Fill(WaveScanner);end; procedure TForm1.Timer1Timer(Sender: TObject);begin  BGRAVirtualScreen1.RedrawBitmap;end; { TWaveScanner } function TWaveScanner.GetOffset(X, Y: Single): Single;begin  result := 50 + (10 * sin((Y + Time*5) * 8/5 * PI / 180));end; procedure TWaveScanner.ScanMoveTo(X, Y: Integer);begin  inherited ScanMoveTo(X + round(GetOffset(X, Y)), Y);end; function TWaveScanner.ScanAt(X, Y: Single): TBGRAPixel;begin  Result:=inherited ScanAt(X + GetOffset(X, Y), Y);end; constructor TWaveScanner.Create(ASource: TBGRACustomBitmap;  ARepeatX,ARepeatY: boolean; AOrigin: TPoint);begin  inherited Create(ASource, ARepeatX, ARepeatY, AOrigin);  Time := 0;end; end. This way you can combine transforms, for example with a rotation: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes, BGRATransform; type  TWaveScanner = class(TBGRAAffineBitmapTransform)    Time: integer;    function GetOffset({%H-}X, Y: Single): Single;    { fast integer scanning (used by PutImage) }    procedure ScanMoveTo(X, Y: Integer); override;    { slow floating point scanning }    function ScanAt(X, Y: Single): TBGRAPixel; override;    constructor Create(ASource: TBGRACustomBitmap;      ARepeatX,ARepeatY: boolean);  end;   { TForm1 }   TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;  Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    Image: TBGRABitmap;    WaveScanner: TWaveScanner;  public  end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Image := TBGRABitmap.Create('warrior1.png');  WaveScanner := TWaveScanner.Create(Image, true, true);end; // wobble or sinwave !!procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);begin  WaveScanner.Time := WaveScanner.Time + 1;  WaveScanner.Translate(-ClientWidth/2, -ClientWidth/2);  WaveScanner.RotateDeg(1);  WaveScanner.Translate(ClientWidth/2, ClientWidth/2);  Bitmap.Fill(WaveScanner);end; procedure TForm1.Timer1Timer(Sender: TObject);begin  BGRAVirtualScreen1.RedrawBitmap;end; { TWaveScanner } function TWaveScanner.GetOffset(X, Y: Single): Single;begin  result := 50 + (10 * sin((Y + Time*5) * 8/5 * PI / 180));end; procedure TWaveScanner.ScanMoveTo(X, Y: Integer);begin  inherited ScanMoveTo(X + round(GetOffset(X, Y)), Y);end; function TWaveScanner.ScanAt(X, Y: Single): TBGRAPixel;begin  Result:=inherited ScanAt(X + GetOffset(X, Y), Y);end; constructor TWaveScanner.Create(ASource: TBGRACustomBitmap;  ARepeatX,ARepeatY: boolean);begin  inherited Create(ASource, ARepeatX, ARepeatY);  Time := 0;end; end. ---------------------------------------------------------------------- Gigatron · 2024-04-24 22:48 Thank you circular , the BGRA is very powerfull to make demos. My goal is make simple and short code for each demo part eg: Copper bars, bitmap font scroller, sinwave, blitter obj (bob) plasma  and so on like Amiga demos. After that i can combine all fx to make big demo with each part ; So thank you again for the sinwave fx and here is the short version 60 lines with correction . Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes; type  { TForm1 }  TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);   private   public   end; var  Form1: TForm1;  Bmp  : TBGRABitmap;  // bmp mean picture :)  acc  : integer; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin    Bmp := TBGRABitmap.Create('warrior1.png');    acc := 0;end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);   // wobble or sinwave !!var i,w : integer;begin     i :=0; w :=0; acc := acc + 1;     for i:=0 to Bmp.Height div 5 do   //     begin     w := round(50 + (10 * sin((i+acc) * 6 * PI / 180)));     Bitmap.PutImagePart(0, i*5-4 , Bmp,  Rect(-50+w,  i*5-4,  Bmp.Width*w ,(i+1)*5-4), dmSet); // xoffset to -50 to center bmp     end;end;procedure TForm1.Timer1Timer(Sender: TObject);begin     BGRAVirtualScreen1.RedrawBitmap;end; end. ---------------------------------------------------------------------- KodeZwerg · 2024-04-24 23:28 Quote from: circular on April 24, 2024, 07:27:02 pmAnother way to do the effect is to define a scanner:I do liking it a lot but could you assist me with a struggle where I having a blackout and dont know what to do: how do i center "any" image inside the virtualscreen please? with "any" i do mean a calculated center from different sized images in different sized virtualscreen, so when it rotate, that it rotate around itself, like a turntable. as of right now it rotate... how to say... unlike a turntable centered, its off-set from center and turn egg-like. If it would not be too much work, there is another question in that direction imagine i do have a round logo, like the fpc paw, where outside of the logo is transparent area, would your method already work with such that only visible pixels are drawn or would it rotate a black screen with a logo in middle? ---------------------------------------------------------------------- TRon · 2024-04-25 01:22 Quote from: Gigatron on April 23, 2024, 09:00:25 pmLet's continue with the Bitmap.PutImagePart from BGRA component, usefull now to make flag wave or ... under 70 lines of code running for me at 60 fps, so play with.... Very nice Gigatron !!. Again a sub with many trades... let's try push it  Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen, BGRABitmap; type   { TForm1 }   TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private   public   end; var  Form1: TForm1;  Plasma: TBGRABitmap;  acc: integer = 0; implementation {$R *.lfm} uses  BGRABitmapTypes; { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Timer1.Interval := round(1000/25);  BGRAVirtualScreen1.Width := 800;  BGRAVirtualScreen1.Height := 600;  BGRAVirtualScreen1.BitmapAutoScale:=false;  Plasma := TBGRABitmap.Create('warrior1.png');end; procedure TForm1.FormDestroy(Sender: TObject);begin  Plasma.Free;end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  i : integer;  w : integer;  x : integer;  y : integer;  speed: integer = 4;begin  Bitmap.Fill(BGRAPixelTransparent);  acc := acc + 1;   x := (BGRAVirtualScreen1.ClientRect.Width  - Plasma.ClipRect.Width)  shr 1;  y := (BGRAVirtualScreen1.CLientRect.Height - Plasma.ClipRect.Height) shr 1;   for i := 0 to Plasma.ClipRect.Height-1 do  begin    if odd(i)     then w := round( i * sin(acc * speed * PI / 180))      else w := round( i * cos(acc * speed * PI / 180));     Bitmap.PutImagePart    (      x + w,      y + i,      Plasma,      Rect(Plasma.ClipRect.Left , Plasma.ClipRect.Top + i, Plasma.ClipRect.Right , Plasma.ClipRect.Top + i + 1),      dmSet  );  end;end; procedure TForm1.Timer1Timer(Sender: TObject);begin  BGRAVirtualScreen1.RedrawBitmap;end; end. ---------------------------------------------------------------------- Gigatron · 2024-04-25 01:42 Very nice , it reminds me my shadertoy example  https://www.shadertoy.com/view/4s3SR4 ---------------------------------------------------------------------- circular · 2024-04-25 17:54 Quote from: KodeZwerg on April 25, 2024, 01:28:20 amI do liking it a lot but could you assist me with a struggle where I having a blackout and dont know what to do: how do i center "any" image inside the virtualscreen please? with "any" i do mean a calculated center from different sized images in different sized virtualscreen, so when it rotate, that it rotate around itself, like a turntable.Sure it is not trivial. Basically, you need to consider when the rotation is applied that it rotates around the origin (0, 0). In this example, one can center by first bringing the origin to the middle of the image in the scanner. Then when drawing, one need to apply an offset so that this origin is at the center of the virtual screen: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes, BGRATransform; type  TWaveScanner = class(TBGRAAffineBitmapTransform)    Time: integer;    function GetOffset({%H-}X, Y: Single): Single;    { fast integer scanning (used by PutImage) }    procedure ScanMoveTo(X, Y: Integer); override;    { slow floating point scanning }    function ScanAt(X, Y: Single): TBGRAPixel; override;    constructor Create(ASource: TBGRACustomBitmap;      ARepeatX,ARepeatY: boolean);  end;   { TForm1 }   TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;  Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    Image: TBGRABitmap;    WaveScanner: TWaveScanner;  public  end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Image := TBGRABitmap.Create('warrior1.png');  WaveScanner := TWaveScanner.Create(Image, false, false);  // for the scanner, translate so that the origin (0, 0) is now at the center of the image  WaveScanner.Translate(-Image.Width/2, -Image.Height/2);end; // wobble or sinwave !!procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);begin  WaveScanner.Time := WaveScanner.Time + 1;  WaveScanner.RotateDeg(1);  // when drawing, use an negative offset so that we get to the origin of the scanner  // at the center of the virtual screen   Bitmap.FillRect(Bitmap.ClipRect, WaveScanner, dmSet,    Point(-ClientWidth div 2, -ClientHeight div 2));end; procedure TForm1.Timer1Timer(Sender: TObject);begin  BGRAVirtualScreen1.RedrawBitmap;end; { TWaveScanner } function TWaveScanner.GetOffset(X, Y: Single): Single;begin  // removed the constant in the offset so that this value oscillates around zero  // keeping the centering intact  result := 10 * sin((Y + Time*5) * 8/5 * PI / 180);end; procedure TWaveScanner.ScanMoveTo(X, Y: Integer);begin  inherited ScanMoveTo(X + round(GetOffset(X, Y)), Y);end; function TWaveScanner.ScanAt(X, Y: Single): TBGRAPixel;begin  Result:=inherited ScanAt(X + GetOffset(X, Y), Y);end; constructor TWaveScanner.Create(ASource: TBGRACustomBitmap;  ARepeatX,ARepeatY: boolean);begin  inherited Create(ASource, ARepeatX, ARepeatY);  Time := 0;end; end. QuoteIf it would not be too much work, there is another question in that direction imagine i do have a round logo, like the fpc paw, where outside of the logo is transparent area, would your method already work with such that only visible pixels are drawn or would it rotate a black screen with a logo in middle? It depends on the draw mode. Here it is dmSet so opaque but you can use dmDrawWithTransparency when filling a rectangle. Note that I replace the call to Fill by a call to FillRect which has more flexibility. ---------------------------------------------------------------------- KodeZwerg · 2024-04-25 18:44 @circular: Exact what I was asking for, purrrfectissimo! Many thanks for your code pearl!! ---------------------------------------------------------------------- circular · 2024-04-25 19:08 You're welcome  I am pleased it is purrrrfect for you. ---------------------------------------------------------------------- TRon · 2024-04-26 00:23 Quote from: Gigatron on April 25, 2024, 03:42:01 amVery nice , it reminds me my shadertoy example A that is very nice and indeed is similar in nature. There is another one there as well. Actually I wished it was easy to re-create the different bitplanes as the original effect I had in mind is waving the different bitplanes (originally done by the copper) so that the picture is only fully visible when all planes align at a single point in time. This is the closest best thing without resorting to spartanic bit-f*ing