소스 검색

add wave displacement filter

Johann 6 년 전
부모
커밋
e903f86275

+ 58 - 39
lazpaint/dialog/filter/utwirl.lfm

@@ -1,8 +1,8 @@
 object FTwirl: TFTwirl
 object FTwirl: TFTwirl
   Left = 631
   Left = 631
-  Height = 217
+  Height = 288
   Top = 173
   Top = 173
-  Width = 148
+  Width = 173
   AutoSize = True
   AutoSize = True
   BorderIcons = [biSystemMenu]
   BorderIcons = [biSystemMenu]
   BorderStyle = bsDialog
   BorderStyle = bsDialog
@@ -13,113 +13,132 @@ object FTwirl: TFTwirl
   ChildSizing.VerticalSpacing = 8
   ChildSizing.VerticalSpacing = 8
   ChildSizing.Layout = cclLeftToRightThenTopToBottom
   ChildSizing.Layout = cclLeftToRightThenTopToBottom
   ChildSizing.ControlsPerLine = 1
   ChildSizing.ControlsPerLine = 1
-  ClientHeight = 217
-  ClientWidth = 148
-  Font.Height = -12
+  ClientHeight = 288
+  ClientWidth = 173
+  DesignTimePPI = 120
+  Font.Height = -15
   OnCreate = FormCreate
   OnCreate = FormCreate
   OnDestroy = FormDestroy
   OnDestroy = FormDestroy
   OnShow = FormShow
   OnShow = FormShow
   Position = poScreenCenter
   Position = poScreenCenter
-  LCLVersion = '1.6.0.4'
+  LCLVersion = '2.0.2.0'
   object Panel1: TPanel
   object Panel1: TPanel
     Left = 8
     Left = 8
-    Height = 54
+    Height = 76
     Top = 8
     Top = 8
-    Width = 114
+    Width = 143
     BevelOuter = bvNone
     BevelOuter = bvNone
     ChildSizing.HorizontalSpacing = 8
     ChildSizing.HorizontalSpacing = 8
     ChildSizing.VerticalSpacing = 8
     ChildSizing.VerticalSpacing = 8
     ChildSizing.Layout = cclLeftToRightThenTopToBottom
     ChildSizing.Layout = cclLeftToRightThenTopToBottom
     ChildSizing.ControlsPerLine = 2
     ChildSizing.ControlsPerLine = 2
-    ClientHeight = 54
-    ClientWidth = 114
+    ClientHeight = 76
+    ClientWidth = 143
+    Font.Height = -15
+    ParentFont = False
     TabOrder = 0
     TabOrder = 0
     object Label_Radius: TLabel
     object Label_Radius: TLabel
       Left = 0
       Left = 0
-      Height = 23
+      Height = 34
       Top = 0
       Top = 0
-      Width = 41
+      Width = 54
       Caption = 'Radius :'
       Caption = 'Radius :'
+      Font.Height = -15
       Layout = tlCenter
       Layout = tlCenter
       ParentColor = False
       ParentColor = False
+      ParentFont = False
     end
     end
     object SpinEdit_Radius: TSpinEdit
     object SpinEdit_Radius: TSpinEdit
-      Left = 49
-      Height = 23
+      Left = 62
+      Height = 34
       Top = 0
       Top = 0
-      Width = 65
-      Constraints.MinWidth = 65
+      Width = 81
+      Constraints.MinWidth = 81
+      Font.Height = -15
       Increment = 10
       Increment = 10
       MaxValue = 10000
       MaxValue = 10000
       MinValue = 1
       MinValue = 1
       OnChange = SpinEdit_RadiusChange
       OnChange = SpinEdit_RadiusChange
+      ParentFont = False
       TabOrder = 0
       TabOrder = 0
       Value = 100
       Value = 100
     end
     end
     object Label_Angle: TLabel
     object Label_Angle: TLabel
       Left = 0
       Left = 0
-      Height = 23
-      Top = 31
-      Width = 41
+      Height = 34
+      Top = 42
+      Width = 54
       Caption = 'Angle :'
       Caption = 'Angle :'
+      Font.Height = -15
       Layout = tlCenter
       Layout = tlCenter
       ParentColor = False
       ParentColor = False
+      ParentFont = False
     end
     end
     object SpinEdit_Angle: TSpinEdit
     object SpinEdit_Angle: TSpinEdit
-      Left = 49
-      Height = 23
-      Top = 31
-      Width = 65
-      Constraints.MinWidth = 65
+      Left = 62
+      Height = 34
+      Top = 42
+      Width = 81
+      Constraints.MinWidth = 81
+      Font.Height = -15
       Increment = 30
       Increment = 30
       MaxValue = 10000
       MaxValue = 10000
       MinValue = 1
       MinValue = 1
       OnChange = SpinEdit_AngleChange
       OnChange = SpinEdit_AngleChange
+      ParentFont = False
       TabOrder = 1
       TabOrder = 1
       Value = 360
       Value = 360
     end
     end
   end
   end
   object PaintBox1: TPaintBox
   object PaintBox1: TPaintBox
     Left = 8
     Left = 8
-    Height = 105
-    Top = 70
-    Width = 114
+    Height = 131
+    Top = 92
+    Width = 143
+    Font.Height = -15
+    ParentFont = False
     OnMouseDown = PaintBox1MouseDown
     OnMouseDown = PaintBox1MouseDown
     OnMouseMove = PaintBox1MouseMove
     OnMouseMove = PaintBox1MouseMove
     OnPaint = PaintBox1Paint
     OnPaint = PaintBox1Paint
   end
   end
   object Panel2: TPanel
   object Panel2: TPanel
     Left = 8
     Left = 8
-    Height = 25
-    Top = 183
-    Width = 114
+    Height = 36
+    Top = 231
+    Width = 143
     BevelOuter = bvNone
     BevelOuter = bvNone
     ChildSizing.HorizontalSpacing = 8
     ChildSizing.HorizontalSpacing = 8
     ChildSizing.Layout = cclLeftToRightThenTopToBottom
     ChildSizing.Layout = cclLeftToRightThenTopToBottom
     ChildSizing.ControlsPerLine = 2
     ChildSizing.ControlsPerLine = 2
-    ClientHeight = 25
-    ClientWidth = 114
+    ClientHeight = 36
+    ClientWidth = 143
+    Font.Height = -15
+    ParentFont = False
     TabOrder = 1
     TabOrder = 1
     object Button_OK: TButton
     object Button_OK: TButton
       Left = 0
       Left = 0
-      Height = 25
+      Height = 36
       Top = 0
       Top = 0
-      Width = 42
+      Width = 35
       AutoSize = True
       AutoSize = True
       Caption = 'OK'
       Caption = 'OK'
       Default = True
       Default = True
