瀏覽代碼

use matrix rotation with originals

Unknown 6 年之前
父節點
當前提交
4725d10e22
共有 3 個文件被更改,包括 111 次插入55 次删除
  1. 20 19
      lazpaint/utool.pas
  2. 89 33
      lazpaint/utoollayer.pas
  3. 2 3
      lazpaint/utoolselect.pas

+ 20 - 19
lazpaint/utool.pas

@@ -57,6 +57,7 @@ type
     procedure OnTryStop(sender: TCustomLayerAction); virtual;
     function SelectionMaxPointDistance: single;
     function GetStatusText: string; virtual;
+    function DoGetToolDrawingLayer: TBGRABitmap; virtual;
   public
     ToolUpdateNeeded: boolean;
     Cursor: TCursor;
@@ -82,7 +83,7 @@ type
     function ToolProvideCopy: boolean; virtual;
     function ToolProvideCut: boolean; virtual;
     function ToolProvidePaste: boolean; virtual;
-    function GetToolDrawingLayer: TBGRABitmap; virtual;
+    function GetToolDrawingLayer: TBGRABitmap;
     procedure RestoreBackupDrawingLayer;
     function GetBackupLayerIfExists: TBGRABitmap;
     function Render(VirtualScreen: TBGRABitmap; VirtualScreenWidth, VirtualScreenHeight: integer; BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect; virtual;
@@ -100,8 +101,7 @@ type
   protected
     function GetAction: TLayerAction; override;
     function GetIsSelectingTool: boolean; override;
-  public
-    function GetToolDrawingLayer: TBGRABitmap; override;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
   end;
 
   TToolClass = class of TGenericTool;
@@ -355,7 +355,7 @@ begin
   result := false;
 end;
 
-function TReadonlyTool.GetToolDrawingLayer: TBGRABitmap;
+function TReadonlyTool.DoGetToolDrawingLayer: TBGRABitmap;
 begin
   if Manager.Image.SelectionMaskEmpty or not assigned(Manager.Image.SelectionLayerReadonly) then
     Result:= Manager.Image.CurrentLayerReadOnly
@@ -392,6 +392,21 @@ begin
   result := '';
 end;
 
+function TGenericTool.DoGetToolDrawingLayer: TBGRABitmap;
+begin
+  if Action = nil then
+    result := nil
+  else if IsSelectingTool then
+  begin
+    Action.QuerySelection;
+    result := Action.CurrentSelection;
+    if result = nil then
+      raise exception.Create('Selection not created');
+  end
+  else
+    result := Action.DrawingLayer;
+end;
+
 function TGenericTool.GetAction: TLayerAction;
 var
   layer: TBGRABitmap;
@@ -649,21 +664,7 @@ end;
 
 function TGenericTool.GetToolDrawingLayer: TBGRABitmap;
 begin
-  if Action = nil then
-  begin
-    result := nil;
-  end else
-  if IsSelectingTool then
-  begin
-    Action.QuerySelection;
-    result := Action.CurrentSelection;
-    if result = nil then
-      raise exception.Create('Selection not created');
-  end
-  else
-  begin
-    result := Action.DrawingLayer;
-  end;
+  result := DoGetToolDrawingLayer;
   FLastToolDrawingLayer := result;
 end;
 

+ 89 - 33
lazpaint/utoollayer.pas

@@ -5,7 +5,7 @@ unit UToolLayer;
 interface
 
 uses
-  Classes, SysUtils, UTool, BGRABitmap, BGRABitmapTypes, UImageType;
+  Classes, SysUtils, UTool, BGRABitmap, BGRABitmapTypes, UImageType, BGRATransform;
 
 type
   { TToolMoveLayer }
@@ -27,8 +27,8 @@ type
     procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
     function UseOriginal: boolean;
     procedure NeedLayerBounds;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
   public
-    function GetToolDrawingLayer: TBGRABitmap; override;
     function ToolUp: TRect; override;
     function ToolKeyDown(var key: Word): TRect; override;
     function Render(VirtualScreen: TBGRABitmap; {%H-}VirtualScreenWidth,
@@ -44,9 +44,11 @@ type
     function GetOriginalLayerBounds: TRect;
     function GetRotationCenter: TPointF;
     procedure SetRotationCenter(AValue: TPointF);
+    function UseOriginal: boolean;
   protected
-    FOriginalLayerBounds: TRect;
-    FOriginalLayerBoundsDefined: boolean;
+    FInitialOriginalMatrix: TAffineMatrix;
+    FInitialLayerBounds: TRect;
+    FInitialLayerBoundsDefined: boolean;
     FRotationCenter: TPointF;
     FRotationCenterDefined: boolean;
     FFilter: TResampleFilter;
@@ -64,9 +66,12 @@ type
     function DoToolMove({%H-}toolDest: TBGRABitmap; {%H-}pt: TPoint; ptF: TPointF): TRect;
       override;
     function UpdateRotation: TRect;
+    procedure CancelRotation;
+    procedure ValidateRotation;
     property RotationCenter: TPointF read GetRotationCenter write SetRotationCenter;
     property OriginalLayerBounds: TRect read GetOriginalLayerBounds;
     procedure OnTryStop({%H-}sender: TCustomLayerAction); override;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
   public
     constructor Create(AManager: TToolManager); override;
     destructor Destroy; override;
@@ -80,7 +85,7 @@ type
 
 implementation
 
-uses LazPaintType, ugraph, LCLType, Types, BGRATransform;
+uses LazPaintType, ugraph, LCLType, Types;
 
 { TToolRotateLayer }
 
@@ -94,12 +99,12 @@ end;
 
 function TToolRotateLayer.GetOriginalLayerBounds: TRect;
 begin
-  if not FOriginalLayerBoundsDefined then
+  if not FInitialLayerBoundsDefined then
   begin
-    FOriginalLayerBounds := GetToolDrawingLayer.GetImageBounds;
-    FOriginalLayerBoundsDefined := true;
+    FInitialLayerBounds := GetToolDrawingLayer.GetImageBounds;
+    FInitialLayerBoundsDefined := true;
   end;
-  result := FOriginalLayerBounds;
+  result := FInitialLayerBounds;
 end;
 
 function TToolRotateLayer.GetRotationCenter: TPointF;
@@ -109,8 +114,12 @@ begin
     if IsRectEmpty(OriginalLayerBounds) then
       FRotationCenter := PointF(Manager.Image.Width/2 - 0.5,Manager.Image.Height/2 - 0.5)
     else
-    with OriginalLayerBounds do
-      FRotationCenter := PointF((Left+Right)/2 - 0.5, (Top+Bottom)/2 - 0.5);
+    begin
+      with OriginalLayerBounds do
+        FRotationCenter := PointF((Left+Right)/2 - 0.5, (Top+Bottom)/2 - 0.5);
+      with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+        FRotationCenter += PointF(X,Y);
+    end;
     FRotationCenterDefined := true;
   end;
   result := FRotationCenter;
@@ -121,9 +130,19 @@ begin
   FRotationCenter := AValue;
 end;
 
+function TToolRotateLayer.UseOriginal: boolean;
+begin
+  with Manager.Image do
+    result := LayerOriginalDefined[CurrentLayerIndex] and
+              LayerOriginalKnown[CurrentLayerIndex];
+end;
+
 function TToolRotateLayer.DoToolDown(toolDest: TBGRABitmap; pt: TPoint;
   ptF: TPointF; rightBtn: boolean): TRect;
 begin
+  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+    ptF += PointF(X,Y);
+
   if not FRotating and not rightBtn then
   begin
     FRotating := true;
@@ -149,7 +168,10 @@ end;
 function TToolRotateLayer.DoToolMove(toolDest: TBGRABitmap; pt: TPoint;
   ptF: TPointF): TRect;
 var angleDiff: single;
+  ofs: TPoint;
 begin
+  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+    ptF += PointF(X,Y);
   if FRotating then
   begin
     angleDiff := ComputeAngle(ptF.X-RotationCenter.X,ptF.Y-RotationCenter.Y)-
@@ -175,22 +197,47 @@ begin
   FPreviousRotationCenter := RotationCenter;
   FPreviousFilter := FFilter;
   result := EmptyRect;
-  if not FLastUpdateRectDefined then
+
+  if UseOriginal then
   begin
-    GetToolDrawingLayer.FillTransparent;
-    result := rect(0,0,GetToolDrawingLayer.Width,GetToolDrawingLayer.Height);
+    Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] :=
+      AffineMatrixTranslation(RotationCenter.X,RotationCenter.Y)*
+      AffineMatrixRotationDeg(FActualAngle)*
+      AffineMatrixTranslation(-RotationCenter.X,-RotationCenter.Y)*
+      FInitialOriginalMatrix;
   end else
-  if not IsRectEmpty(FLastUpdateRect) then
   begin
-    GetToolDrawingLayer.FillRect(FLastUpdateRect,BGRAPixelTransparent,dmSet);
-    result := FLastUpdateRect;
+    if not FLastUpdateRectDefined then
+    begin
+      GetToolDrawingLayer.FillTransparent;
+      result := rect(0,0,GetToolDrawingLayer.Width,GetToolDrawingLayer.Height);
+    end else
+    if not IsRectEmpty(FLastUpdateRect) then
+    begin
+      GetToolDrawingLayer.FillRect(FLastUpdateRect,BGRAPixelTransparent,dmSet);
+      result := FLastUpdateRect;
+    end;
+    FLastUpdateRect := GetToolDrawingLayer.GetImageAngleBounds(0,0,Action.BackupDrawingLayer,FActualAngle,RotationCenter.X,RotationCenter.Y,True);
+    FLastUpdateRectDefined:= true;
+    GetToolDrawingLayer.ComputeImageAngleAxes(0,0,Action.BackupDrawingLayer.Width,Action.BackupDrawingLayer.Height,FActualAngle,RotationCenter.X,RotationCenter.Y,True,
+    origin,haxis,vaxis);
+    GetToolDrawingLayer.PutImageAffine(origin,haxis,vaxis,Action.BackupDrawingLayer,FLastUpdateRect,FFilter,dmSet,255);
+    result := RectUnion(result,FLastUpdateRect);
   end;
-  FLastUpdateRect := GetToolDrawingLayer.GetImageAngleBounds(0,0,Action.BackupDrawingLayer,FActualAngle,RotationCenter.X,RotationCenter.Y,True);
-  FLastUpdateRectDefined:= true;
-  GetToolDrawingLayer.ComputeImageAngleAxes(0,0,Action.BackupDrawingLayer.Width,Action.BackupDrawingLayer.Height,FActualAngle,RotationCenter.X,RotationCenter.Y,True,
-  origin,haxis,vaxis);
-  GetToolDrawingLayer.PutImageAffine(origin,haxis,vaxis,Action.BackupDrawingLayer,FLastUpdateRect,FFilter,dmSet,255);
-  result := RectUnion(result,FLastUpdateRect);
+end;
+
+procedure TToolRotateLayer.CancelRotation;
+begin
+  if UseOriginal then
+    Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex] := FInitialOriginalMatrix
+  else
+    CancelActionPartially;
+  Manager.QueryExitTool;
+end;
+
+procedure TToolRotateLayer.ValidateRotation;
+begin
+  Manager.QueryExitTool;
 end;
 
 procedure TToolRotateLayer.OnTryStop(sender: TCustomLayerAction);
