Copper Chunky Pixel lazarus / 39-Graphics ---------------------------------------------------------------------- Gigatron · 2025-05-11 00:48 Hi, A nice fx from amiga called copper chunky; Working with grid cells , code from a javascript version not optimized yet ! example of this code on Scoopex Cracktro : https://youtu.be/urhCo_3Khd4?si=0viz1GNDdnYe0X6v&t=14 Or Digital A maze intro https://youtu.be/fcB-v8D3i6s?si=8soBKLQwBaIIakbA&t=72 Explanation of Copper Chunky : https://www.youtube.com/watch?v=ste_ejNVvDk 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, StdCtrls,  BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes; type  { TForm1 }  TForm1 = class(TForm)  BGRAVirtualScreen1: TBGRAVirtualScreen;    Button1: TButton;    Panel1: TPanel;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    ZoomFactor: Single;    MaxZoom: Single;    MinZoom: Single;    CellSize: Integer;    Angle: Single;    RotSpeed: Single;    Tmr: Single;    ZoomCenter: Single;    ZoomAmp: Single;  public  end; var  Form1: TForm1;  tex : TBGRABitmap; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  // texture  tex := TBGRABitmap.Create('gl.png');  MaxZoom :=  5.0;  MinZoom := 2.0;  CellSize := 8;  Angle := 0;  RotSpeed := 0.6;  Tmr := 0;  ZoomCenter := (MaxZoom + MinZoom) / 2;  ZoomAmp := (MaxZoom - MinZoom) / 2;  ZoomFactor := ZoomCenter / 8; end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  x, y: Integer;  bx, by: Integer;  dx, dy: Single;  sx, sy: Integer;  centerX, centerY: Single;  zoom: Single;  col: TBGRAPixel;  angleRad: Single;  sinVal, cosVal: Single;  rotX, rotY: Single;begin   centerX := tex.Width / 2;  centerY := tex.Height / 2;  zoom := 1 / ZoomFactor;  angleRad := Angle * Pi / 180;  sinVal := Sin(angleRad);  cosVal := Cos(angleRad);  Bitmap.Fill(BGRABlack);  // pixel fx ok with pascal  for y := 0 to (BGRAVirtualScreen1.Height - 1) div CellSize do  begin    for x := 0 to (BGRAVirtualScreen1.Width - 1) div CellSize do    begin      dx := (x * CellSize - BGRAVirtualScreen1.Width/2) * zoom;      dy := (y * CellSize - BGRAVirtualScreen1.Height/2) * zoom;      rotX := dx * cosVal - dy * sinVal;      rotY := dx * sinVal + dy * cosVal;      sx := Round(centerX + rotX);      sy := Round(centerY + rotY);      // Replace pixel on each cells adapted from js;      if (sx >= 0) and (sx < tex.Width) and (sy >= 0) and (sy < tex.Height) then      begin      // get pixel source        col := tex.GetPixel(sx, sy);        // cells block        for by := 0 to CellSize - 1 do        begin        for bx := 0 to CellSize - 1 do          begin            if (x * CellSize + bx < BGRAVirtualScreen1.Width) and            (y * CellSize + by < BGRAVirtualScreen1.Height) then            begin              Bitmap.SetPixel(x * CellSize + bx, y * CellSize + by, col);          end;          end;        end;       end;    end;  end; end; procedure TForm1.Button1Click(Sender: TObject);begin  RotSpeed := -RotSpeed;end; procedure TForm1.Timer1Timer(Sender: TObject);begin  Tmr := Tmr + 0.01;  // counter timer  ZoomFactor := ZoomCenter + (ZoomAmp * Sin(Tmr * 0.5));  Angle := Angle + RotSpeed;  BGRAVirtualScreen1.RedrawBitmap;end; end. Base code js : Code: Javascript  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function rotozoom() {    const centerX = srcWidth / 2;    const centerY = srcHeight / 2;    const zoom = 1 / config.zoom;    const angleRad = config.angle * Math.PI / 180;    const sin = Math.sin(angleRad);    const cos = Math.cos(angleRad);        const bufferData = bufferCtx.createImageData(config.width, config.height);    const pixels = bufferData.data;    const step = config.blockSize;              clearCanvas();        for (let y = 0; y < config.height; y += step) {        for (let x = 0; x < config.width; x += step) {          // Transformation            const dx = (x - config.width/2) * zoom;            const dy = (y - config.height/2) * zoom;            const sx = Math.floor(centerX + dx * cos - dy * sin);            const sy = Math.floor(centerY + dx * sin + dy * cos);             if (sx >= 0 && sx < srcWidth && sy >= 0 && sy < srcHeight) {                const srcPos = (sy * srcWidth + sx) << 2;                              for (let by = 0; by < step && y + by < config.height; by++) {                  for (let bx = 0; bx < step && x + bx < config.width; bx++) {                        const destPos = ((y + by) * config.width + (x + bx)) << 2;                        pixels[destPos] = srcData[srcPos];       // R                        pixels[destPos+1] = srcData[srcPos+1];   // G                        pixels[destPos+2] = srcData[srcPos+2];   // B                        pixels[destPos+3] = 255;                 // A                    }                }          }        }    }        bufferCtx.putImageData(bufferData, 0, 0);  ctx.drawImage(buffer, 0, 0);} ---------------------------------------------------------------------- Gigatron · 2025-05-11 12:57 Hi A new version of this nice chunky copper effect , Pascal version is near 95% of the original amiga effet version. https://www.youtube.com/watch?v=ste_ejNVvDk Source bird image from : https://powerprograms.nl/amiga/copper- chunky.html You can change cellsize, speed, zoom factor and reverse rotation. This demo is running fullscreen to see how BGRA and Pascal code is 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, StdCtrls,  Spin, BGRAVirtualScreen, BGRABitmap, BGRABitmapTypes; type  { TForm1 }  TForm1 = class(TForm)    BGRAVirtualScreen1: TBGRAVirtualScreen;    Button1: TButton;    FloatSpinEdit1: TFloatSpinEdit;    FloatSpinEdit2: TFloatSpinEdit;    Panel1: TPanel;    SpinEdit1: TSpinEdit;    Timer1: TTimer;    procedure BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure Timer1Timer(Sender: TObject);  private    ZoomFactor, MaxZoom, MinZoom, Angle, RotSpeed, Tmr, ZoomCenter, ZoomAmp: Single;    CellSize: Integer;  public  end; var  Form1: TForm1;  tex : TBGRABitmap; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  // texture  tex := TBGRABitmap.Create('bird.jpg');  MaxZoom :=  4.0;  MinZoom := 1.5;  CellSize := 12;  Angle := 0;  RotSpeed := 0.6;  Tmr := 0;  ZoomCenter := (MaxZoom + MinZoom) / 2;  ZoomAmp := (MaxZoom - MinZoom) / 2;  ZoomFactor := ZoomCenter / 8;end; procedure TForm1.BGRAVirtualScreen1Redraw(Sender: TObject; Bitmap: TBGRABitmap);var  x, y: Integer;  bx, by: Integer;  dx, dy: Single;  sx, sy: Integer;  centerX, centerY: Single;  zoom: Single;  col: TBGRAPixel;  angleRad: Single;  sinVal, cosVal: Single;  rotX, rotY: Single;begin   centerX := tex.Width / 2;  centerY := tex.Height / 2;  zoom := 1 / ZoomFactor;  angleRad := Angle * Pi / 180;  sinVal := Sin(angleRad);  cosVal := Cos(angleRad);  Bitmap.Fill(BGRABlack);  // pixel fx ok with pascal  for y := 0 to (BGRAVirtualScreen1.Height - 1) div CellSize do  begin    for x := 0 to (BGRAVirtualScreen1.Width - 1) div CellSize do    begin      dx := (x * CellSize - BGRAVirtualScreen1.Width/2) * zoom;      dy := (y * CellSize - BGRAVirtualScreen1.Height/2) * zoom;      rotX := dx * cosVal - dy * sinVal;      rotY := dx * sinVal + dy * cosVal;      sx := Round(centerX + rotX);      sy := Round(centerY + rotY);      // Replace pixel on each cells inside limits adapted from js;      if (sx >= 0) and (sx < tex.Width) and (sy >= 0) and (sy < tex.Height) then    begin        // get pixel source        col := tex.GetPixel(sx, sy);        // fill cells block        for by := 0 to CellSize - 1 do        begin          for bx := 0 to CellSize - 1 do          begin          if (x * CellSize + bx < BGRAVirtualScreen1.Width) and          (y * CellSize + by < BGRAVirtualScreen1.Height) then            begin              Bitmap.SetPixel(x * CellSize + bx, y * CellSize + by, col);            end;          end;        end;      end;     end;  end; end; procedure TForm1.Button1Click(Sender: TObject);begin  FloatSpinEdit1.Value := -FloatSpinEdit1.Value;end; procedure TForm1.Timer1Timer(Sender: TObject);begin  Tmr := Tmr + 0.01;  // counter timer  ZoomFactor := ZoomCenter + (ZoomAmp * Sin(Tmr * 0.5));  Angle := Angle + RotSpeed;  CellSize := SpinEdit1.Value;  RotSpeed := FloatSpinEdit1.Value;  ZoomFactor := FloatSpinEdit2.Value; // never negative ! div / 0  BGRAVirtualScreen1.RedrawBitmap;end;end.