+      Font.Height = -15
       OnClick = Button_OKClick
       OnClick = Button_OKClick
+      ParentFont = False
       TabOrder = 0
       TabOrder = 0
     end
     end
     object Button_Cancel: TButton
     object Button_Cancel: TButton
-      Left = 50
-      Height = 25
+      Left = 43
+      Height = 36
       Top = 0
       Top = 0
-      Width = 62
+      Width = 59
       AutoSize = True
       AutoSize = True
       Cancel = True
       Cancel = True
       Caption = 'Cancel'
       Caption = 'Cancel'
+      Font.Height = -15
       ModalResult = 2
       ModalResult = 2
+      ParentFont = False
       TabOrder = 1
       TabOrder = 1
     end
     end
   end
   end
@@ -127,7 +146,7 @@ object FTwirl: TFTwirl
     Enabled = False
     Enabled = False
     Interval = 200
     Interval = 200
     OnTimer = Timer1Timer
     OnTimer = Timer1Timer
-    left = 40
-    top = 8
+    left = 64
+    top = 120
   end
   end
 end
 end

+ 1 - 1
lazpaint/dialog/filter/utwirl.pas

@@ -92,7 +92,7 @@ begin
   SpinEdit_Angle.Value := round(FilterConnector.LazPaintInstance.Config.DefaultTwirlTurn*360);
   SpinEdit_Angle.Value := round(FilterConnector.LazPaintInstance.Config.DefaultTwirlTurn*360);
   FInitializing := false;
   FInitializing := false;
   PreviewNeeded;
   PreviewNeeded;
-  Left := FilterConnector.LazPaintInstance.MainFormBounds.Left
+  Left := FilterConnector.LazPaintInstance.MainFormBounds.Left;
 end;
 end;
 
 
 procedure TFTwirl.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
 procedure TFTwirl.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;

+ 174 - 0
lazpaint/dialog/filter/uwavedisplacement.lfm

@@ -0,0 +1,174 @@
+object FWaveDisplacement: TFWaveDisplacement
+  Left = 306
+  Height = 356
+  Top = 172
+  Width = 222
+  AutoSize = True
+  BorderIcons = [biSystemMenu]
+  BorderStyle = bsDialog
+  Caption = 'Wave displacement'
+  ChildSizing.LeftRightSpacing = 8
+  ChildSizing.TopBottomSpacing = 8
+  ChildSizing.HorizontalSpacing = 8
+  ChildSizing.VerticalSpacing = 8
+  ChildSizing.Layout = cclLeftToRightThenTopToBottom
+  ChildSizing.ControlsPerLine = 1
+  ClientHeight = 356
+  ClientWidth = 222
+  DesignTimePPI = 120
+  OnCreate = FormCreate
+  OnShow = FormShow
+  Position = poScreenCenter
+  LCLVersion = '2.0.2.0'
+  object Panel1: TPanel
+    Left = 8
+    Height = 118
+    Top = 8
+    Width = 191
+    AutoSize = True
+    BevelOuter = bvNone
+    ChildSizing.HorizontalSpacing = 8
+    ChildSizing.VerticalSpacing = 8
+    ChildSizing.Layout = cclLeftToRightThenTopToBottom
+    ChildSizing.ControlsPerLine = 2
+    ClientHeight = 118
+    ClientWidth = 191
+    Font.Height = -15
+    ParentFont = False
+    TabOrder = 0
+    object Label_Wavelength: TLabel
+      Left = 0
+      Height = 34
+      Top = 0
+      Width = 102
+      Caption = 'Wavelength :'
+      Font.Height = -15
+      Layout = tlCenter
+      ParentColor = False
+      ParentFont = False
+    end
+    object SpinEdit_Wavelength: TSpinEdit
+      Left = 110
+      Height = 34
+      Top = 0
+      Width = 81
+      Constraints.MinWidth = 81
+      Font.Height = -15
+      Increment = 10
+      MaxValue = 10000
+      MinValue = 1
+      OnChange = SpinEdit_WavelengthChange
+      ParentFont = False
+      TabOrder = 0
+      Value = 100
+    end
+    object Label_Displacement: TLabel
+      Left = 0
+      Height = 34
+      Top = 42
+      Width = 102
+      Caption = 'Displacement :'
+      Font.Height = -15
+      Layout = tlCenter
+      ParentColor = False
+      ParentFont = False
+    end
+    object SpinEdit_Displacement: TSpinEdit
+      Left = 110
+      Height = 34
+      Top = 42
+      Width = 81
+      Constraints.MinWidth = 81
+      Font.Height = -15
+      Increment = 5
+      MaxValue = 1000
+      OnChange = SpinEdit_DisplacementChange
+      ParentFont = False
+      TabOrder = 1
+      Value = 50
+    end
+    object Label_Phase: TLabel
+      Left = 0
+      Height = 34
+      Top = 84
+      Width = 102
+      Caption = 'Phase :'
+      Font.Height = -15
+      Layout = tlCenter
+      ParentColor = False
+      ParentFont = False
+    end
+    object SpinEdit_Phase: TSpinEdit
+      Left = 110
+      Height = 34
+      Top = 84
+      Width = 81
+      Constraints.MinWidth = 81
+      Font.Height = -15
+      Increment = 30
+      MaxValue = 360
+      OnChange = SpinEdit_PhaseChange
+      ParentFont = False
+      TabOrder = 2
+    end
+  end
+  object PaintBox1: TPaintBox
+    Left = 9
+    Height = 160
+    Top = 136
+    Width = 189
+    Font.Height = -15
+    ParentFont = False
+    OnMouseDown = PaintBox1MouseDown
+    OnMouseMove = PaintBox1MouseMove
+    OnPaint = PaintBox1Paint
+  end
+  object Panel2: TPanel
+    Left = 9
+    Height = 36
+    Top = 304
+    Width = 188
+    BevelOuter = bvNone
+    ChildSizing.HorizontalSpacing = 8
+    ChildSizing.Layout = cclLeftToRightThenTopToBottom
+    ChildSizing.ControlsPerLine = 2
+    ClientHeight = 36
+    ClientWidth = 188
+    Font.Height = -15
+    ParentFont = False
+    TabOrder = 1
+    object Button_OK: TButton
+      Left = 0
+      Height = 36
+      Top = 0
+      Width = 35
+      AutoSize = True
+      Caption = 'OK'
+      Default = True
+      Font.Height = -15
+      OnClick = Button_OKClick
+      ParentFont = False
+      TabOrder = 0
+    end
+    object Button_Cancel: TButton
+      Left = 43
+      Height = 36
+      Top = 0
+      Width = 59
+      AutoSize = True
+      Cancel = True
+      Caption = 'Cancel'
+      Font.Height = -15
+      ModalResult = 2
+      ParentFont = False
+      TabOrder = 1
+    end
+  end
+  object Timer1: TTimer
+    Enabled = False
+    Interval = 200
+    OnTimer = Timer1Timer
+    left = 48
+    top = 184
+  end
+end

