Заработало !
(Слегка медленней и волны более широкие но в целом похоже )

deepseek с HiAsm знаком но писать полный код аналог не стал (лениво ему

)
Ну ладно скормил ему исходник WaveProcessor-а и запросили "перевод с паскаля на паскаль" ( то бишь потребовал написать адаптацию для Лазаруса)
Сделал, просил демку написал и её ... Но что-то не то ...
Приведенная в начале этого диалога демка на Hiasm могла генерировать несколько волн параллельно (с разными начальными точкам ) может ли это делать класс TWaveProcessor ? Если нет то как этого добиться ?
Дип Сек извинился и переписал демку ...
Все ок ... (добавил {$mode delphi} код скомпилировался ) но ничего не работает...
начал копать код вначале уперся в PaintBox ( видимо забыл какие-то тонкости потому что мой старый проект с PaintBox успешно собрался и заработал ) (Заменил PaintBox на TImage) Дальше уперся в то что deepseek не вник в отличия KOL и VCL , ладно приписал способ адресации все равно не работает (хотя ошибок не выдает ) ...
Потом вспомнил что FWaveProcessor.Process(FImage, FBitmap); вызывается еще и в обработчике таймера
"Закавычил" и его .
- Код: Выделить всё
fbitmap.BeginUpdate;
FWaveProcessor.Process(FImage, FBitmap);
fbitmap.EndUpdate;
И тут все наконец завертелось .
Добавлено спустя 54 минуты 37 секунд:Модифицированный WaveProcessorUnit
- Код: Выделить всё
unit WaveProcessorUnit;
{$mode delphi}{$H+}
interface
uses
Classes, SysUtils, Graphics, LCLType, Math;
type
TWave = record
Height: Double;
Speed: Double;
end;
TByteArray = array of Byte;
PByteArray = ^TByteArray;
{ TWaveProcessor }
TWaveProcessor = class
private
FBitmapWidth: Integer;
FBitmapHeight: Integer;
FBackgroundLines: array of PByteArray;
FBitmapLines: array of PByteArray;
FHalfResolution: Boolean;
FImage, FBitmap: TBitmap;
FWaves: array of array of TWave;
FLightIntensity: Double; // Интенсивность эффекта света
FDepth: Double; // Глубина воды для псевдо-рефракции
FViscosity: Double; // Псевдо-вязкость для анимации
FWavesSpeed: Double; // Параметр для скорости волн (должен быть не менее 2.0)
FLastT: Integer;
FFPSCount: Integer;
procedure Init;
procedure InitWavesArray;
procedure InitWavesData;
procedure InitBackgroundLines;
procedure InitBitmapLines;
procedure Simulate;
procedure SimulateEdges;
procedure Ripple(CenterX, CenterY, Radius: Integer; Height: Double);
procedure Render;
procedure Idle;
public
constructor Create;
destructor Destroy; override;
procedure Process(Image, Bitmap: TBitmap);
procedure MakeRipple(X, Y, Radius: Integer; Height: Double);
property Viscosity: Double read FViscosity write FViscosity;
property WavesSpeed: Double read FWavesSpeed write FWavesSpeed;
property LightIntensity: Double read FLightIntensity write FLightIntensity;
property Depth: Double read FDepth write FDepth;
end;
implementation
{ TWaveProcessor }
constructor TWaveProcessor.Create;
begin
inherited Create;
FImage := TBitmap.Create;
FBitmap := TBitmap.Create;
end;
destructor TWaveProcessor.Destroy;
begin
FImage.Free;
FBitmap.Free;
inherited Destroy;
end;
procedure TWaveProcessor.Init;
begin
FHalfResolution := False;
FBitmapWidth := FImage.Width;
FBitmapHeight := FImage.Height;
FLightIntensity := 300;
FWavesSpeed := 2.0;
FViscosity := 0.02;
FDepth := 47.3;
InitBitmapLines;
InitBackgroundLines;
InitWavesArray;
InitWavesData;
end;
procedure TWaveProcessor.InitWavesArray;
var
X: Integer;
begin
SetLength(FWaves, FBitmapWidth + 1);
for X := 0 to FBitmapWidth do
SetLength(FWaves[X], FBitmapHeight + 1);
end;
procedure TWaveProcessor.InitWavesData;
var
X, Y: Integer;
begin
for X := 0 to FBitmapWidth do
for Y := 0 to FBitmapHeight do
begin
FWaves[X, Y].Height := 0.0;
FWaves[X, Y].Speed := 0.0;
end;
end;
procedure TWaveProcessor.InitBackgroundLines;
var
I: Integer;
begin
FBitmap.PixelFormat := pf24bit;
// SetLength(FBackgroundLines, FBitmap.Height);
// for I := 0 to FBitmap.Height - 1 do
// FBackgroundLines[I] := FBitmap.ScanLine[I];
end;
procedure TWaveProcessor.InitBitmapLines;
var
I: Integer;
begin
FImage.PixelFormat := pf24bit;
// SetLength(FBitmapLines, FBitmapHeight);
// for I := 0 to FBitmapHeight - 1 do
// FBitmapLines[I] := FImage.ScanLine[I];
end;
procedure TWaveProcessor.Simulate;
var
X, Y: Integer;
D1, D2, Ddx, Ddy, Viscosity1: Double;
begin
for X := 1 to FBitmapWidth - 1 do
for Y := 1 to FBitmapHeight - 1 do
begin
D1 := FWaves[X + 1, Y].Height - FWaves[X, Y].Height;
D2 := FWaves[X, Y].Height - FWaves[X - 1, Y].Height;
Ddx := D1 - D2;
D1 := FWaves[X, Y + 1].Height - FWaves[X, Y].Height;
D2 := FWaves[X, Y].Height - FWaves[X, Y - 1].Height;
Ddy := D1 - D2;
FWaves[X, Y].Speed := FWaves[X, Y].Speed + Ddx / FWavesSpeed + Ddy / FWavesSpeed;
end;
Viscosity1 := 1.0 - FViscosity;
for X := 1 to FBitmapWidth - 1 do
for Y := 1 to FBitmapHeight - 1 do
FWaves[X, Y].Height := (FWaves[X, Y].Height + FWaves[X, Y].Speed) * Viscosity1;
end;
procedure TWaveProcessor.SimulateEdges;
var
X: Integer;
begin
for X := 1 to FBitmapWidth - 1 do
begin
FWaves[X, 0] := FWaves[X, 1];
FWaves[X, FBitmapHeight] := FWaves[X, FBitmapHeight - 1];
end;
for X := 0 to FBitmapHeight do
begin
FWaves[0, X] := FWaves[1, X];
FWaves[FBitmapWidth, X] := FWaves[FBitmapWidth - 1, X];
end;
end;
procedure TWaveProcessor.Ripple(CenterX, CenterY, Radius: Integer; Height: Double);
var
X, Y: Integer;
begin
for X := (CenterX - Radius) to (CenterX + Radius - 1) do
begin
if (X >= 0) and (X <= FBitmapWidth) then
for Y := (CenterY - Radius) to (CenterY + Radius - 1) do
begin
if (Y >= 0) and (Y <= FBitmapHeight) then
FWaves[X, Y].Height := FWaves[X, Y].Height + ((Cos((X - CenterX + Radius) / (2 * Radius) * 2 * PI - PI) + 1) * (Cos((Y - CenterY + Radius) / (2 * Radius) * 2 * PI - PI) + 1) * Height);
end;
end;
end;
procedure TWaveProcessor.Render;
var
I, X, Y: Integer;
Background, Buffer: PByteArray;
Dx, Dy: Double;
Light, XMap, YMap: Integer;
P1,P2:Pointer;
begin
for Y := 0 to FBitmapHeight - 1 do
begin
for X := 0 to FBitmapWidth - 1 do
begin
Dx := FWaves[X + 1, Y].Height - FWaves[X, Y].Height;
Dy := FWaves[X, Y + 1].Height - FWaves[X, Y].Height;
XMap := X + Round(Dx * (FWaves[X, Y].Height + FDepth));
YMap := Y + Round(Dy * (FWaves[X, Y].Height + FDepth));
if FHalfResolution then
begin
XMap := XMap * 2;
YMap := YMap * 2;
end;
Light := Round(Dx * FLightIntensity + Dy * FLightIntensity);
if XMap >= 0 then
XMap := XMap mod FBitmap.Width
else
XMap := FBitmap.Width - ((-XMap) mod FBitmap.Width) - 1;
if YMap >= 0 then
YMap := YMap mod FBitmap.Height
else
YMap := FBitmap.Height - ((-YMap) mod FBitmap.Height) - 1;
P2:=FBitmap.RawImage.Data;
P2:=P2+(FBitmap.Width*Y*3)+X * 3 ;
P1:=FImage.RawImage.Data;
P1:=P1+(FBitmap.Width*Y*3)+X * 3 ;
for I:=0 to 2 do begin Inc (P1,I);Inc (P2,I);
Byte(P2^):=Min(255, Max(0, Byte(P1^)+ Light));
end;
//FBitmapLines[Y][X * 3 + 0] := Min(255, Max(0, FBackgroundLines[YMap][XMap * 3 + 0] + Light));
//FBitmapLines[Y][X * 3 + 1] := Min(255, Max(0, FBackgroundLines[YMap][XMap * 3 + 1] + Light));
//FBitmapLines[Y][X * 3 + 2] := Min(255, Max(0, FBackgroundLines[YMap][XMap * 3 + 2] + Light));
end;
end;
end;
procedure TWaveProcessor.Idle;
begin
SimulateEdges;
Simulate;
Render;
end;
procedure TWaveProcessor.Process(Image, Bitmap: TBitmap);
begin
if FImage <> Image then
begin
FImage := Image;
FBitmap := Bitmap;
Init;
end;
InitBackgroundLines;
Idle;
end;
procedure TWaveProcessor.MakeRipple(X, Y, Radius: Integer; Height: Double);
begin
Ripple(X, Y, Radius, Height);
end;
end.
Демка
- Код: Выделить всё
unit MainFormUnit;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, WaveProcessorUnit;
type
{ TMainForm }
TMainForm = class(TForm)
Image1: TImage;
Timer: TTimer;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure TimerTimer(Sender: TObject);
private
FImage: TBitmap;
FBitmap: TBitmap;
FWaveProcessor: TWaveProcessor;
procedure GenerateRandomRipple; // Метод для генерации случайной волны
public
end;
var
MainForm: TMainForm;
implementation
{$R *.lfm}
{ TMainForm }
procedure TMainForm.FormCreate(Sender: TObject);
begin
// Загрузка изображения
Image1.Picture.LoadFromFile('background.bmp');
FImage := TBitmap.Create;
FImage.SetSize(Image1.Picture.Bitmap.Width, Image1.Picture.Bitmap.Height);
FImage.PixelFormat:=pf24bit;
FImage.Canvas.Draw(0,0,Image1.Picture.Bitmap);
// Создание битмапа для отрисовки
FBitmap := TBitmap.Create;
FBitmap. PixelFormat:=pf24bit;
FBitmap.SetSize(FImage.Width, FImage.Height);
// Инициализация WaveProcessor
FWaveProcessor := TWaveProcessor.Create;
fbitmap.BeginUpdate;
FWaveProcessor.Process(FImage, FBitmap);
fbitmap.EndUpdate;
// Настройка таймера
Timer.Interval := 16; // ~60 FPS
Timer.Enabled := True;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
// Освобождение ресурсов
FWaveProcessor.Free;
FBitmap.Free;
FImage.Free;
end;
procedure TMainForm.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
// Создание волны при клике мышью
FWaveProcessor.MakeRipple(X, Y, 20, 10.0); // Радиус 20, высота волны 10.0
end;
procedure TMainForm.TimerTimer(Sender: TObject);
begin
// Генерация случайной волны каждые 500 мс
if Random(100) < 10 then // 10% вероятность генерации волны
GenerateRandomRipple;
// Обработка волнового эффекта
fbitmap.BeginUpdate;
FWaveProcessor.Process(FImage, FBitmap);
fbitmap.EndUpdate;
// Отрисовка результата на PaintBox
Image1.Picture.Bitmap.Canvas.Draw(0, 0, FBitmap);
end;
procedure TMainForm.GenerateRandomRipple;
var
X, Y: Integer;
begin
// Генерация случайных координат для волны
X := Random(FBitmap.Width);
Y := Random(FBitmap.Height);
// Создание волны
FWaveProcessor.MakeRipple(X, Y, 20 + Random(30), 5.0 + Random(10));
end;
end.