@@ -198,22 +245,32 @@ begin
   //nothing
 end;
 
+function TToolRotateLayer.DoGetToolDrawingLayer: TBGRABitmap;
+begin
+  if UseOriginal then
+    Result:= Manager.Image.CurrentLayerReadOnly   //do not modify layer data directly and ignore selection
+  else
+    Result:= Action.SelectedImageLayer;
+end;
+
 constructor TToolRotateLayer.Create(AManager: TToolManager);
 begin
   inherited Create(AManager);
   FAngle:= 0;
   FPreviousActualAngle := 0;
   FCtrlDown:= false;
-  FOriginalLayerBoundsDefined:= false;
+  FInitialLayerBoundsDefined:= false;
   FRotationCenterDefined := false;
   FLastUpdateRectDefined:= false;
   FFilter := rfCosine;
   FPreviousFilter := FFilter;
+  FInitialOriginalMatrix := Manager.Image.LayerOriginalMatrix[Manager.Image.CurrentLayerIndex];
 end;
 
 destructor TToolRotateLayer.Destroy;
 begin
-  ValidateActionPartially;
+  if not UseOriginal then
+    ValidateAction;
   inherited Destroy;
 end;
 
@@ -232,17 +289,15 @@ begin
   end else
   if Key = VK_RETURN then
   begin