+ 183 - 0
lazpaint/dialog/filter/uwavedisplacement.pas

@@ -0,0 +1,183 @@
+unit UWaveDisplacement;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
+  Spin, UFilterConnector, BGRABitmap, BGRABitmapTypes, LazPaintType;
+
+type
+
+  { TFWaveDisplacement }
+
+  TFWaveDisplacement = class(TForm)
+    Button_Cancel: TButton;
+    Button_OK: TButton;
+    Label_Displacement: TLabel;
+    Label_Phase: TLabel;
+    Label_Wavelength: TLabel;
+    PaintBox1: TPaintBox;
+    Panel1: TPanel;
+    Panel2: TPanel;
+    SpinEdit_Displacement: TSpinEdit;
+    SpinEdit_Phase: TSpinEdit;
+    SpinEdit_Wavelength: TSpinEdit;
+    Timer1: TTimer;
+    procedure Button_OKClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure FormShow(Sender: TObject);
+    procedure PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
+      Shift: TShiftState; X, Y: Integer);
+    procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
+      Y: Integer);
+    procedure PaintBox1Paint(Sender: TObject);
+    procedure SpinEdit_DisplacementChange(Sender: TObject);
+    procedure SpinEdit_PhaseChange(Sender: TObject);
+    procedure SpinEdit_WavelengthChange(Sender: TObject);
+    procedure Timer1Timer(Sender: TObject);
+  private
+    { private declarations }
+    FInitializing: boolean;
+    FCenter: TPointF;
+    procedure PreviewNeeded;
+    function ComputeFilteredLayer: TBGRABitmap;
+  public
+    FilterConnector: TFilterConnector;
+  end;
+
+var
+  FWaveDisplacement: TFWaveDisplacement;
+
+function ShowWaveDisplacementDlg(AFilterConnector: TObject):boolean;
+
+implementation
+
+uses umac, ugraph, LCScaleDPI;
+
+function ShowWaveDisplacementDlg(AFilterConnector: TObject):boolean;
+var
+  FWaveDisplacement: TFWaveDisplacement;
+begin
+  result := false;
+  FWaveDisplacement:= TFWaveDisplacement.create(nil);
+  FWaveDisplacement.FilterConnector := AFilterConnector as TFilterConnector;
+  try
+    if FWaveDisplacement.FilterConnector.ActiveLayer <> nil then
+      result:= (FWaveDisplacement.showModal = mrOk)
+    else
+      result := false;
+  finally
+    FWaveDisplacement.free;
+  end;
+end;
+
+{ TFWaveDisplacement }
+
+procedure TFWaveDisplacement.FormCreate(Sender: TObject);
+begin
+  ScaleControl(Self,OriginalDPI);
+
+  CheckSpinEdit(SpinEdit_Wavelength);
+  CheckSpinEdit(SpinEdit_Displacement);
+  CheckSpinEdit(SpinEdit_Phase);
+  CheckOKCancelBtns(Button_OK{,Button_Cancel});
+
+  FCenter := PointF(0.5,0.5);
+end;
+
+procedure TFWaveDisplacement.FormShow(Sender: TObject);
+begin
+  FInitializing:= true;
+  SpinEdit_Wavelength.Value := round(FilterConnector.LazPaintInstance.Config.DefaultWaveDisplacementWavelength);
+  SpinEdit_Displacement.Value := round(FilterConnector.LazPaintInstance.Config.DefaultWaveDisplacementAmount);
+  SpinEdit_Phase.Value := round(FilterConnector.LazPaintInstance.Config.DefaultWaveDisplacementPhase);
+  FInitializing := false;
+  PreviewNeeded;
+  Left := FilterConnector.LazPaintInstance.MainFormBounds.Left;
+end;
+
+procedure TFWaveDisplacement.PaintBox1MouseDown(Sender: TObject; Button: TMouseButton;
+  Shift: TShiftState; X, Y: Integer);
+begin
+  FCenter := PointF(X/PaintBox1.Width,Y/PaintBox1.Height);
+  PaintBox1.Invalidate;
+  PreviewNeeded;
+end;
+
+procedure TFWaveDisplacement.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
+  Y: Integer);
+begin
+  if ssLeft in Shift then
+  begin
+    FCenter := PointF(X/PaintBox1.Width,Y/PaintBox1.Height);
+    PaintBox1.Invalidate;
+    PreviewNeeded;
+  end;
+end;
+
+procedure TFWaveDisplacement.PaintBox1Paint(Sender: TObject);
+var x,y: integer;
+begin
+  x := round(FCenter.X*PaintBox1.Width);
+  y := round(FCenter.Y*PaintBox1.Height);
+  PaintBox1.Canvas.Brush.Style := bsClear;
+  PaintBox1.Canvas.Pen.Style := psSolid;
+  PaintBox1.Canvas.Pen.Color := clWindowText;
+  PaintBox1.Canvas.Rectangle(0,0,PaintBox1.Width,PaintBox1.Height);
+  PaintBox1.Canvas.Pen.Color := clBlack;
+  PaintBox1.Canvas.Brush.Style := bsSolid;
+  PaintBox1.Canvas.Brush.Color := clWhite;
+  PaintBox1.Canvas.Ellipse(x-3,y-3,x+4,y+4);
+end;
+
+procedure TFWaveDisplacement.SpinEdit_WavelengthChange(Sender: TObject);
+begin
+  if not FInitializing then PreviewNeeded;
+end;
+
+procedure TFWaveDisplacement.SpinEdit_DisplacementChange(Sender: TObject);
+begin
+  if not FInitializing then PreviewNeeded;
+end;
+
+procedure TFWaveDisplacement.SpinEdit_PhaseChange(Sender: TObject);
+begin
+  if not FInitializing then PreviewNeeded;
+end;
+
+procedure TFWaveDisplacement.Timer1Timer(Sender: TObject);
+begin
+  Timer1.Enabled := false;
+  FilterConnector.PutImage(ComputeFilteredLayer,False,true);
+  Button_OK.Enabled := true;
+end;
+
+procedure TFWaveDisplacement.PreviewNeeded;
+begin
+  Timer1.Enabled := false;
+  Timer1.Enabled := True;
+  Button_OK.Enabled := false;
+end;
+
+function TFWaveDisplacement.ComputeFilteredLayer: TBGRABitmap;
+begin
+  result := ugraph.WaveDisplacementFilter(FilterConnector.BackupLayer,FilterConnector.WorkArea,
+      PointF(FCenter.X*FilterConnector.ActiveLayer.Width,FCenter.Y*FilterConnector.ActiveLayer.Height),
+      SpinEdit_Wavelength.Value,SpinEdit_Displacement.Value,SpinEdit_Phase.Value) as TBGRABitmap;
+end;
+
+procedure TFWaveDisplacement.Button_OKClick(Sender: TObject);
+begin
+  FilterConnector.ValidateAction;
+  FilterConnector.LazPaintInstance.Config.SetDefaultWaveDisplacementWavelength(SpinEdit_Wavelength.Value);
+  FilterConnector.LazPaintInstance.Config.SetDefaultWaveDisplacementAmount(SpinEdit_Displacement.Value);
+  FilterConnector.LazPaintInstance.Config.SetDefaultWaveDisplacementPhase(SpinEdit_Phase.Value);
+  ModalResult := mrOK;
+end;
+
+{$R *.lfm}
+
+end.
+

