Demo Scene Text Fx lazarus / 39-Graphics ---------------------------------------------------------------------- Gigatron · 2024-05-06 06:36 Hi, Yesterdat i've played with .ttf font with lazarus fpc and bgra component to make a nice intro under 100 lines of code. the font is from Digital demo group on Amiga converted to ttf by me included in attachement; the code source : 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;  ta,xapp,yapp : double;  x,y,i,j  : integer;   tx: Array[0..9]  Of String; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin     ta :=0;     xapp :=0;     yapp :=0;     x:=0;     y:=60;     i :=0;     j :=0;      tx[0] := '***************************';     tx[1] := '*       GIGATRON          *';     tx[2] := '*                         *';     tx[3] := '*    PRESENTS TEXT FX#1   *';     tx[4] := '*                         *';     tx[5] := '*      BGRA COMPONENT     *';     tx[6] := '*-------------------------*';     tx[7] := '*   LAZARUS FPC RULEZ  !!!*';     tx[8] := '*-------------------------*';     tx[9] := '***************************'; end;  procedure TForm1.Timer1Timer(Sender: TObject);begin    BGRAVirtualScreen1.RedrawBitmap;end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap); begin   bitmap.FontName:='AmigaDigital8';  bitmap.FontHeight := 40;  bitmap.FontAntialias := false;      for i:=0 to 27 do    begin    for j:=0 to 9 do     begin      ta := ta +0.002;         xapp := (x + 2)  + 8   * sin(ta-j*0.05);        yApp := (y+i*15) + 4  * sin(tA-j*0.4-i) * 2;       bitmap.TextOut(i*24+xapp-10, (j*32 + yapp-i*15)+6  , tx[j][i],BGRA(0,0,0));      bitmap.TextOut(i*24+xapp-10,  j*32 + yapp-i*15   ,   tx[j][i],BGRA(255,255,255));     end;    end;   end;  end.   This fx is slow for me .. ---------------------------------------------------------------------- lainz · 2024-05-07 01:45 I like how you create effects with few lines of code. ---------------------------------------------------------------------- Gigatron · 2024-05-07 03:22 But, it's thanks to you lainz and the best component BGRA ; So the same fx but with usin open GL, it's smooth and faster than light 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,  BGLVirtualScreen, BGRAOpenGL, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    BGLVirtualScreen1: TBGLVirtualScreen;    Timer1: TTimer;    procedure BGLVirtualScreen1Redraw(Sender: TObject; BGLContext: TBGLContext);    procedure FormCreate(Sender: TObject);  procedure FormShow(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private        GLFont: IBGLFont;  public   end; var  Form1: TForm1;  ta,xapp,yapp : double;  x,y,i,j  : integer;  tx: Array[0..9]  Of String; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin     ta :=0; xapp :=0; yapp :=0; x:=0; y:=60; i :=0; j :=0;      tx[0] := '***************************';     tx[1] := '*       GIGATRON          *';     tx[2] := '*                         *';     tx[3] := '*    PRESENTS TEXT FX#1   *';     tx[4] := '*                         *';     tx[5] := '*     BGRA COMPONENT GL   *';     tx[6] := '*-------------------------*';     tx[7] := '*   LAZARUS FPC RULEZ  !!!*';     tx[8] := '*-------------------------*';     tx[9] := '***************************';end; procedure TForm1.FormShow(Sender: TObject);begin     GLFont := BGLFont('AmigaDigital8',40);end; procedure TForm1.BGLVirtualScreen1Redraw(Sender: TObject;BGLContext: TBGLContext);begin    for i:=0 to 27 do    begin    for j:=0 to 9 do   begin      ta := ta +0.0004;         xapp := (x + 2)  + 10   * sin(ta-j*0.005);        yApp := (y+i*15) + 6    * sin(tA-j*0.004-i)*2 ;       GLFont.TextOut(i*24+xapp, (j*32 + yapp-i*15)+6  , tx[j][i],BGRA(68,85,102));      GLFont.TextOut(i*24+xapp,  j*32 + yapp-i*15   ,   tx[j][i],BGRA(255,255,255));     end;    end; end; procedure TForm1.Timer1Timer(Sender: TObject);begin         BGLVirtualScreen1.Repaint;end; end. ---------------------------------------------------------------------- KodeZwerg · 2024-05-07 07:04 Minimal modified so it actually use on windows the font that you shared (also renamed variables to better qualifier names) (modified for a smoother wave look) 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  Windows,  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGLVirtualScreen, BGRAOpenGL, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    BGLVirtualScreen1: TBGLVirtualScreen;    Timer1: TTimer;    procedure BGLVirtualScreen1Redraw(Sender: TObject; BGLContext: TBGLContext);    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);    procedure FormShow(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    angle,    xPos, yPos : double;    xStart,    yStart: Integer;    Message: array[0..9] of AnsiString;  private     GLFont: IBGLFont;  public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.Timer1Timer(Sender: TObject);begin  BGLVirtualScreen1.Repaint;end; procedure TForm1.FormCreate(Sender: TObject);begin  angle   := 0;  xPos    := 0;  yPos    := 0;  xStart  := 0;  yStart  := 60;   Message[0] := '***************************';  Message[1] := '*       GIGATRON          *';  Message[2] := '*                       *';  Message[3] := '*    PRESENTS TEXT FX#1   *';  Message[4] := '*                         *';  Message[5] := '*     BGRA COMPONENT GL   *';  Message[6] := '*-------------------------*';  Message[7] := '*   LAZARUS FPC RULEZ  !!!*';  Message[8] := '*-------------------------*';  Message[9] := '***************************';   // preset a minimal wanted window size  Self.Width := 710;  Self.Height := 460;   // adopted your color from screenshot :D  BGLVirtualScreen1.Color := $00776655;   // adjust timer to your needs  Timer1.Interval := 1;   // load the font on the fly and make it systemwide public  AddFontResource('AmigaDigital8.ttf');  SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);end; procedure TForm1.FormDestroy(Sender: TObject);begin  // unload the font and make it systemwide public  RemoveFontResource('AmigaDigital8.ttf');  SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);end; procedure TForm1.BGLVirtualScreen1Redraw(Sender: TObject;  BGLContext: TBGLContext);var  i, j: Integer;begin  for i := 0 to 27 do    for j := 0 to 9 do      begin        // movement modifier        angle := angle + 0.0004;        // left to right movement        xPos := (xStart + 2) + 10 * Sin(angle - j * 0.005);        // up and down movement        yPos := (yStart + i * 15) + 6 * Cos(angle - j * 0.004 - i) * 2;      // fake shadow character        GLFont.TextOut(i * 24 + xPos, (j * 32 + yPos - i * 15) + 6, Message[j][i], BGRA(68, 85, 102));        // actual text character        GLFont.TextOut(i * 24 + xPos, j * 32 + yPos - i * 15, Message[j][i], BGRA(255, 255, 255));      end;end; procedure TForm1.FormShow(Sender: TObject);begin  GLFont := BGLFont('AmigaDigital8', 40);end; end.Thank you Gigatron for that nice example! Attached is how it looks without font installed, I am unsure what is used but its not the AmigaDigital8 ---------------------------------------------------------------------- TRon · 2024-05-07 07:08 Quote from: Gigatron on May 06, 2024, 08:36:12 amThis fx is slow for me .. Yeah, that is way of things. Learn to know the tools and their trade- offs. So, - the font can be set to the virtual screen once. However slightly, it helps. - at a certain point clearing the screen (big surface) at once is cheaper than (re)drawing smaller bits - in accordance with the above, skip drawing when there is actually nothing to draw (spaces) - also however slightly it helps, pre-calculation of sin/coords (that has a certain drawback ofc.) - note that using a timer to actually time frames is .. not smart ... to say the least. It fires every x-th millisecond an is literally wasting all time in between (I know it a timer is a simple pleasure usage and use it myself as well). - the bigger slowness seem to originate form redrawing of the same thing over and over (opengl caches some important parts hence the speed increase), so pre-draw the glyphs and blit a single glyph at once. There are many more things that are able to influence speed (or the perception thereof). The funny part of this is... we are talking about hardware that is around 3-4 decades old (the generation before Amiga was also capable of these same fx) and is able to display such a wavy text without breaking a sweat with enough time to spare to do some actual important stuff. It is a living testimony that relying on cpu grunt alone is not the smartest way to approach these kind of things. ---------------------------------------------------------------------- Guva · 2024-05-07 12:55 Cool!!!, five minutes to convert. the total is 120 lines in raylib. 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 program project1;{$mode objfpc}{$H+} uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}  Classes, SysUtils, CustApp, RayLib, RayMath; type  PStar = ^TStar;  TStar = record    position : TVector2;    speed    : TVector2;  end;   { TRayApplication }  TRayApplication = class(TCustomApplication)  protected    procedure DoRun; override;  public    Stars: array [0..400] of TStar;    constructor Create(TheOwner: TComponent); override;    destructor Destroy; override;    procedure UpdateStar(s: PStar);    procedure ResetStar(s: PStar);  end;   const AppTitle = 'raylib - text fx#1'; var  message : Array[0..9] Of Pchar; MyFont: TFont;  angle, xPos, yPos : double;  xStart, yStart: Integer; constructor TRayApplication.Create(TheOwner: TComponent);var n,m: integer;begin  inherited Create(TheOwner);  InitWindow(800, 600, AppTitle); // for window settings, look at example - window flags  SetTargetFPS(60); // Set our game to run at 60 frames-per-second  MyFont:= LoadFont('Phased.ttf');  angle   := 0; xPos := 0; yPos    := 0;  xStart  := 80; yStart  := 120;   message[0] := '***************************';  message[1] := '*       GIGATRON        *';  message[2] := '*                         *';  message[3] := '*  PRESENTS TEXT FX#1   *';  message[4] := '*                         *';  message[5] := '*      120 LINE CODE      *';  message[6] := '*-------------------------*';  message[7] := '*      RAYLIB RULEZ  !!!  *';  message[8] := '*-------------------------*';  message[9] := '***************************';  for n := 0  to 399 do ResetStar(@stars[n]);  for m := 0 to  GetscreenWidth div 2 do  begin   for n:=0 to 399 do UpdateStar(@stars[n]);  end;end; procedure TRayApplication.DoRun;var i,j,n: integer;begin  while (not WindowShouldClose) do // Detect window close button or ESC key  begin    for n := 0 to 399 do UpdateStar(@stars[n]);    BeginDrawing();    ClearBackground(DARKBLUE);    for i:=0 to 26 do    for j:=0 to 9 do   begin      angle := angle + 0.0004;      // left to right movement    xPos := (xStart + 2) + 10 * Sin(angle - j * 0.005);     // up and down movement     yPos := (yStart + i * 15) + 6 * Cos(angle - j * 0.004 - i) * 2;     DrawTextCodepoint(MyFont,Integer(message[j][i]), Vector2Create(i * 24 + xPos,  (j*32 + yPos - i *15 ) + 3), 40, Black);     DrawTextCodepoint(MyFont,Integer(message[j][i]), Vector2Create(i * 24 + xPos,  (j*32 + yPos - i *15 )), 40, White);     end;    for n := 0 to 399 do    DrawRectangle(round(stars[n].position.x), round(stars[n].position.y), 2, 2, WHITE);    EndDrawing();  end;  Terminate;end; destructor TRayApplication.Destroy;begin  CloseWindow(); // Close window and OpenGL context  inherited Destroy;end; procedure TRayApplication.UpdateStar(s: PStar);begin  s^.position := Vector2Add(s^.position, s^.speed);  if ((s^.position.x < 0) or (s^.position.x > GetScreenWidth()) or      (s^.position.y < 0) or (s^.position.y > GetScreenHeight())) then ResetStar(s);end; procedure TRayApplication.ResetStar(s: PStar);begin  s^.position := Vector2Create(GetScreenWidth()/2.0, GetScreenHeight()/2.0);  while not (abs(s^.speed.x + abs(s^.speed.y)) > 1) do  begin      s^.speed.x := GetRandomValue(-1000, 1000)/100;      s^.speed.y := GetRandomValue(-1000, 1000)/100;  end;  s^.position := Vector2Add(s^.position, Vector2Multiply(s^.speed, Vector2Create( 20.0, 20.0 )));end; var  Application: TRayApplication;begin  Application:=TRayApplication.Create(nil);  Application.Title:=AppTitle;  Application.Run;  Application.Free;end. ---------------------------------------------------------------------- Gigatron · 2024-05-07 13:23 Quote from: KodeZwerg on May 07, 2024, 09:04:15 amMinimal modified so it actually use on windows the font that you shared (also renamed variables to better qualifier names) (modified for a smoother wave look) 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  Windows,  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls,  BGLVirtualScreen, BGRAOpenGL, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    BGLVirtualScreen1: TBGLVirtualScreen;    Timer1: TTimer;    procedure BGLVirtualScreen1Redraw(Sender: TObject; BGLContext: TBGLContext);    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);    procedure FormShow(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    angle,    xPos, yPos : double;    xStart,    yStart: Integer;    Message: array[0..9] of AnsiString;  private     GLFont: IBGLFont;  public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.Timer1Timer(Sender: TObject);begin  BGLVirtualScreen1.Repaint;end; procedure TForm1.FormCreate(Sender: TObject);begin  angle   := 0;  xPos    := 0;  yPos    := 0;  xStart  := 0;  yStart  := 60;   Message[0] := '***************************';  Message[1] := '*       GIGATRON          *';  Message[2] := '*                       *';  Message[3] := '*    PRESENTS TEXT FX#1   *';  Message[4] := '*                         *';  Message[5] := '*     BGRA COMPONENT GL   *';  Message[6] := '*-------------------------*';  Message[7] := '*   LAZARUS FPC RULEZ  !!!*';  Message[8] := '*-------------------------*';  Message[9] := '***************************';   // preset a minimal wanted window size  Self.Width := 710;  Self.Height := 460;   // adopted your color from screenshot :D  BGLVirtualScreen1.Color := $00776655;   // adjust timer to your needs  Timer1.Interval := 1;   // load the font on the fly and make it systemwide public  AddFontResource('AmigaDigital8.ttf');  SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);end; procedure TForm1.FormDestroy(Sender: TObject);begin  // unload the font and make it systemwide public  RemoveFontResource('AmigaDigital8.ttf');  SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);end; procedure TForm1.BGLVirtualScreen1Redraw(Sender: TObject;  BGLContext: TBGLContext);var  i, j: Integer;begin  for i := 0 to 27 do    for j := 0 to 9 do      begin        // movement modifier        angle := angle + 0.0004;        // left to right movement        xPos := (xStart + 2) + 10 * Sin(angle - j * 0.005);        // up and down movement        yPos := (yStart + i * 15) + 6 * Cos(angle - j * 0.004 - i) * 2;      // fake shadow character        GLFont.TextOut(i * 24 + xPos, (j * 32 + yPos - i * 15) + 6, Message[j][i], BGRA(68, 85, 102));        // actual text character        GLFont.TextOut(i * 24 + xPos, j * 32 + yPos - i * 15, Message[j][i], BGRA(255, 255, 255));      end;end; procedure TForm1.FormShow(Sender: TObject);begin  GLFont := BGLFont('AmigaDigital8', 40);end; end.Thank you Gigatron for that nice example! Attached is how it looks without font installed, I am unsure what is used but its not the AmigaDigital8  Thank you very much for the code , i saved it ; ---------------------------------------------------------------------- Gigatron · 2024-05-07 13:33 Quote from: TRon on May 07, 2024, 09:08:34 amQuote from: Gigatron on May 06, 2024, 08:36:12 amThis fx is slow for me .. Yeah, that is way of things. Learn to know the tools and their trade- offs. So, - the font can be set to the virtual screen once. However slightly, it helps. - at a certain point clearing the screen (big surface) at once is cheaper than (re)drawing smaller bits - in accordance with the above, skip drawing when there is actually nothing to draw (spaces) - also however slightly it helps, pre-calculation of sin/coords (that has a certain drawback ofc.) - note that using a timer to actually time frames is .. not smart ... to say the least. It fires every x-th millisecond an is literally wasting all time in between (I know it a timer is a simple pleasure usage and use it myself as well). - the bigger slowness seem to originate form redrawing of the same thing over and over (opengl caches some important parts hence the speed increase), so pre-draw the glyphs and blit a single glyph at once. There are many more things that are able to influence speed (or the perception thereof). The funny part of this is... we are talking about hardware that is around 3-4 decades old (the generation before Amiga was also capable of these same fx) and is able to display such a wavy text without breaking a sweat with enough time to spare to do some actual important stuff. It is a living testimony that relying on cpu grunt alone is not the smartest way to approach these kind of things. You explained the situation perfectly I have not tried to optimize the assembly code to speed up the execution, however I wonder about a sine table precalculated in advance by myself so what is the use of the 8 cores that I have , if it is not capable of calculating values ​​of 27*8 sine in real time. If commodore's i****s weren't *****, we would all be on amiga now. I still have Winuae on PC ---------------------------------------------------------------------- KodeZwerg · 2024-05-07 14:35 another small update that the wave become a wobble (and now the "message" could be a dynamic array of ansistring) 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 procedure TForm1.BGLVirtualScreen1Redraw(Sender: TObject;  BGLContext: TBGLContext);var  Column,  Row: Integer;begin  for Row := Low(Message) to High(Message) do    for Column := Low(Message[Row]) to Length(Message[Row]) do      begin        // movement modifier        angle := angle + 0.0004;        // left to right movement        xPos := (xStart + 2) + 3 * Sin(angle - Row * -2) * 2;        // up and down movement        yPos := (yStart + Column * 15) + 3 * Cos(angle - Row * 0.004 - Column) * 3;        // fake shadow character        GLFont.TextOut(Column * 24 + xPos + 5, (Row * 32 + yPos - Column * 15) + 5, Message[Row][Column], BGRA(1, 1, 1));        // actual text character        GLFont.TextOut(Column * 24 + xPos, Row * 32 + yPos - Column * 15, Message[Row][Column], BGRA(254, 254, 254));      end;end;all those fixed numbers could become parameters to tweak the mechanism, many variations possible Nice done @Guva! ---------------------------------------------------------------------- Gigatron · 2024-05-07 16:45 Very nice mr KodeZwerg; I am working for another good text fx , my goal is doing that in digital demo; https://www.youtube.com/watch?v=fcB-v8D3i6s&t=52s For now just begining slowly and really non optimized code sorry i am lazy ; 245 linesof code is not acceptable will reduce it soon ; I had to do the same thing in lua, lazy that I am https://tic80.com/play?cart=3659 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,  BGLVirtualScreen, BGRAOpenGL, BGRABitmap, BGRABitmapTypes; type   { TForm1 }   TForm1 = class(TForm)    BGLVirtualScreen1: TBGLVirtualScreen;    Timer1: TTimer;    procedure BGLVirtualScreen1Redraw(Sender: TObject; BGLContext: TBGLContext);    procedure FormCreate(Sender: TObject);  procedure FormShow(Sender: TObject);    procedure Timer1Timer(Sender: TObject);    procedure reset;  private        GLFont: IBGLFont;  public   end; var  Form1: TForm1;   x,y,i,j,g_timer,idx  : integer;  // general demo timer  tx: Array[0..12]  Of String;  dest_y :Array[0..12]  Of integer; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin       x:=20; y:=0; i :=0; j :=0;      tx[0] := '+*************************+';     tx[1] := '*        GIGATRON         *';     tx[2] := '*                       *';     tx[3] := '*    PRESENTS TEXT FX#2   *';     tx[4] := '*                         *';     tx[5] := '*    BGRA COMPONENT GL    *';     tx[6] := '*                         *';     tx[7] := '* @@ LAZARUS FPC RULEZ @@ *';     tx[8] := '*                         *';   tx[9] := '******   *********   ******';     tx[10]:= '*   AMIGA DIGITAL FONT    *';     tx[11]:= '*      BY DOUGHNUT        *';     tx[12]:= '+*************************+';      for i:=0 to 12 do     begin     dest_y[i] := 800  ;     end; end; procedure TForm1.FormShow(Sender: TObject);begin     GLFont := BGLFont('AmigaDigital8',40);     GLFont.SetStepX(-12);end; procedure TForm1.BGLVirtualScreen1Redraw(Sender: TObject;BGLContext: TBGLContext);begin     for i:=0 to 1 do    begin      GLFont.TextOut(x, dest_y[0]+6  ,   tx[0],BGRA(68,85,102));      GLFont.TextOut(x, dest_y[0]    ,   tx[0],BGRA(255,255,255));      dest_y[0] := dest_y[0] - 8 ;      if  (dest_y[0]<0) then dest_y[0]:=0;     end;      if(g_timer>30) then     begin      for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[1]+6  ,   tx[1],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[1]    ,   tx[1],BGRA(255,255,255));          dest_y[1] := dest_y[1] - 8 ;        if  (dest_y[1]<32) then dest_y[1]:=32;        end;     end;       if(g_timer>60) then     begin        for i:=0 to 1 do        begin        GLFont.TextOut(x, dest_y[2]+6  ,   tx[2],BGRA(68,85,102));        GLFont.TextOut(x, dest_y[2]    ,   tx[2],BGRA(255,255,255));        dest_y[2] := dest_y[2] - 8 ;          if  (dest_y[2]<64) then dest_y[2]:=64;        end;     end;      if(g_timer>90) then     begin        for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[3]+6  ,   tx[3],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[3]    ,   tx[3],BGRA(255,255,255));          dest_y[3] := dest_y[3] - 8 ;          if  (dest_y[3]<96) then dest_y[3]:=96;      end;     end;       if(g_timer>120) then     begin       for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[4]+6  ,   tx[4],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[4]    ,   tx[4],BGRA(255,255,255));          dest_y[4] := dest_y[4] - 8 ;        if  (dest_y[4]<128) then dest_y[4]:=128;        end;     end;      if(g_timer>150) then     begin       for i:=0 to 1 do        begin        GLFont.TextOut(x, dest_y[5]+6  ,   tx[5],BGRA(68,85,102));        GLFont.TextOut(x, dest_y[5]    ,   tx[5],BGRA(255,255,255));        dest_y[5] := dest_y[5] - 8 ;          if  (dest_y[5]<160) then dest_y[5]:=160;        end;     end;      if(g_timer>180) then     begin      for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[6]+6  ,   tx[6],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[6]    ,   tx[6],BGRA(255,255,255));          dest_y[6] := dest_y[6] - 8 ;          if  (dest_y[6]<192) then dest_y[6]:=192;      end;     end;       if(g_timer>210) then     begin      for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[7]+6  ,   tx[7],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[7]    ,   tx[7],BGRA(255,255,255));          dest_y[7] := dest_y[7] - 8 ;        if  (dest_y[7]<224) then dest_y[7]:=224;        end;     end;      if(g_timer>240) then     begin      for i:=0 to 1 do        begin        GLFont.TextOut(x, dest_y[8]+6  ,   tx[8],BGRA(68,85,102));        GLFont.TextOut(x, dest_y[8]    ,   tx[8],BGRA(255,255,255));        dest_y[8] := dest_y[8] - 8 ;          if  (dest_y[8]<256) then dest_y[8]:=256;        end;     end;     if(g_timer>270) then     begin      for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[9]+6  ,   tx[9],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[9]    ,   tx[9],BGRA(255,255,255));          dest_y[9] := dest_y[9] - 8 ;          if  (dest_y[9]<288) then dest_y[9]:=288;      end;     end;      if(g_timer>300) then     begin      for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[10]+6  ,   tx[10],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[10]    ,   tx[10],BGRA(255,255,255));          dest_y[10] := dest_y[10] - 8 ;        if  (dest_y[10]<320) then dest_y[10]:=320;        end;     end;      if(g_timer>330) then     begin      for i:=0 to 1 do        begin        GLFont.TextOut(x, dest_y[11]+6  ,   tx[11],BGRA(68,85,102));        GLFont.TextOut(x, dest_y[11]    ,   tx[11],BGRA(255,255,255));        dest_y[11] := dest_y[11] - 8 ;          if  (dest_y[11]<352) then dest_y[11]:=352;        end;     end;      if(g_timer>360) then   begin      for i:=0 to 1 do        begin          GLFont.TextOut(x, dest_y[12]+6  ,   tx[12],BGRA(68,85,102));          GLFont.TextOut(x, dest_y[12]    ,   tx[12],BGRA(255,255,255));          dest_y[12] := dest_y[12] - 8 ;          if  (dest_y[12]<384) then dest_y[12]:=384;      end;     end; end; procedure TForm1.Timer1Timer(Sender: TObject);begin         BGLVirtualScreen1.Repaint;         inc(g_timer,1);         if(g_timer>600) then         begin          g_timer :=0;          BGLVirtualScreen1.Invalidate;          reset;       end; end; procedure TForm1.reset();var  i :integer;begin    i:=0;    for i:=0 to 12 do     begin     dest_y[i] := 800  ;     end; end; end.   Quote from: KodeZwerg on May 07, 2024, 04:35:11 pmanother small update that the wave become a wobble (and now the "message" could be a dynamic array of ansistring) 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 procedure TForm1.BGLVirtualScreen1Redraw(Sender: TObject;  BGLContext: TBGLContext);var  Column,  Row: Integer;begin  for Row := Low(Message) to High(Message) do    for Column := Low(Message[Row]) to Length(Message[Row]) do      begin        // movement modifier        angle := angle + 0.0004;        // left to right movement        xPos := (xStart + 2) + 3 * Sin(angle - Row * -2) * 2;        // up and down movement        yPos := (yStart + Column * 15) + 3 * Cos(angle - Row * 0.004 - Column) * 3;        // fake shadow character        GLFont.TextOut(Column * 24 + xPos + 5, (Row * 32 + yPos - Column * 15) + 5, Message[Row][Column], BGRA(1, 1, 1));        // actual text character        GLFont.TextOut(Column * 24 + xPos, Row * 32 + yPos - Column * 15, Message[Row][Column], BGRA(254, 254, 254));      end;end;all those fixed numbers could become parameters to tweak the mechanism, many variations possible Nice done @Guva! ---------------------------------------------------------------------- KodeZwerg · 2024-05-07 17:56 I tried to simplify your loops but something I do wrong :-/ 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 var  Row: Integer;  yOffset: Integer;begin  for Row := Low(tx) to High(tx) do  for yOffset := BGLContext.Canvas.ClipRect.Height downto (Row * 32) do      begin        GLFont.TextOut(x, yOffset, tx[Row], BGRA(68,85,102));        GLFont.TextOut(x, yOffset, tx[Row], BGRA(255,255,255));      end;end; ---------------------------------------------------------------------- Gigatron · 2024-05-08 18:20 Hi, Just reduced the code above from 245 lines to 110. 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,  BGLVirtualScreen, BGRAOpenGL, BGRABitmap, BGRABitmapTypes,Math; type   { TForm1 }   TForm1 = class(TForm)    BGLVirtualScreen1: TBGLVirtualScreen;    Timer1: TTimer;    procedure BGLVirtualScreen1Redraw(Sender: TObject; BGLContext: TBGLContext);    procedure FormCreate(Sender: TObject);  procedure FormShow(Sender: TObject);    procedure Timer1Timer(Sender: TObject);    procedure reset;  private        GLFont: IBGLFont;  public end; var  Form1: TForm1;  x,y,i,j,g_timer,speed  : integer;  // general demo timer  tx: Array[0..12]  Of String;  dest_y :Array[0..12]  Of integer; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin     x:=20; y:=0; i :=0; j :=0; speed := 20; // speed of fx      tx[0] := '+*************************+';     tx[1] := '*        GIGATRON       *';     tx[2] := '*                         *';     tx[3] := '*    PRESENTS TEXT FX#2   *';     tx[4] := '*                         *';     tx[5] := '*    BGRA COMPONENT GL    *';     tx[6] := '*                       *';     tx[7] := '* @@ LAZARUS FPC RULEZ @@ *';     tx[8] := '*                         *';     tx[9] := '******   *********   ******';     tx[10]:= '*   AMIGA DIGITAL FONT    *';     tx[11]:= '*    BY DOUGHNUT        *';     tx[12]:= '+*************************+';      for i:=0 to 12 do     begin     dest_y[i] := 800  ; // set ypos for each line     end;end; procedure TForm1.FormShow(Sender: TObject);begin     GLFont := BGLFont('AmigaDigital8',40);     GLFont.SetStepX(-12);end; procedure TForm1.BGLVirtualScreen1Redraw(Sender: TObject; BGLContext: TBGLContext);begin  for j := 0 to  Min((g_timer div speed), High(tx)) do  begin    if g_timer > (j * speed) then    begin      for i := 0 to 1 do      begin        GLFont.TextOut(x, dest_y[j] + 6, tx[j], BGRA(68, 85, 102));        GLFont.TextOut(x, dest_y[j], tx[j], BGRA(255, 255, 255));        dest_y[j] := dest_y[j] - 8;        if dest_y[j] < (j * 32) then dest_y[j] := j * 32;      end;    end;  end;end; procedure TForm1.Timer1Timer(Sender: TObject);begin         BGLVirtualScreen1.Repaint;         inc(g_timer,1);         if(g_timer>500) then         begin          g_timer :=0;          BGLVirtualScreen1.Invalidate;          reset;         end;  end; procedure TForm1.reset();begin    i:=0;    for i:=0 to 12 do     begin       dest_y[i] := 800  ;     end;end; end. ---------------------------------------------------------------------- Guva · 2024-05-09 02:19 @Gigatron thanks for the text effects. that's what I got in the end. https://www.youtube.com/watch?v=dUnmISyqlEI Final version https://www.youtube.com/watch?v=SGmaGI-JNT4 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 program project1;{$mode objfpc}{$H+}uses {$IFDEF UNIX}cthreads,{$ENDIF} Classes, SysUtils, CustApp, RayLib, RayMath, Math; const AppTitle = 'raylib - text fx#1';type  { TRayApplication }  TRayApplication = class(TCustomApplication)  protected    message : Array[0..9] Of Pchar;    MyFont: TFont;    Texture: TTexture2D;    Shader: TShader;  line_message :Array of PChar;    angle, line_angle, xPos, LineXpos, yPos, LineYpos, FreqX, FreqY,    AmpX, AmpY, SpeedX, SpeedY, Seconds : Single;    xStart, yStart, lineXstart, LineYstart, SecondsLoc, FreqXLoc,    FreqYLoc, AmpXLoc, AmpYLoc, SpeedXLoc, SpeedYLoc: Integer;    ScreenSize: array [0..1] of Single;    LineColor: TColorB;    procedure DoRun; override;  public    constructor Create(TheOwner: TComponent); override;    destructor Destroy; override;  end; var  alpha: byte;constructor TRayApplication.Create(TheOwner: TComponent);begin  inherited Create(TheOwner);  InitWindow(800, 450, AppTitle); // for window settings, look at example - window flags   MyFont:= LoadFont('Phased.ttf');  angle   := 0; xPos := 0; yPos    := 0;  xStart  := 80; yStart  := 40;  LinexStart  := 800; LineyStart  := 380;  LineXPos := 800;   message[0] := '                           ';  message[1] := '        GIGATRON           ';  message[2] := '                         ';  message[3] := '     PRESENTS TEXT FX#1    ';  message[4] := '                           ';  message[5] := '       150 LINE CODE       ';  message[6] := ' ------------------------- ';  message[7] := '       RAYLIB RULEZ  !!!   ';  message[8] := ' ------------------------- ';  message[9] := '                         ';   SetLength(line_message, 1);  line_message[0] := TextToUpper('raylib is a simple and easy-to-use library to enjoy videogames programming. Thanks to Ramon Santamarina and the raylib community for a great product');  // Load texture texture to apply shaders  Texture := LoadTexture('space.png');  // Load shader and setup location points and values  Shader := LoadShader(nil, GetAppDir('wave.fs'));   secondsLoc := GetShaderLocation(shader, 'seconds');  freqXLoc := GetShaderLocation(shader, 'freqX');  freqYLoc := GetShaderLocation(shader, 'freqY');  ampXLoc := GetShaderLocation(shader, 'ampX');  ampYLoc := GetShaderLocation(shader, 'ampY');  speedXLoc := GetShaderLocation(shader, 'speedX');  speedYLoc := GetShaderLocation(shader, 'speedY');   // Shader uniform values that can be updated at any time  freqX := 25.0;  freqY := 25.0;  ampX := 5.0;  ampY := 5.0;  speedX := 8.0;  speedY := 8.0;  ScreenSize[0] := GetScreenWidth();  ScreenSize[1] := GetScreenHeight();  SetShaderValue(shader, GetShaderLocation(shader, 'size'), @screenSize, SHADER_UNIFORM_VEC2);  SetShaderValue(shader, freqXLoc, @freqX, SHADER_UNIFORM_FLOAT);  SetShaderValue(shader, freqYLoc, @freqY, SHADER_UNIFORM_FLOAT);  SetShaderValue(shader, ampXLoc, @ampX, SHADER_UNIFORM_FLOAT);  SetShaderValue(shader, ampYLoc, @ampY, SHADER_UNIFORM_FLOAT);  SetShaderValue(shader, speedXLoc, @speedX, SHADER_UNIFORM_FLOAT);  SetShaderValue(shader, speedYLoc, @speedY, SHADER_UNIFORM_FLOAT);  Seconds := 0.0;  SetTargetFPS(60); // Set our game to run at 60 frames-per-secondend; procedure TRayApplication.DoRun;var i,j,n: integer; cp: integer;begin  while (not WindowShouldClose) do // Detect window close button or ESC key  begin   // update   seconds += GetFrameTime();   SetShaderValue(shader, secondsLoc, @seconds, SHADER_UNIFORM_FLOAT);   if alpha <> 255 then Inc(Alpha);   // draw    BeginDrawing();    ClearBackground(WHITE);    BeginShaderMode(Shader);      DrawTexture(Texture, 0, 0, WHITE);      DrawTexture(Texture, Texture.Width, 0, WHITE);    EndShaderMode();    for i:=0 to 26 do    for j:=0 to 9 do     begin       angle := angle + 0.0004;       // left to right movement       xPos := (xStart + 2) + 10 * Sin(angle - j * 0.005);       // up and down movement       yPos := (yStart + i * 15) + 4 * Cos(angle - j * 0.004 - i) * 2;       DrawTextCodepoint(MyFont,Integer(message[j][i]), Vector2Create(i * 24 + xPos,  (j*32 + yPos - i *15 ) + 3), 30, ColorCreate(0,0,0,Alpha));        case j mod 7 of       0: LineColor := ColorCreate(0,158,47, alpha) ;       1: LineColor := ColorCreate(255,109,194,Alpha);       2: LineColor := ColorCreate(0,121,241,Alpha);       3: LineColor := ColorCreate(253,249,0,Alpha);       4: LineColor := ColorCreate(102,191,255,Alpha);       5: LineColor := ColorCreate(255,161,0,Alpha);       6: LineColor := ColorCreate(230,41,55,Alpha);       end;       DrawTextCodepoint(MyFont,Integer(message[j][i]), Vector2Create(i * 24 + xPos,  (j*32 + yPos - i *15 )), 30, LineColor);     end;     for  i := 0 to  Length(line_message[0])-1 do    begin     line_angle := line_angle + 0.0007;     if LinexPos < -Length(line_message[0]) * 32  then LinexPos := 800;     LinexPos := LineXPos - 0.01;     LineyPos := (LineyStart + i * 15) + 10 * Cos(line_angle - 0 * 0.004 - i) * 2;   DrawTextCodepoint(MyFont,Integer(line_message[0][i]), Vector2Create(i * 24 + LinexPos,  (0*32 + LineYPos - i *15 ) + 3), 50, Black);     case i mod 7 of     0: LineColor := LIME;   1: LineColor := PINK;     2: LineColor := BLUE;   3: LineColor := YELLOW;     4: LineColor := SKYBLUE; 5: LineColor := ORANGE; 6: LineColor := RED;     end;     DrawTextCodepoint(MyFont,Integer(line_message[0][i]), Vector2Create(i * 24 + LinexPos,  (0*32 + LineYPos - i *15 ) ), 50, LineColor);    end;    EndDrawing();  end;  Terminate;end; destructor TRayApplication.Destroy;begin  CloseWindow(); // Close window and OpenGL context  inherited Destroy;end; var  Application: TRayApplication;begin  Application:=TRayApplication.Create(nil);  Application.Title:=AppTitle;  Application.Run;  Application.Free;end. ---------------------------------------------------------------------- Gigatron · 2024-05-09 17:26 Nice work @Guva, i don't know Raylib but the demo is amazing amiga style And of course, I got curious and looked at Raylib; A little knowledge of glsl fragment shaders; Tested a shader like the space harrier ground plus the tshr music Thanks @Guva So what is the result ? https://www.youtube.com/watch?v=_kvWH1NNN_8 ---------------------------------------------------------------------- Guva · 2024-05-10 03:31 Quote from: Gigatron on May 09, 2024, 07:26:57 pmSo what is the result ? Oh, it looks really cool!!! This video needs to be added in #madewithinraylib on discord channel https://discord.gg/raylib ---------------------------------------------------------------------- Gigatron · 2024-05-10 14:57 Quote from: Guva on May 10, 2024, 05:31:46 amQuote from: Gigatron on May 09, 2024, 07:26:57 pmSo what is the result ? Oh, it looks really cool!!! This video needs to be added in #madewithinraylib on discord channel https://discord.gg/raylib Ok , let me just learn Raylib quickly i mean Faster than light ;  and improve the demo and then will post it to discord sure Edit : Nice, do someting nice at 1500 times faster than light here ; https://www.youtube.com/watch?v=qQUGzPRQhoM&t=42s ---------------------------------------------------------------------- KodeZwerg · 2024-05-10 16:34 Quote from: Guva on May 10, 2024, 05:31:46 amhttps://discord.gg/raylibI was very happy to read about Discord server but a little disappointed on arrival ---------------------------------------------------------------------- Gigatron · 2024-05-23 17:03 Hi, just made another intro using BGRA component; Raylib version is different : https://www.youtube.com/watch?v=dfoDfmjd1x8 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, BGRACanvas2D, Math; 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  procedure drawStar(ctx: TBGRACanvas2D;cx, cy, spikes : integer; outerRadius, innerRadius, rotation : single;style : TBGRAPixel);   procedure reset;  end; var  Form1: TForm1;  rt : double;  x_pos,y_pos : integer;   // txt  x,y,i,j,g_timer,speed  : integer;  // general demo timer  tx: Array[0..12]  Of String =('+******************+',                              '*    GIGATRON      *',                              '*                  *',                                '*PRESENTS TEXT FX#5*',                                '*                  *',                              '*  BGRA COMPONENT  *',                              '*                  *',                                '*@LAZARUS FPC RULEZ*',                                 '********************',                                '*SFX : TDK       *',                                '*FONT: DOUGHNUT    *',                              '*CODE: GIGATRON    *',                              '+******************+');  dest_y :Array[0..12]  Of integer; implementation {$R *.lfm} { TForm1 } procedure Tform1.DrawStar(ctx: TBGRACanvas2D; cx, cy, spikes: Integer; outerRadius, innerRadius, rotation: single;style : TBGRAPixel);var  rot, step, x, y: single;  i: Integer;begin  rot := Pi / 2 * 3 + rotation;  step := Pi / spikes;   ctx.BeginPath;  x := cx + cos(rot) * outerRadius;  y := cy + sin(rot) * outerRadius;  ctx.MoveTo(x, y);   for i := 0 to spikes - 1 do  begin    x := cx + cos(rot) * outerRadius;    y := cy + sin(rot) * outerRadius;    ctx.LineTo(x, y);    rot := rot + step;    x := cx + cos(rot) * innerRadius;    y := cy + sin(rot) * innerRadius;    ctx.LineTo(x, y);    rot := rot + step;  end;   x := cx + cos(rot) * outerRadius;  y := cy + sin(rot) * outerRadius;  ctx.LineTo(x, y);  ctx.ClosePath;   ctx.LineWidth := 50;  ctx.strokeStyle(style);  ctx.Stroke;  ctx.fillStyle ('rgba(0,0,0,0)');;  ctx.Fill;end; procedure TForm1.FormCreate(Sender: TObject);begin  rt := 0.0;  x_pos :=160;  y_pos :=50;      x:=10; y:=0; i :=0; j :=0; speed := 40; // speed of fx     for i:=0 to 12 do     begin     dest_y[i] := 800  ; // set ypos for each lines     end;   sleep(5000);end;procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  ctx: TBGRACanvas2D;begin  ctx := Bitmap.Canvas2D;  bitmap.FontName:='AmigaDigital8';  bitmap.FontHeight := 40;  bitmap.FontAntialias := false;   drawStar(ctx, x_pos+200,y_pos+210, 7, 110.0, 170.0, rt,BGRA(44,55,66));  drawStar(ctx, x_pos+210,y_pos+220, 7, 110.0, 170.0, rt,BGRA(66,77,88));  drawStar(ctx, x_pos+220,y_pos+225, 7, 110.0, 170.0, rt,BGRA(77,88,99));  /// Txt  for j := 0 to  Min((g_timer div speed), High(tx)) do  begin    if g_timer > (j * speed) then    begin      for i := 0 to 1 do      begin        Bitmap.TextOut(x , dest_y[j] + 6, tx[j], BGRA(68, 85, 102));        Bitmap.TextOut(x , dest_y[j],   tx[j], BGRA(255, 255, 255));        dest_y[j] := dest_y[j] - 8;      if dest_y[j] < (j * 32) then dest_y[j] := j * 32;      end;    end;  end;end; procedure TForm1.Timer1Timer(Sender: TObject);begin         rt := rt + 0.02;         inc(g_timer);         if(g_timer>800) then       begin          g_timer :=0;          BGRAVirtualScreen1.Invalidate;          reset;        end;        BGRAVirtualScreen1.RedrawBitmap;end; procedure TForm1.reset();begin  i:=0;    for i:=0 to 12 do     begin       dest_y[i] := 800  ;     end;end; end. ---------------------------------------------------------------------- Gigatron · 2024-06-19 17:38 Hi, Here is another cool text fx, this one bounce each chars of your text from top to bottom and stop ! The javascript live version here : http://gigatron3k.free.fr/laz/bounce.html 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  Positions: array of record    y: Integer;     // yposition for each chars !      vy: Single;     // yposition speed    end;    g: Single;   // gravity    groundLevel: Integer;   public   end; var  Form1: TForm1;  Texte : String = 'GIGATRON PRESENTS';    // text implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);var  i: Integer;begin  SetLength(Positions, Length(Texte));  g := 0.3;  groundLevel := 500;  // fill table y and vy for each char !  for i := 0 to High(Positions) do  begin    Positions[i].y := -140 - i * 40;    Positions[i].vy := 0;  end; end; procedure TForm1.Timer1Timer(Sender: TObject);var  i: Integer;begin  for i := 0 to High(Positions) do  begin    Positions[i].vy := Positions[i].vy + Frac(g);    Positions[i].y := Positions[i].y + Round(Positions[i].vy);     if Positions[i].y > groundLevel then    begin      Positions[i].y := groundLevel;      Positions[i].vy := Positions[i].vy * Frac(-0.8);    end;  end;   BGRAVirtualScreen1.RedrawBitmap;end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var    i,x, y: Integer;begin   Bitmap.FontName := 'AmigaDigital8';  // your ttf font  Bitmap.FontHeight := 80;   for i := 1 to Length(Texte) do  begin    x := 60 + (i - 1) * 40; // space between char * 40    y := Positions[i - 1].y;    Bitmap.TextOut(x+2, y+4, Texte[i],BGRA(105,105,105));    Bitmap.TextOut(x, y, Texte[i],BGRA(255,255,255));  end;end; end. ---------------------------------------------------------------------- Gigatron · 2024-06-25 18:26 Hi all; Here is another cool demo of bounce text ; sfx from MAF64 ; Try to improve this nice cool fx for your production used the best component on this galaxy for lazarus BGRA !! https://www.youtube.com/watch?v=3-TwsuXJ4HA ** Edit : add plot fx and code optimization , all calculation are now much faster !! 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,mmsystem; 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   public   MyAudio_File: AnsiString;  WavStream : TMemoryStream;  gtr_scanner,phx_scanner: TWaveScanner;   end; var  Form1: TForm1;  ddr_table: Array[0..15] of integer =(0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1);   // sinus movement factor table   tx: Array[0..13]  Of String =('                         ',                                '      GIGATRON PRESENTS    ',                                '  THE GREAT GIANA SISTERS  ',                                '   CRACKED ON 08/06/2024   ',                                '   GREETING TO MEMBERS OF  ',                                ' TRONIC-SYSTEM AND SUB-SERO',                              ' ALL LAZARUS AND FPC TEAM  ',                              '   SFX BY : MAF64  R.I.P   ',                              '      GFX BY : RED-MAX     ',                              '   @ LAZARUS FPC RULEZ @   ',                                '  THE BEST COMPONENT BGRA  ',                                '     THANX TO CIRCULAR     ',                                ' SEE YOU ON NEXT PRODUCTION',                                '      GOTO SUB-QUANTUM   ');   // attention tx vars !  tm,tx_id,dir,x,y,vx  : integer ;  g,vy : single ;  groundLevel : integer;  // logo  phenix,gtr  phenix,gtr : TBGRABitmap;   // ddr  table index !  ddr : integer;   // dot plot  s,a : single;  implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin   // init text vars    tm := 0;    tx_id := 0;    dir := 1; // vers la droite    g := 0.6; // acceleration gravity    x := 0; // initial horizontal position    y := -400; // initial vertical position out of scene   vx := 0; // initial horizontal speed   in case ; unused !!   vy := 0; // initial vertical speed   groundLevel := 500;    ddr := 0; // table index    // plot fx   s := 255/sqrt(3)*2/30;   a := 0.0;  // angle     BGRAVirtualScreen1.Color := $00776655;    phenix := TBGRABitmap.Create('phex.png');   gtr    := TBGRABitmap.Create('gtr.png');    gtr_scanner := TWaveScanner.Create(gtr,false, false); // bitmap   gtr_scanner.Translate(140,-40);    phx_scanner := TWaveScanner.Create(phenix,false, false); // bitmap   phx_scanner.Translate(110,80);    // audio   // audio stream   // MyAudio_File := 'pp2.wav';   // WavStream    := TMemoryStream.Create;   // WavStream.LoadFromFile(MyAudio_File);   // PlaySound(WavStream.Memory, 0, SND_NODEFAULT or SND_LOOP or SND_ASYNC or SND_MEMORY); end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  xx,yy : integer;  r,z,x1,x2,y1,y2 : single;begin      // plot fx      for xx:=15 downto -15 do       begin       for yy:=15 downto -15 do        begin        r := (sqrt(xx*xx+yy*yy))+2;       z := 40*sin(r+a*0.6)/r*0.8;        x2 := xx*cos(a*PI/180)-yy*sin(a*PI/180);       y2 := xx*sin(a*PI/180)+yy*cos(a*PI/180);        x1 := round(360+(y2-x2)*s*sqrt(3)/2);       y1 := round(360+z-(y2+x2)*s/2);        bitmap.Rectangle(Rect(Round(x1), Round(y1),Round(x1+2), Round(y1+2)),BGRA(25+round(x2),255,255),dmSet);         end;       end;        a := a - 0.4;        //***********************************       // le logo phenix en premier       Bitmap.Fill(phx_scanner,dmFastBlend);       dec(phx_scanner.Time,1);       // puis le logo gtr       inc(gtr_scanner.Time,1);       Bitmap.Fill(gtr_scanner,dmFastBlend);        // puis le texte ligne par ligne !       Bitmap.FontName := 'AmigaDigital';  // your ttf font       Bitmap.FontHeight := 60;       Bitmap.TextOut(x+4, y+2, tx[tx_id],BGRA(50,50,50));       Bitmap.TextOut(x, y, tx[tx_id],BGRA(255,255,255));  end; procedure TForm1.Timer1Timer(Sender: TObject);begin       vy := vy + Frac(g);      y := y + Round(vy);        if (y >= groundLevel ) then // if text hits the ground       begin         y  := groundLevel;         // reposition it at the ground         vy := vy * Frac(-0.6);    // then reverse and reduce its vertical speed       end;        if( y = groundLevel) then       begin       tm := tm +1;          if(tm>=80) then           begin               if (dir=1) then x := x + 20 ;   // on va aller vite !!              if (dir=2) then x := x - 20 ;              if( x>= 800)  Or (x <=-800 ) then               begin            // si x >< sort de l'ecran reset all vars ;                   tm := 0;                   x  := 0;                   y  := -400;                  ddr := ddr +1;   // commence le sinus movement !                 if(ddr>=14) then ddr := 1;                         dir := dir + 1;                        if(dir>2) then dir := 1;                       tx_id := tx_id +1;                        if(tx_id>=14 ) then tx_id := 0;                end;             end;        end;        BGRAVirtualScreen1.RedrawBitmap;end; { TWaveScanner } function TWaveScanner.GetOffset(X, Y: Single): Single;begin  result := ddr_table[ddr] * sin((Y + Time) * 30/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-06-26 16:29 Hi, Here is the final code before something new ! 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,mmsystem; 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);    function cs(agl : Single)  : Single;   private   public   MyAudio_File: AnsiString;  WavStream : TMemoryStream;  gtr_scanner,phx_scanner: TWaveScanner;    end; var  Form1: TForm1;  ddr_table: Array[0..15] of integer =(0,1,2,3,4,5,6,7,8,7,6,5,4,3,2,1);   // sinus movement factor table   tx: Array[0..13]  Of String =('                           ',                              '      GIGATRON PRESENTS    ',                              '  THE GREAT GIANA SISTERS  ',                              '   CRACKED ON 08/06/2024   ',                                '  GREETINGS TO MEMBERS OF  ',                                ' TRONIC- SYSTEM AND SUB-SERO',                                ' ALL LAZARUS AND FPC TEAM  ',                                ' SFX BY : KARSTEN OBARSKI  ',                                '      GFX BY : RED-MAX     ',                              '   @ LAZARUS FPC RULEZ @   ',                              '  THE BEST COMPONENT BGRA  ',                              '     THANX TO CIRCULAR     ',                                ' SEE YOU ON NEXT PRODUCTION',                                '      GOTO SUB-QUANTUM     ');   // attention tx vars !  tm,tx_id,dir,x,y,vx  : integer ;  g,vy : single ;  groundLevel : integer;  // logo  phenix,gtr  phenix,gtr : TBGRABitmap;   // ddr  table index !  ddr : integer;   // dot plot  s,a,a2 : single;  rot : Boolean;  rot_dir,rot_timer : integer;  implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin   // init text vars    tm := 0;    tx_id := 0;    dir := 1; // vers la droite  g := 0.6; // acceleration gravity    x := 0; // initial horizontal position    y := -400; // initial vertical position out of scene   vx := 0; // initial horizontal speed   in case ; unused !!   vy := 0; // initial vertical speed   groundLevel := 500;    ddr := 0; // table index    // plot fx   s := 255/sqrt(3)*2/30;   a := 0.0;  // angle   a2:= 0.0;   rot := false;   rot_dir := 0;   rot_timer :=0;    BGRAVirtualScreen1.Color := $00776655;    phenix := TBGRABitmap.Create('phex.png');   gtr    := TBGRABitmap.Create('gtr.png');    gtr_scanner := TWaveScanner.Create(gtr,false, false); // bitmap   gtr_scanner.Translate(140,-40);    phx_scanner := TWaveScanner.Create(phenix,false, false); // bitmap   phx_scanner.Translate(110,80);    // audio   // audio stream    MyAudio_File := 'blueberry.wav';    WavStream    := TMemoryStream.Create;    WavStream.LoadFromFile(MyAudio_File);    PlaySound(WavStream.Memory, 0, SND_NODEFAULT or SND_LOOP or SND_ASYNC or SND_MEMORY); end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  xx,yy : integer;  z,x1,x2,y1,y2 : single; begin     // plot fx      for xx:=15 downto -15 do       begin       for yy:=15 downto -15 do        begin        z := cs(sqrt(xx*xx+yy*yy)/30-a)*30;        x2 := xx*cos(2*a2*PI/180)-yy*sin(a2*PI/180);       y2 := xx*sin(2*a2*PI/180)+yy*cos(a2*PI/180);        x1 := round(360+(y2-x2)*s*sqrt(3)/2);       y1 := round(360+z-(y2+x2)*s/2);        bitmap.Rectangle(Rect(Round(x1), Round(y1),Round(x1+2), Round(y1+2)),BGRA(255,255,255),dmSet);         end;       end;        a := a + 0.005;       if(rot) and (rot_dir=1) then a2 := a2 + 0.2;       if(rot) and (rot_dir=2) then a2 := a2 - 0.2;        //***********************************       // le logo phenix en premier       Bitmap.Fill(phx_scanner,dmFastBlend);       dec(phx_scanner.Time,1);       // puis le logo gtr       inc(gtr_scanner.Time,1);       Bitmap.Fill(gtr_scanner,dmFastBlend);        // puis le texte ligne par ligne !       Bitmap.FontName := 'AmigaDigital';  // your ttf font       Bitmap.FontHeight := 60;       Bitmap.TextOut(x+4, y+2, tx[tx_id],BGRA(50,50,50));       Bitmap.TextOut(x, y, tx[tx_id],BGRA(255,255,255)); end; procedure TForm1.Timer1Timer(Sender: TObject);begin       vy := vy + Frac(g);      y := y + Round(vy);        if (y >= groundLevel ) then // if text hits the ground       begin         y  := groundLevel;         // reposition it at the ground         vy := vy * Frac(-0.6);    // then reverse and reduce its vertical speed       end;        if( y = groundLevel) then       begin       tm := tm +1;          if(tm>=80) then           begin               if (dir=1) then x := x + 20 ;   // on va aller vite !!              if (dir=2) then x := x - 20 ;              if( x>= 800)  Or (x <=-800 ) then               begin            // si x >< sort de l'ecran reset all vars ;                   tm := 0;                   x  := 0;                   y  := -400;                 rot := true;                   ddr := ddr +1;   // commence le sinus movement !                   if(ddr>=14) then ddr := 1;                       dir := dir + 1;                        if(dir>2) then dir := 1;                         tx_id := tx_id +1;                      if(tx_id>=14 ) then tx_id := 0;                end;             end;        end;        inc(rot_timer);       if(rot_timer>=1000) then rot_dir   := 1;       if(rot_timer>=2000) then rot_dir   := 2;       if(rot_timer>=3000) then rot_timer :=0;        BGRAVirtualScreen1.RedrawBitmap;end; function TForm1.cs(agl : single)  : single;begin     result := cos(2*PI*agl);end; { TWaveScanner } function TWaveScanner.GetOffset(X, Y: Single): Single;begin  result := ddr_table[ddr] * sin((Y + Time) * 30/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 of demoend.