I am attaching a version of your project which scales correctly.
w := 800 + Panel1.Width;
Width := w;
Height := w - Panel1.Width;
t := 0;
Don't know what you want to achieve with this in the OnCreate handler of the form, but the large literal numeric value 800 certainly is a severe issue for correct scaling because the corresponding dimension does not change when the pixel density changes. Since you add 800 to the panel width and then assign it to the width of the form, I guess you want the size of the Paintbox to be 800x800? For such a case, I would set the Paintbox.Constraints.MinWidth and .MaxWidth to 800 and the .MinHeight and .MaxHeight as well - this would freeze the size of the paintbox and protect it from incidental size changes.
Nevertheless, I skipped this detail in the modified demo because I found another issue: You do not scale the size of the buffer bitmap - this is an object that you created and you have the responsibility to scale it. You create the bitmap in the OnCreate event of the form, and you also define the size variable w there. But OnCreate often is too early when size calculations are involved because the form does not yet have a parent at this early state and thus sizing operations are delayed.
You can postpone your bitmap creation to a later state, I prefer the OnActivate event (along with a status variable to avoid multiple calls):
procedure TForm1.FormCreate(Sender: TObject);
begin
{ Don't use unscaled dimensions!
w := 800 + Panel1.Width;
Width := w;
Height := w - Panel1.Width;
}
t := 0;
// The Paintbox has not yet been scaled here, the bmp will be too small on a high-dpi screen!
// bmp := TBGRABitmap.Create(PaintBox1.Width, PaintBox1.Height, BGRABlack);
Timer1.Interval := 16; // ~60 FPS
Timer1.Enabled := True;
trkSpeedAdjust.Max := 100;
trkSpeedAdjust.Position := 8; // default speed
FActivated := false; // a boolean variable in TForm1
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
if not FActivated then
begin
FActivated := true;
// LCLScaling has been completed here --> the bitmap can get its correct size.
bmp := TBGRABitmap.Create(PaintBox1.Width, PaintBox1.Height, BGRABlack);
end;
end;
This solution, although simple, has a disadvantage: When you have two monitors with different resolutions and drag the form over to the other monitor with the different ppi LCLScaling will change the size of the paintbox but your buffer bitmap will not notice it and remain at its old size - you will either have a non-centered waterfall or the image will not cover the entire paintbox.
There is a procedure AutoAdjustLayout which is called whenever the monitor ppi changes. This is a rather general procedure, the usual way for user-defined scaling is to override the DoAutoAdjustLayout method which is called from there for each control. Since the Paintbox has been already scaled by the ancestor method simple reset the size of the buffer bitmap here:
procedure TForm1.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
const AXProportion, AYProportion: Double);
begin
inherited;
// The PaintBox has already been resized (by "inherited") - we must update the size of the buffer bitmap
bmp.SetSize(Paintbox1.Width, Paintbox1.Height);
end;
Since the AutoAdjustLayout mechanism is triggered also at program start in case of different resolutions, you can keep creation of the bitmap in the OnCreate handler.
I moved the variable w (which is the Paintbox.Width, isn't it?) into the Paintbox.OnPaint handler so that is requires no extra handling. If you don't want that, update w whenever you change the bmp size.
In the screenshots of the modified demo, taken at 96 ppi and 144 ppi, you can see that there are more cascades of the waterfall at the higher resolution. This is because your drawing code uses unscaled numbers in the OnPaint handler. It's a bit tricky to find out the relevant numbers in this specific project- I did not go into this detail. Call Scale96ToForm for the number that you want to scale from 96ppi to the current ppi.