+ 10 - 1
lazpaint/lazpaint.lpi

@@ -336,7 +336,7 @@
         <PackageName Value="LCL"/>
         <PackageName Value="LCL"/>
       </Item5>
       </Item5>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="97">
+    <Units Count="98">
       <Unit0>
       <Unit0>
         <Filename Value="lazpaint.lpr"/>
         <Filename Value="lazpaint.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
@@ -907,7 +907,16 @@
       <Unit96>
       <Unit96>
         <Filename Value="udarktheme.pas"/>
         <Filename Value="udarktheme.pas"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
+        <UnitName Value="UDarkTheme"/>
       </Unit96>
       </Unit96>
+      <Unit97>
+        <Filename Value="dialog\filter\uwavedisplacement.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="FWaveDisplacement"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+        <UnitName Value="UWaveDisplacement"/>
+      </Unit97>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>

+ 2 - 2
lazpaint/lazpaint.lpr

@@ -24,7 +24,7 @@ uses
 
 
   //forms
   //forms
   UNewimage, UMultiImage, UBrowseImages, UBlendOp, UCanvassize, UResample, UObject3D,
   UNewimage, UMultiImage, UBrowseImages, UBlendOp, UCanvassize, UResample, UObject3D,
-  URadialBlur, UMotionBlur, UCustomblur, UEmboss, UTwirl, UPixelate,
+  URadialBlur, UMotionBlur, UCustomblur, UEmboss, UTwirl, UWaveDisplacement, UPixelate,
   UColorintensity, UShiftColors, UColorize, USharpen,
   UColorintensity, UShiftColors, UColorize, USharpen,
   UPhongFilter, UFilterFunction,
   UPhongFilter, UFilterFunction,
   UAbout, ULoading,
   UAbout, ULoading,
@@ -37,7 +37,7 @@ uses
   UToolBrush, UMainFormLayout, USaveOption, UBrushType, ugeometricbrush,
   UToolBrush, UMainFormLayout, USaveOption, UBrushType, ugeometricbrush,
   URainType, UFormRain, UPaletteToolbar, uselectionhighlight, UGridBitmap,
   URainType, UFormRain, UPaletteToolbar, uselectionhighlight, UGridBitmap,
   UToolIcon, UImagePreview, UPreviewDialog, UQuestion, UTiff, UImageView,
   UToolIcon, UImagePreview, UPreviewDialog, UQuestion, UTiff, UImageView,
-  udarktheme;
+  UDarkTheme;
 
 
 //sometimes LResources disappear in the uses clause
 //sometimes LResources disappear in the uses clause
 
 

+ 12 - 0
lazpaint/lazpaintdialogs.inc

@@ -396,6 +396,18 @@ begin
   self.ShowTopmost(top);
   self.ShowTopmost(top);
 end;
 end;
 
 
+function TLazPaintInstance.ShowwaveDisplacementDlg(AFilterConnector: TObject): boolean;
+var oldSelectionNormal: boolean;
+    top: TTopMostInfo;
+begin
+  top := self.HideTopmost;
+  oldSelectionNormal := ShowSelectionNormal;
+  ShowSelectionNormal := true;
+  result := UWaveDisplacement.ShowWaveDisplacementDlg(AFilterConnector);
+  ShowSelectionNormal := oldSelectionNormal;
+  self.ShowTopmost(top);
+end;
+
 function TLazPaintInstance.ShowPhongFilterDlg(AFilterConnector: TObject): boolean;
 function TLazPaintInstance.ShowPhongFilterDlg(AFilterConnector: TObject): boolean;
 var oldSelectionNormal: boolean;
 var oldSelectionNormal: boolean;
     top: TTopMostInfo;
     top: TTopMostInfo;

+ 2 - 1
lazpaint/lazpaintinstance.pas

@@ -170,6 +170,7 @@ type
     function ShowPixelateDlg(AFilterConnector: TObject):boolean; override;
     function ShowPixelateDlg(AFilterConnector: TObject):boolean; override;
     function ShowNoiseFilterDlg(AFilterConnector: TObject):boolean; override;
     function ShowNoiseFilterDlg(AFilterConnector: TObject):boolean; override;
     function ShowTwirlDlg(AFilterConnector: TObject):boolean; override;
     function ShowTwirlDlg(AFilterConnector: TObject):boolean; override;
+    function ShowWaveDisplacementDlg(AFilterConnector: TObject):boolean; override;
     function ShowPhongFilterDlg(AFilterConnector: TObject): boolean; override;
     function ShowPhongFilterDlg(AFilterConnector: TObject): boolean; override;
     function ShowFunctionFilterDlg(AFilterConnector: TObject): boolean; override;
     function ShowFunctionFilterDlg(AFilterConnector: TObject): boolean; override;
     function ShowSharpenDlg(AFilterConnector: TObject):boolean; override;
     function ShowSharpenDlg(AFilterConnector: TObject):boolean; override;
@@ -206,7 +207,7 @@ implementation
 
 
 uses LCLType, Types, Forms, Dialogs, FileUtil, LCLIntf, Math,
 uses LCLType, Types, Forms, Dialogs, FileUtil, LCLIntf, Math,
 
 
-     uradialblur, umotionblur, uemboss, utwirl,
+     uradialblur, umotionblur, uemboss, UTwirl, UWaveDisplacement,
      unewimage, uresample, upixelate, unoisefilter, ufilters,
      unewimage, uresample, upixelate, unoisefilter, ufilters,
      UImageAction, USharpen, uposterize, UPhongFilter, UFilterFunction,
      UImageAction, USharpen, uposterize, UPhongFilter, UFilterFunction,
      uprint, USaveOption, UFormRain,
      uprint, USaveOption, UFormRain,