-    if FActualAngle = 0 then CancelActionPartially
-     else ValidateActionPartially;
+    if FActualAngle = 0 then CancelRotation
+    else ValidateRotation;
     result := OnlyRenderChange;
-    manager.QueryExitTool;
     key := 0;
   end else
   if Key = VK_ESCAPE then
   begin
-    CancelActionPartially;
+    CancelRotation;
     result := OnlyRenderChange;
-    manager.QueryExitTool;
     key := 0;
   end else
     result := EmptyRect;
@@ -273,7 +328,8 @@ function TToolRotateLayer.Render(VirtualScreen: TBGRABitmap;
   VirtualScreenWidth, VirtualScreenHeight: integer;
   BitmapToVirtualScreen: TBitmapToVirtualScreenFunction): TRect;
 begin
-  Result:= NicePoint(VirtualScreen,BitmapToVirtualScreen(RotationCenter));
+  with Manager.Image.LayerOffset[Manager.Image.CurrentLayerIndex] do
+    Result:= NicePoint(VirtualScreen,BitmapToVirtualScreen(RotationCenter-PointF(X,Y)));
 end;
 
 function TToolRotateLayer.GetIsSelectingTool: boolean;
@@ -366,9 +422,9 @@ begin
   end;
 end;
 
-function TToolMoveLayer.GetToolDrawingLayer: TBGRABitmap;
+function TToolMoveLayer.DoGetToolDrawingLayer: TBGRABitmap;
 begin
-  Result:= Manager.Image.CurrentLayerReadOnly;   //do not create a selection layer
+  Result:= Manager.Image.CurrentLayerReadOnly;   //do not modify layer data directly and ignore selection
 end;
 
 function TToolMoveLayer.ToolUp: TRect;

+ 2 - 3
lazpaint/utoolselect.pas

@@ -86,8 +86,7 @@ type
     function GetIsSelectingTool: boolean; override;
     function GetAction: TLayerAction; override;
     function FixSelectionTransform: boolean; override;
-  public
-    function GetToolDrawingLayer: TBGRABitmap; override;
+    function DoGetToolDrawingLayer: TBGRABitmap; override;
   end;
 
   { TToolMoveSelection }
@@ -152,7 +151,7 @@ begin
   Result:= false;
 end;
 
-function TTransformSelectionTool.GetToolDrawingLayer: TBGRABitmap;
+function TTransformSelectionTool.DoGetToolDrawingLayer: TBGRABitmap;
 begin
   result := Manager.Image.SelectionMaskReadonly;
 end;