123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- unit GR32.Paint.Tool.Brush;
- (* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1 or LGPL 2.1 with linking exception
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * Alternatively, the contents of this file may be used under the terms of the
- * Free Pascal modified version of the GNU Lesser General Public License
- * Version 2.1 (the "FPC modified LGPL License"), in which case the provisions
- * of this license are applicable instead of those above.
- * Please see the file LICENSE.txt for additional information concerning this
- * license.
- *
- * The Original Code is Paint tools for Graphics32
- *
- * The Initial Developer of the Original Code is
- * Anders Melander, [email protected]
- *
- * Portions created by the Initial Developer are Copyright (C) 2008-2025
- * the Initial Developer. All Rights Reserved.
- *
- * ***** END LICENSE BLOCK ***** *)
- interface
- {$INCLUDE GR32.inc}
- uses
- Classes,
- Controls,
- GR32,
- GR32.Paint.Host.API,
- GR32.Paint.Tool,
- GR32.Paint.Tool.API,
- GR32.Paint.Brush;
- //------------------------------------------------------------------------------
- //
- // TBitmap32PaintToolBrush
- //
- //------------------------------------------------------------------------------
- type
- IBitmap32PaintToolBrush = interface
- ['{9AF10CB0-6D29-48A6-8DE6-F19CDEEBAFB2}']
- function CreateBrush(Color: TColor32): TCustomPaintBrush;
- end;
- TBitmap32PaintToolBrush = class abstract(TCustomBitmap32PaintTool, IBitmap32PaintToolBrush)
- strict private
- FBrushLineState: TPaintBrushLineState;
- FLastPos: TFloatPoint;
- FBrush: TCustomPaintBrush;
- FBrushLine: TPaintBrushLine;
- FHasVectorCursor: boolean;
- FCursorSize: Single;
- FBrushSize: Single;
- strict protected
- // IBitmap32PaintToolBrush
- function CreateBrush(Color: TColor32): TCustomPaintBrush; virtual; abstract;
- strict protected
- function GetCaption: string; override;
- procedure BeginAction(const Context: IBitmap32PaintToolContext; var ToolState: TBitmap32PaintToolState); override;
- procedure ContinueAction(const Context: IBitmap32PaintToolContext; var ToolState: TBitmap32PaintToolState); override;
- procedure EndAction(const Context: IBitmap32PaintToolContext; var ToolState: TBitmap32PaintToolState); override;
- function GetCursor(out Cursor: TCursor): boolean; override;
- strict protected
- procedure GetVectorCursor;
- function CreateVectorCursor: boolean; virtual;
- function GetStep: integer; virtual;
- property Brush: TCustomPaintBrush read FBrush;
- property Step: integer read GetStep;
- public
- constructor Create(const APaintHost: IBitmap32PaintHost); override;
- destructor Destroy; override;
- property BrushSize: Single read FBrushSize write FBrushSize;
- end;
- TBitmap32PaintToolBrushClass = class of TBitmap32PaintToolBrush;
- resourcestring
- sBitmap32PaintToolBrushCaption = 'Brush';
- //------------------------------------------------------------------------------
- //
- // TBitmap32PaintToolCircularBrush
- //
- //------------------------------------------------------------------------------
- type
- TBitmapBrushClass = class of TBitmapPaintBrush;
- TBitmap32PaintToolCircularBrush = class(TBitmap32PaintToolBrush)
- strict private
- FBlendFunc: TPixelCombineEvent;
- FAntiAlias: boolean;
- FHardness: Single;
- FStep: integer;
- strict protected
- procedure BlendWrapper(F: TColor32; var B: TColor32; M: Cardinal);
- function GetStep: integer; override;
- function CreateBrush(Color: TColor32): TCustomPaintBrush; override;
- function GetBrushClass: TBitmapBrushClass; virtual;
- public
- constructor Create(const APaintHost: IBitmap32PaintHost); override;
- property AntiAlias: boolean read FAntiAlias write FAntiAlias;
- // [0..100]
- property Hardness: Single read FHardness write FHardness;
- // [1..]
- property Step: integer read FStep write FStep;
- end;
- //------------------------------------------------------------------------------
- //
- // TBitmap32PaintToolSmudgeBrush
- //
- //------------------------------------------------------------------------------
- type
- TBitmap32PaintToolSmudgeBrush = class(TBitmap32PaintToolCircularBrush)
- strict private
- FPressure: integer;
- strict protected
- function GetCaption: string; override;
- function GetStep: integer; override;
- function GetBrushClass: TBitmapBrushClass; override;
- function GetCursor(out Cursor: TCursor): boolean; override;
- function CreateBrush(Color: TColor32): TCustomPaintBrush; override;
- public
- constructor Create(const APaintHost: IBitmap32PaintHost); override;
- // [0..100]
- property Pressure: integer read FPressure write FPressure;
- end;
- resourcestring
- sBitmap32PaintToolSmudgeCaption = 'Smudge';
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- //------------------------------------------------------------------------------
- implementation
- uses
- Math,
- Types,
- SysUtils,
- GR32_VectorUtils,
- GR32_Polygons,
- GR32.Blur;
- //------------------------------------------------------------------------------
- //
- // TBitmap32PaintToolBrush
- //
- //------------------------------------------------------------------------------
- constructor TBitmap32PaintToolBrush.Create(const APaintHost: IBitmap32PaintHost);
- begin
- inherited;
- FBrushSize := 15;
- end;
- destructor TBitmap32PaintToolBrush.Destroy;
- begin
- inherited;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolBrush.CreateVectorCursor: boolean;
- var
- Radius: Single;
- Steps: integer;
- Stipple: TArrayOfColor32;
- Polygon: TArrayOfFixedPoint;
- FeatureVectorCursor: IBitmap32PaintFeatureVectorCursor;
- begin
- Result := False;
- if (not Supports(PaintHost, IBitmap32PaintFeatureVectorCursor, FeatureVectorCursor)) then
- exit;
- FCursorSize := BrushSize;
- Radius := FCursorSize / 2;
- if (Radius > 1) then
- begin
- Steps := Round(Radius * Abs(PaintHost.Magnification)) + 4;
- if Odd(Steps) then
- Inc(Steps);
- Polygon := FloatPointToFixedPoint(Circle(FloatPoint(0, 0), Radius, Steps));
- SetLength(Stipple, 6);
- Stipple[0] := $80FFFFFF;
- Stipple[1] := $80FFFFFF;
- Stipple[2] := $00000000;
- Stipple[3] := $80000000;
- Stipple[4] := $80000000;
- Stipple[5] := $00000000;
- Result := FeatureVectorCursor.SetToolVectorCursor(Polygon, GR32.Point(0, 0), 0, Stipple);
- end;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolBrush.GetCaption: string;
- begin
- Result := sBitmap32PaintToolBrushCaption;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolBrush.GetCursor(out Cursor: TCursor): boolean;
- begin
- Cursor := crCross;
- Result := True;
- GetVectorCursor;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolBrush.GetStep: integer;
- begin
- Result := 1;
- end;
- //------------------------------------------------------------------------------
- procedure TBitmap32PaintToolBrush.GetVectorCursor;
- begin
- FHasVectorCursor := CreateVectorCursor;
- end;
- //------------------------------------------------------------------------------
- procedure TBitmap32PaintToolBrush.BeginAction(const Context: IBitmap32PaintToolContext; var ToolState: TBitmap32PaintToolState);
- begin
- inherited;
- // Note: TRemapTransformation requires the width/height of the map to be greater than one!
- if ([ssLeft, ssRight] * Context.MouseParams.ShiftState <> []) and (Context.Buffer.Width > 1) and (Context.Buffer.Height > 1) then
- begin
- FLastPos := Context.MouseParams.BitmapPosFloat;
- FBrush := CreateBrush(ActiveColor(Context.MouseParams.ShiftState));
- FBrush.BeginBrush(Context.Buffer);
- ASSERT(FBrushLine = nil);
- FBrushLine := TPaintBrushLine.Create(Context.Buffer, FBrush, Step);
- FBrushLine.MoveTo(FLastPos.X, FLastPos.Y);
- FBrushLineState.Valid := False;
- PaintHost.Changed(Caption);
- end else
- ToolState := tsAbort;
- end;
- //------------------------------------------------------------------------------
- procedure TBitmap32PaintToolBrush.ContinueAction(const Context: IBitmap32PaintToolContext; var ToolState: TBitmap32PaintToolState);
- begin
- if ([ssLeft, ssRight] * Context.MouseParams.ShiftState <> []) then
- begin
- // Erase old line (via update of background)
- if (FBrushLineState.Valid) then
- begin
- Context.Buffer.BeginMeasuring(nil);
- try
- // Replay stroke without actually modifying anything
- FBrushLine.RestoreState(FBrushLineState);
- FBrushLine.LineTo(FLastPos.X, FLastPos.Y);
- finally
- Context.Buffer.EndMeasuring;
- end;
- end;
- // Save brush state so we can replay the stroke we're about to make when
- // the old line should be erased (via background repaint).
- FBrushLine.SaveState(FBrushLineState);
- FLastPos := Context.MouseParams.BitmapPosFloat;
- FBrushLine.LineTo(FLastPos.X, FLastPos.Y);
- PaintHost.Changed(Caption);
- end;
- end;
- //------------------------------------------------------------------------------
- procedure TBitmap32PaintToolBrush.EndAction(const Context: IBitmap32PaintToolContext; var ToolState: TBitmap32PaintToolState);
- begin
- (*
- ** [] Replace
- ** [ssShift] Transparent (blend)
- *)
- if (FLastPos <> Context.MouseParams.BitmapPosFloat) then
- begin
- FBrushLine.LineTo(Context.MouseParams.BitmapPosFloat.X, Context.MouseParams.BitmapPosFloat.Y);
- PaintHost.Changed(Caption);
- end;
- FreeAndNil(FBrushLine);
- FBrush.EndBrush;
- FreeAndNil(FBrush);
- end;
- //------------------------------------------------------------------------------
- //
- // TBitmap32PaintToolCircularBrush
- //
- //------------------------------------------------------------------------------
- constructor TBitmap32PaintToolCircularBrush.Create(const APaintHost: IBitmap32PaintHost);
- begin
- inherited;
- FAntiAlias := True;
- FHardness := 75;
- FStep := 1;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolCircularBrush.CreateBrush(Color: TColor32): TCustomPaintBrush;
- var
- Feather, Radius: Single;
- BrushCircle: TArrayOfFloatPoint;
- // Blender: IBitmap32Blender;
- begin
- // +2 to make room for antialiasing
- Result := GetBrushClass.Create(Ceil(BrushSize)+2, Ceil(BrushSize)+2);
- TBitmapPaintBrush(Result).Bitmap.Clear(0);
- if (AntiAlias) then
- Feather := BrushSize - BrushSize / 100 * Hardness
- else
- Feather := 0;
- Radius := (BrushSize - Feather) / 2;
- BrushCircle := Circle(Result.Width/2-0.5, Result.Height/2-0.5, Radius);
- PolygonFS(TBitmapPaintBrush(Result).Bitmap, BrushCircle, Color);
- if (Feather > 0) then
- Blur32(TBitmapPaintBrush(Result).Bitmap, Feather);
- (* Maybe later...
- DrawCircle(TBitmapPaintBrush(Result).Bitmap, Result.Width/2-0.5, Result.Height/2-0.5, Radius, Color, Color, 0, Feather, AntiAlias, True);
- *)
- (*
- Blender := BitmapEditorBlendService.BlenderByID(SettingValues['Blend']);
- if (Blender <> nil) then
- begin
- Blender.GetBlendFunc(FBlendFunc);
- if (Assigned(FBlendFunc)) then
- TBitmapPaintBrush(Result).BlendFunc := BlendWrapper
- else
- TBitmapPaintBrush(Result).BlendFunc := nil;
- end else
- *)
- TBitmapPaintBrush(Result).BlendFunc := nil;
- end;
- //------------------------------------------------------------------------------
- procedure TBitmap32PaintToolCircularBrush.BlendWrapper(F: TColor32; var B: TColor32; M: Cardinal);
- begin
- if (Assigned(FBlendFunc)) then
- FBlendFunc(F, B, M or $0000FF00); // Set source master alpha to 255
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolCircularBrush.GetBrushClass: TBitmapBrushClass;
- begin
- Result := TBitmapPaintBrush;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolCircularBrush.GetStep: integer;
- begin
- Result := FStep;
- end;
- //------------------------------------------------------------------------------
- //
- // TBitmap32PaintToolSmudgeBrush
- //
- //------------------------------------------------------------------------------
- constructor TBitmap32PaintToolSmudgeBrush.Create(const APaintHost: IBitmap32PaintHost);
- begin
- inherited;
- FPressure := 50;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolSmudgeBrush.CreateBrush(
- Color: TColor32): TCustomPaintBrush;
- begin
- Result := inherited CreateBrush(Color or $FF000000);
- TSmudgePaintBrush(Result).Pressure := FPressure;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolSmudgeBrush.GetBrushClass: TBitmapBrushClass;
- begin
- Result := TSmudgePaintBrush;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolSmudgeBrush.GetCaption: string;
- begin
- Result := sBitmap32PaintToolSmudgeCaption;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolSmudgeBrush.GetCursor(out Cursor: TCursor): boolean;
- begin
- Cursor := crCross;
- Result := True;
- GetVectorCursor;
- end;
- //------------------------------------------------------------------------------
- function TBitmap32PaintToolSmudgeBrush.GetStep: integer;
- begin
- Result := 1;
- end;
- //------------------------------------------------------------------------------
- end.
|