+ 5 - 0
lazpaint/lazpaintmainform.lfm

@@ -6805,6 +6805,11 @@ object FMain: TFMain
       OnExecute = ViewDarkThemeExecute
       OnExecute = ViewDarkThemeExecute
       OnUpdate = ViewDarkThemeUpdate
       OnUpdate = ViewDarkThemeUpdate
     end
     end
+    object FilterWaveDisplacement: TAction
+      Category = 'Filter'
+      Caption = 'Wave diplacement...'
+      OnExecute = FilterAnyExecute
+    end
   end
   end
   object ColorDialog1: TColorDialog
   object ColorDialog1: TColorDialog
     Title = 'Choose color'
     Title = 'Choose color'

+ 1 - 0
lazpaint/lazpaintmainform.pas

@@ -28,6 +28,7 @@ type
   { TFMain }
   { TFMain }
 
 
   TFMain = class(TForm)
   TFMain = class(TForm)
+    FilterWaveDisplacement: TAction;
     ViewDarkTheme: TAction;
     ViewDarkTheme: TAction;
     MenuFileToolbar: TMenuItem;
     MenuFileToolbar: TMenuItem;
     ViewWorkspaceColor: TAction;
     ViewWorkspaceColor: TAction;

+ 4 - 3
lazpaint/lazpainttype.pas

@@ -76,7 +76,7 @@ type
                     pfBlurPrecise, pfBlurRadial, pfBlurFast, pfBlurBox, pfBlurCorona, pfBlurDisk, pfBlurMotion, pfBlurCustom,
                     pfBlurPrecise, pfBlurRadial, pfBlurFast, pfBlurBox, pfBlurCorona, pfBlurDisk, pfBlurMotion, pfBlurCustom,
                     pfSharpen, pfSmooth, pfMedian, pfNoise, pfPixelate, pfClearType, pfClearTypeInverse, pfFunction,
                     pfSharpen, pfSmooth, pfMedian, pfNoise, pfPixelate, pfClearType, pfClearTypeInverse, pfFunction,
                     pfEmboss, pfPhong, pfContour, pfGrayscale, pfNegative, pfLinearNegative, pfComplementaryColor, pfNormalize,
                     pfEmboss, pfPhong, pfContour, pfGrayscale, pfNegative, pfLinearNegative, pfComplementaryColor, pfNormalize,
-                    pfSphere, pfTwirl, pfCylinder, pfPlane,
+                    pfSphere, pfTwirl, pfWaveDisplacement, pfCylinder, pfPlane,
                     pfPerlinNoise,pfCyclicPerlinNoise,pfClouds,pfCustomWater,pfWater,pfRain,pfWood,pfWoodVertical,pfPlastik,pfMetalFloor,pfCamouflage,
                     pfPerlinNoise,pfCyclicPerlinNoise,pfClouds,pfCustomWater,pfWater,pfRain,pfWood,pfWoodVertical,pfPlastik,pfMetalFloor,pfCamouflage,
                     pfSnowPrint,pfStone,pfRoundStone,pfMarble);
                     pfSnowPrint,pfStone,pfRoundStone,pfMarble);
 
 
@@ -86,7 +86,7 @@ const
                     'BlurPrecise', 'BlurRadial', 'BlurFast', 'BlurBox', 'BlurCorona', 'BlurDisk', 'BlurMotion', 'BlurCustom',
                     'BlurPrecise', 'BlurRadial', 'BlurFast', 'BlurBox', 'BlurCorona', 'BlurDisk', 'BlurMotion', 'BlurCustom',
                     'Sharpen', 'Smooth', 'Median', 'Noise', 'Pixelate', 'ClearType', 'ClearTypeInverse', 'Function',
                     'Sharpen', 'Smooth', 'Median', 'Noise', 'Pixelate', 'ClearType', 'ClearTypeInverse', 'Function',
                     'Emboss', 'Phong', 'Contour', 'Grayscale', 'Negative', 'LinearNegative', 'ComplementaryColor', 'Normalize',
                     'Emboss', 'Phong', 'Contour', 'Grayscale', 'Negative', 'LinearNegative', 'ComplementaryColor', 'Normalize',
-                    'Sphere', 'Twirl', 'Cylinder', 'Plane',
+                    'Sphere', 'Twirl', 'WaveDisplacement', 'Cylinder', 'Plane',
                     'PerlinNoise','CyclicPerlinNoise','Clouds','CustomWater','Water','Rain','Wood','WoodVertical','Plastik','MetalFloor','Camouflage',
                     'PerlinNoise','CyclicPerlinNoise','Clouds','CustomWater','Water','Rain','Wood','WoodVertical','Plastik','MetalFloor','Camouflage',
                     'SnowPrint','Stone','RoundStone','Marble');
                     'SnowPrint','Stone','RoundStone','Marble');
 
 
@@ -95,7 +95,7 @@ const
                     false, false, false, false, false, false, false, false,
                     false, false, false, false, false, false, false, false,
                     false, false, false, false, false, true, true, true,
                     false, false, false, false, false, true, true, true,
                     false, true, false, false, false, false, false, false,
                     false, true, false, false, false, false, false, false,
-                    false, false, false, false,
+                    false, false, false, false, false,
                     false,false,true,true,true,true,true,true,true,true,true,
                     false,false,true,true,true,true,true,true,true,true,true,
                     true,true,true,true);
                     true,true,true,true);
 
 
@@ -255,6 +255,7 @@ type
     function ShowPixelateDlg(AFilterConnector: TObject):boolean; virtual; abstract;
     function ShowPixelateDlg(AFilterConnector: TObject):boolean; virtual; abstract;
     function ShowNoiseFilterDlg(AFilterConnector: TObject):boolean; virtual; abstract;
     function ShowNoiseFilterDlg(AFilterConnector: TObject):boolean; virtual; abstract;
     function ShowTwirlDlg(AFilterConnector: TObject):boolean; virtual; abstract;
     function ShowTwirlDlg(AFilterConnector: TObject):boolean; virtual; abstract;
+    function ShowWaveDisplacementDlg(AFilterConnector: TObject):boolean; virtual; abstract;
     function ShowPhongFilterDlg(AFilterConnector: TObject): boolean; virtual; abstract;
     function ShowPhongFilterDlg(AFilterConnector: TObject): boolean; virtual; abstract;
     function ShowFunctionFilterDlg(AFilterConnector: TObject): boolean; virtual; abstract;
     function ShowFunctionFilterDlg(AFilterConnector: TObject): boolean; virtual; abstract;
     function ShowSharpenDlg(AFilterConnector: TObject):boolean; virtual; abstract;
     function ShowSharpenDlg(AFilterConnector: TObject):boolean; virtual; abstract;

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.ar.po

@@ -950,6 +950,10 @@ msgstr "كرة"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "برم"
 msgstr "برم"
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2663,6 +2667,34 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "نصف القطر :"
 msgstr "نصف القطر :"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "إلغاء"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "موافق"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "العمل في تقدم"
 msgstr "العمل في تقدم"

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.cs.po

@@ -947,6 +947,10 @@ msgstr "Koule"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Vířit..."
 msgstr "Vířit..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2661,6 +2665,34 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Poloměr :"
 msgstr "Poloměr :"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Zrušit"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "OK"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Akce v běhu"
 msgstr "Akce v běhu"

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.de.po

@@ -962,6 +962,10 @@ msgstr "Sphäre"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Wirbel..."
 msgstr "Wirbel..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2677,6 +2681,34 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Radius:"
 msgstr "Radius:"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Abbruch"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "OK"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Aktion wird durchgeführt"
 msgstr "Aktion wird durchgeführt"

+ 30 - 0
lazpaint/release/bin/i18n/lazpaint.es.po

@@ -944,6 +944,10 @@ msgstr "Esfera"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Remolino..."
 msgstr "Remolino..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr "Desplazamiento de onda..."
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr "Olvidar respuestas de cuadro de diálogo"
 msgstr "Olvidar respuestas de cuadro de diálogo"
@@ -2657,6 +2661,32 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Rádio:"
 msgstr "Rádio:"
 
 
+#: tfwavedisplacement.button_cancel.caption
+msgctxt "TFWAVEDISPLACEMENT.BUTTON_CANCEL.CAPTION"
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: tfwavedisplacement.button_ok.caption
+msgctxt "TFWAVEDISPLACEMENT.BUTTON_OK.CAPTION"
+msgid "OK"
+msgstr "Aceptar"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr "Desplazamiento de onda"
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr "Desplazamiento:"
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr "Fase:"
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr "Longitud de onda:"
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Acción en progreso"
 msgstr "Acción en progreso"

+ 31 - 0
lazpaint/release/bin/i18n/lazpaint.fi.po

@@ -934,6 +934,10 @@ msgstr ""
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Pyörre"
 msgstr "Pyörre"
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2647,6 +2651,33 @@ msgctxt "TFTWIRL.LABEL_RADIUS.CAPTION"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Säde :"
 msgstr "Säde :"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Peru"
+
+#: tfwavedisplacement.button_ok.caption
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr ""
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr ""
 msgstr ""

+ 30 - 0
lazpaint/release/bin/i18n/lazpaint.fr.po

@@ -950,6 +950,10 @@ msgstr "Sphère"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Torsion..."
 msgstr "Torsion..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr "Décalage d'onde..."
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr "Oublier les choix aux boites de dialogue"
 msgstr "Oublier les choix aux boites de dialogue"
@@ -2664,6 +2668,32 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Rayon :"
 msgstr "Rayon :"
 
 
+#: tfwavedisplacement.button_cancel.caption
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Annuler"
+
+#: tfwavedisplacement.button_ok.caption
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "OK"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr "Décalage d'onde"
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr "Décalage :"
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr "Phase :"
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr "Longueur d'onde :"
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Action en cours"
 msgstr "Action en cours"

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.ja.po

@@ -950,6 +950,10 @@ msgstr "Sphereフィルタ"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Twirlフィルタ..."
 msgstr "Twirlフィルタ..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2663,6 +2667,34 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "半径:"
 msgstr "半径:"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "キャンセル"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "OK"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr ""
 msgstr ""

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.lv.po

@@ -948,6 +948,10 @@ msgstr "Olveida"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Savirpināt ..."
 msgstr "Savirpināt ..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2660,6 +2664,34 @@ msgctxt "TFTWIRL.LABEL_RADIUS.CAPTION"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Rādiuss:"
 msgstr "Rādiuss:"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Atsaukt"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "Labi"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Moris darbojas"
 msgstr "Moris darbojas"

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.nl.po

@@ -971,6 +971,10 @@ msgstr "Bol"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Wervelen..."
 msgstr "Wervelen..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2686,6 +2690,34 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Radius :"
 msgstr "Radius :"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Annuleren"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "OK"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Bezig met actie"
 msgstr "Bezig met actie"

+ 30 - 0
lazpaint/release/bin/i18n/lazpaint.po

@@ -934,6 +934,10 @@ msgstr ""
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr ""
 msgstr ""
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2647,6 +2651,32 @@ msgctxt "TFTWIRL.LABEL_RADIUS.CAPTION"
 msgid "Radius :"
 msgid "Radius :"
 msgstr ""
 msgstr ""
 
 
+#: tfwavedisplacement.button_cancel.caption
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr ""
+
+#: tfwavedisplacement.button_ok.caption
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr ""
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr ""
 msgstr ""

+ 31 - 0
lazpaint/release/bin/i18n/lazpaint.pt_BR.po

@@ -954,6 +954,10 @@ msgstr "Esfera"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Rodopio..."
 msgstr "Rodopio..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2667,6 +2671,33 @@ msgctxt "TFTWIRL.LABEL_RADIUS.CAPTION"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Raio :"
 msgstr "Raio :"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: tfwavedisplacement.button_ok.caption
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr ""
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Ação em progresso"
 msgstr "Ação em progresso"

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.ru.po

@@ -945,6 +945,10 @@ msgstr "Сфера"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Вращение ..."
 msgstr "Вращение ..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2656,6 +2660,34 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Радиус:"
 msgstr "Радиус:"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Отменить"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "ОК"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr "Прогресс действия"
 msgstr "Прогресс действия"

+ 32 - 0
lazpaint/release/bin/i18n/lazpaint.sv.po

@@ -934,6 +934,10 @@ msgstr "Sfär"
 msgid "Twirl..."
 msgid "Twirl..."
 msgstr "Snurra..."
 msgstr "Snurra..."
 
 
+#: tfmain.filterwavedisplacement.caption
+msgid "Wave diplacement..."
+msgstr ""
+
 #: tfmain.forgetdialoganswers.caption
 #: tfmain.forgetdialoganswers.caption
 msgid "Forget dialog box answers"
 msgid "Forget dialog box answers"
 msgstr ""
 msgstr ""
@@ -2647,6 +2651,34 @@ msgctxt "tftwirl.label_radius.caption"
 msgid "Radius :"
 msgid "Radius :"
 msgstr "Radie :"
 msgstr "Radie :"
 
 
+#: tfwavedisplacement.button_cancel.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_cancel.caption"
+msgid "Cancel"
+msgstr "Avbryt"
+
+#: tfwavedisplacement.button_ok.caption
+#, fuzzy
+msgctxt "tfwavedisplacement.button_ok.caption"
+msgid "OK"
+msgstr "OK"
+
+#: tfwavedisplacement.caption
+msgid "Wave displacement"
+msgstr ""
+
+#: tfwavedisplacement.label_displacement.caption
+msgid "Displacement :"
+msgstr ""
+
+#: tfwavedisplacement.label_phase.caption
+msgid "Phase :"
+msgstr ""
+
+#: tfwavedisplacement.label_wavelength.caption
+msgid "Wavelength :"
+msgstr ""
+
 #: uresourcestrings.rsactioninprogress
 #: uresourcestrings.rsactioninprogress
 msgid "Action in progress"
 msgid "Action in progress"
 msgstr ""
 msgstr ""

+ 38 - 0
lazpaint/uconfig.pas

@@ -276,6 +276,14 @@ type
     function DefaultTwirlTurn: double;
     function DefaultTwirlTurn: double;
     procedure SetDefaultTwirlTurn(value: double);
     procedure SetDefaultTwirlTurn(value: double);
 
 
+    //wave displacement config
+    function DefaultWaveDisplacementWavelength: double;
+    procedure SetDefaultWaveDisplacementWavelength(value: double);
+    function DefaultWaveDisplacementAmount: double;
+    procedure SetDefaultWaveDisplacementAmount(value: double);
+    function DefaultWaveDisplacementPhase: double;
+    procedure SetDefaultWaveDisplacementPhase(value: double);
+
     //phong filter
     //phong filter
     function DefaultPhongFilterAltitude: integer;
     function DefaultPhongFilterAltitude: integer;
     procedure SetDefaultPhongFilterAltitude(value: integer);
     procedure SetDefaultPhongFilterAltitude(value: integer);
@@ -1152,6 +1160,36 @@ begin
   iniOptions.WriteFloat('Filter','TwirlTurn',value);
   iniOptions.WriteFloat('Filter','TwirlTurn',value);
 end;
 end;
 
 
+function TLazPaintConfig.DefaultWaveDisplacementWavelength: double;
+begin
+  result := iniOptions.ReadFloat('Filter','WaveDisplacementWavelength',100);
+end;
+
+procedure TLazPaintConfig.SetDefaultWaveDisplacementWavelength(value: double);
+begin
+  iniOptions.WriteFloat('Filter','WaveDisplacementWavelength',value);
+end;
+
+function TLazPaintConfig.DefaultWaveDisplacementAmount: double;
+begin
+  result := iniOptions.ReadFloat('Filter','WaveDisplacementAmount',50);
+end;
+
+procedure TLazPaintConfig.SetDefaultWaveDisplacementAmount(value: double);
+begin
+  iniOptions.WriteFloat('Filter','WaveDisplacementAmount',value);
+end;
+
+function TLazPaintConfig.DefaultWaveDisplacementPhase: double;
+begin
+  result := iniOptions.ReadFloat('Filter','WaveDisplacementPhase',0);
+end;
+
+procedure TLazPaintConfig.SetDefaultWaveDisplacementPhase(value: double);
+begin
+  iniOptions.WriteFloat('Filter','WaveDisplacementPhase',value);
+end;
+
 function TLazPaintConfig.DefaultPhongFilterAltitude: integer;
 function TLazPaintConfig.DefaultPhongFilterAltitude: integer;
 begin
 begin
   result := iniOptions.ReadInteger('Filter','MapAltitude',10);
   result := iniOptions.ReadInteger('Filter','MapAltitude',10);

+ 5 - 0
lazpaint/ufilters.pas

@@ -163,6 +163,11 @@ begin
           filteredLayer := layer.FilterTwirl(FilterConnector.WorkArea, Point(layer.Width div 2,layer.Height div 2), AInstance.Config.DefaultTwirlRadius, AInstance.Config.DefaultTwirlTurn ) as TBGRABitmap
           filteredLayer := layer.FilterTwirl(FilterConnector.WorkArea, Point(layer.Width div 2,layer.Height div 2), AInstance.Config.DefaultTwirlRadius, AInstance.Config.DefaultTwirlTurn ) as TBGRABitmap
         else
         else
           AInstance.ShowTwirlDlg(FilterConnector);
           AInstance.ShowTwirlDlg(FilterConnector);
+    pfWaveDisplacement:
+        if skipDialog then
+          filteredLayer := ugraph.WaveDisplacementFilter(layer,FilterConnector.WorkArea, PointF(layer.Width/2,layer.Height/2), AInstance.Config.DefaultWaveDisplacementWavelength, AInstance.Config.DefaultWaveDisplacementAmount, AInstance.Config.DefaultWaveDisplacementPhase ) as TBGRABitmap
+        else
+          AInstance.ShowWaveDisplacementDlg(FilterConnector);
     pfContour: filteredLayer := layer.FilterContour as TBGRABitmap;
     pfContour: filteredLayer := layer.FilterContour as TBGRABitmap;
     pfGrayscale: filteredLayer := layer.FilterGrayscale(FilterConnector.WorkArea) as TBGRABitmap;
     pfGrayscale: filteredLayer := layer.FilterGrayscale(FilterConnector.WorkArea) as TBGRABitmap;
     pfPerlinNoise: filteredLayer := CreatePerlinNoiseMap(layer.Width,layer.Height,layer.Width/256,layer.Height/256,1,rfBestQuality);
     pfPerlinNoise: filteredLayer := CreatePerlinNoiseMap(layer.Width,layer.Height,layer.Width/256,layer.Height/256,1,rfBestQuality);

+ 47 - 0
lazpaint/ugraph.pas

@@ -49,6 +49,9 @@ function CreateVerticalWoodTexture(tx,ty: integer): TBGRABitmap;
 
 
 function ClearTypeFilter(source: TBGRACustomBitmap): TBGRACustomBitmap;
 function ClearTypeFilter(source: TBGRACustomBitmap): TBGRACustomBitmap;
 function ClearTypeInverseFilter(source: TBGRACustomBitmap): TBGRACustomBitmap;
 function ClearTypeInverseFilter(source: TBGRACustomBitmap): TBGRACustomBitmap;
+function WaveDisplacementFilter(source: TBGRACustomBitmap;
+  ARect: TRect; ACenter: TPointF;
+  AWaveLength, ADisplacement, APhase: single): TBGRACustomBitmap;
 
 
 function DoResample(source :TBGRABitmap; newWidth, newHeight: integer; StretchMode: TResampleMode): TBGRABitmap;
 function DoResample(source :TBGRABitmap; newWidth, newHeight: integer; StretchMode: TResampleMode): TBGRABitmap;
 procedure DrawArrow(ACanvas: TCanvas; ARect: TRect; AStart: boolean; AKindStr: string; ALineCap: TPenEndCap; State: TOwnerDrawState);
 procedure DrawArrow(ACanvas: TCanvas; ARect: TRect; AStart: boolean; AKindStr: string; ALineCap: TPenEndCap; State: TOwnerDrawState);
@@ -738,6 +741,50 @@ begin
   result := temp;
   result := temp;
 end;
 end;
 
 
+type
+  { TWaveDisplacementScanner }
+
+  TWaveDisplacementScanner = class(TBGRACustomScanner)
+    Source: TBGRACustomBitmap;
+    Center: TPointF;
+    Wavelength, Displacement, PhaseRad: single;
+    function ScanAt(X,Y: Single): TBGRAPixel; override;
+  end;
+
+{ TWaveDisplacementScanner }
+
+function TWaveDisplacementScanner.ScanAt(X, Y: Single): TBGRAPixel;
+var
+  u, disp: TPointF;
+  dist: Single;
+  alpha: ValReal;
+begin
+  u := PointF(X,Y)-Center;
+  dist := VectLen(u);
+  if dist = 0 then disp := PointF(0,0) else
+  begin
+    u := u*(1/dist);
+    alpha := PhaseRad+dist*2*Pi/Wavelength;
+    disp := u*sin(alpha)*Displacement;
+  end;
+  result := Source.GetPixel(x+disp.x,y+disp.y);
+end;
+
+function WaveDisplacementFilter(source: TBGRACustomBitmap; ARect: TRect;
+  ACenter: TPointF; AWaveLength, ADisplacement, APhase: single): TBGRACustomBitmap;
+var scan: TWaveDisplacementScanner;
+begin
+ scan := TWaveDisplacementScanner.Create;
+ scan.Center := ACenter;
+ scan.Source := source;
+ scan.Wavelength := AWaveLength;
+ scan.Displacement := ADisplacement;
+ scan.PhaseRad := APhase*Pi/180;
+ result := TBGRABitmap.Create(source.Width,source.Height);
+ result.FillRect(ARect, scan, dmSet);
+ scan.Free;
+end;
+
 function DoResample(source: TBGRABitmap; newWidth, newHeight: integer;
 function DoResample(source: TBGRABitmap; newWidth, newHeight: integer;
   StretchMode: TResampleMode): TBGRABitmap;
   StretchMode: TResampleMode): TBGRABitmap;
 begin
 begin

+ 1 - 1
lazpaint/umenu.pas

@@ -341,7 +341,7 @@ begin
   AddMenus('MenuView',   'ViewGrid,ViewZoomOriginal,ViewZoomIn,ViewZoomOut,ViewZoomFit,-,ViewToolBox,ViewColors,ViewPalette,ViewLayerStack,ViewImageList,ViewStatusBar,-,*,-,ViewDarkTheme,ViewWorkspaceColor,MenuIconSize');
   AddMenus('MenuView',   'ViewGrid,ViewZoomOriginal,ViewZoomIn,ViewZoomOut,ViewZoomFit,-,ViewToolBox,ViewColors,ViewPalette,ViewLayerStack,ViewImageList,ViewStatusBar,-,*,-,ViewDarkTheme,ViewWorkspaceColor,MenuIconSize');
   AddMenus('MenuImage',  'ImageCrop,ImageCropLayer,ImageFlatten,MenuRemoveTransparency,-,ImageNegative,ImageLinearNegative,ImageSwapRedBlue,-,ImageChangeCanvasSize,ImageRepeat,-,ImageResample,ImageSmartZoom3,-,ImageRotateCW,ImageRotateCCW,ImageHorizontalFlip,ImageVerticalFlip');
   AddMenus('MenuImage',  'ImageCrop,ImageCropLayer,ImageFlatten,MenuRemoveTransparency,-,ImageNegative,ImageLinearNegative,ImageSwapRedBlue,-,ImageChangeCanvasSize,ImageRepeat,-,ImageResample,ImageSmartZoom3,-,ImageRotateCW,ImageRotateCCW,ImageHorizontalFlip,ImageVerticalFlip');
   AddMenus('MenuRemoveTransparency', 'ImageClearAlpha,ImageFillBackground');
   AddMenus('MenuRemoveTransparency', 'ImageClearAlpha,ImageFillBackground');
-  AddMenus('MenuFilter', 'MenuRadialBlur,FilterBlurMotion,FilterBlurCustom,FilterPixelate,-,FilterSharpen,FilterSmooth,FilterNoise,FilterMedian,FilterClearType,FilterClearTypeInverse,FilterFunction,-,FilterContour,FilterEmboss,FilterPhong,-,FilterSphere,FilterTwirl,FilterCylinder');
+  AddMenus('MenuFilter', 'MenuRadialBlur,FilterBlurMotion,FilterBlurCustom,FilterPixelate,-,FilterSharpen,FilterSmooth,FilterNoise,FilterMedian,FilterClearType,FilterClearTypeInverse,FilterFunction,-,FilterContour,FilterEmboss,FilterPhong,-,FilterSphere,FilterTwirl,FilterWaveDisplacement,FilterCylinder');
   AddMenus('MenuRadialBlur',  'FilterBlurBox,FilterBlurFast,FilterBlurRadial,FilterBlurCorona,FilterBlurDisk');
   AddMenus('MenuRadialBlur',  'FilterBlurBox,FilterBlurFast,FilterBlurRadial,FilterBlurCorona,FilterBlurDisk');
   AddMenus('MenuColors', 'ColorCurves,ColorPosterize,ColorColorize,ColorShiftColors,FilterComplementaryColor,ColorIntensity,-,ColorLightness,FilterNegative,FilterLinearNegative,FilterNormalize,FilterGrayscale');
   AddMenus('MenuColors', 'ColorCurves,ColorPosterize,ColorColorize,ColorShiftColors,FilterComplementaryColor,ColorIntensity,-,ColorLightness,FilterNegative,FilterLinearNegative,FilterNormalize,FilterGrayscale');
   AddMenus('MenuTool',   'ToolHand,ToolHotSpot,ToolColorPicker,-,ToolPen,ToolBrush,ToolEraser,ToolFloodFill,ToolClone,-,ToolRect,ToolEllipse,ToolPolygon,ToolSpline,ToolGradient,ToolPhong,ToolText,-,ToolDeformation,ToolTextureMapping');
   AddMenus('MenuTool',   'ToolHand,ToolHotSpot,ToolColorPicker,-,ToolPen,ToolBrush,ToolEraser,ToolFloodFill,ToolClone,-,ToolRect,ToolEllipse,ToolPolygon,ToolSpline,ToolGradient,ToolPhong,ToolText,-,ToolDeformation,ToolTextureMapping');