Ignore:
Timestamp:
Apr 17, 2019, 10:42:18 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Updated Graphics32 library.
Location:
GraphicTest/Packages/Graphics32
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/Graphics32

    • Property svn:ignore set to
      lib
  • GraphicTest/Packages/Graphics32/GR32_Polygons.pas

    r450 r522  
    2121 * license.
    2222 *
    23  * The Original Code is Graphics32
     23 * The Original Code is Vectorial Polygon Rasterizer for Graphics32
    2424 *
    2525 * The Initial Developer of the Original Code is
    26  * Alex A. Denisov
     26 * Mattias Andersson <mattias@centaurix.com>
    2727 *
    28  * Portions created by the Initial Developer are Copyright (C) 2000-2009
     28 * Portions created by the Initial Developer are Copyright (C) 2008-2012
    2929 * the Initial Developer. All Rights Reserved.
    3030 *
    3131 * Contributor(s):
    32  *   Andre Beckedorf <Andre@metaException.de>
    33  *   Mattias Andersson <mattias@centaurix.com>
    34  *   Peter Larson <peter@larson.net>
    3532 *
    3633 * ***** END LICENSE BLOCK ***** *)
     
    4037{$I GR32.inc}
    4138
    42 {$IFDEF PUREPASCAL}
    43 {$DEFINE USENATIVECODE}
    44 {$ENDIF}
    45 {$IFDEF USEINLINING}
    46 {$DEFINE USENATIVECODE}
    47 {$ENDIF}
    48 
    4939uses
    50 {$IFDEF FPC}
    51 {$ELSE}
    52   Windows,
    53 {$ENDIF}
    54   Classes, SysUtils, GR32, GR32_LowLevel, GR32_Blend, GR32_Transforms,
    55   GR32_Resamplers, GR32_Math;
    56 
    57 { Polylines }
    58 
    59 procedure PolylineTS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    60   Color: TColor32; Closed: Boolean = False; Transformation: TTransformation = nil);
    61 procedure PolylineAS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    62   Color: TColor32; Closed: Boolean = False; Transformation: TTransformation = nil);
    63 procedure PolylineXS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    64   Color: TColor32; Closed: Boolean = False; Transformation: TTransformation = nil);
    65 procedure PolylineXSP(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    66   Closed: Boolean = False; Transformation: TTransformation = nil);
    67 
    68 procedure PolyPolylineTS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    69   Color: TColor32; Closed: Boolean = False; Transformation: TTransformation = nil);
    70 procedure PolyPolylineAS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    71   Color: TColor32; Closed: Boolean = False; Transformation: TTransformation = nil);
    72 procedure PolyPolylineXS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    73   Color: TColor32; Closed: Boolean = False; Transformation: TTransformation = nil);
    74 procedure PolyPolylineXSP(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    75   Closed: Boolean = False; Transformation: TTransformation = nil);
    76 
    77 { Polygons }
     40  Types, GR32, GR32_Containers, GR32_VPR, GR32_Transforms, GR32_Resamplers;
    7841
    7942type
    80   TPolyFillMode = (pfAlternate, pfWinding);
    81   TAntialiasMode = (am32times, am16times, am8times, am4times, am2times, amNone);
    82 
    83   TFillLineEvent = procedure(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32) of object;
     43  { Polygon join style - used by GR32_VectorUtils.Grow(). }
     44  { nb: jsRoundEx rounds both convex and concave joins unlike jsRound which
     45    only rounds convex joins. The depth of convex join rounding is controlled
     46    by Grow's MiterLimit parameter }
     47  TJoinStyle = (jsMiter, jsBevel, jsRound, jsRoundEx);
     48
     49  { Polygon end style }
     50  TEndStyle = (esButt, esSquare, esRound);
     51
     52  { Polygon fill mode }
     53  TPolyFillMode = (pfAlternate, pfWinding, pfEvenOdd = 0, pfNonZero);
     54
     55  { TCustomPolygonRenderer }
     56  TCustomPolygonRenderer = class(TThreadPersistent)
     57  public
     58    procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
     59      const ClipRect: TFloatRect; Transformation: TTransformation); overload; virtual;
     60    procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
     61      const ClipRect: TFloatRect); overload; virtual;
     62    procedure PolygonFS(const Points: TArrayOfFloatPoint;
     63      const ClipRect: TFloatRect; Transformation: TTransformation); overload; virtual;
     64    procedure PolygonFS(const Points: TArrayOfFloatPoint;
     65      const ClipRect: TFloatRect); overload; virtual;
     66
     67    // procedure PolyPolygonXS(const Points: TArrayOfArrayOfFixedPoint; const ClipRect: TFixedRect; Transformation: TTransformation); virtual; overload;
     68    // procedure PolyPolygonXS(const Points: TArrayOfArrayOfFixedPoint; const ClipRect: TFixedRect); virtual; overload;
     69  end;
     70  TCustomPolygonRendererClass = class of TCustomPolygonRenderer;
     71
     72  TCustomPolygonFiller = class;
     73
     74  { TPolygonRenderer32 }
     75  TPolygonRenderer32 = class(TCustomPolygonRenderer)
     76  private
     77    FBitmap: TBitmap32;
     78    FFillMode: TPolyFillMode;
     79    FColor: TColor32;
     80    FFiller: TCustomPolygonFiller;
     81    procedure SetColor(const Value: TColor32);
     82    procedure SetFillMode(const Value: TPolyFillMode);
     83    procedure SetFiller(const Value: TCustomPolygonFiller);
     84  protected
     85    procedure SetBitmap(const Value: TBitmap32); virtual;
     86  public
     87    constructor Create(Bitmap: TBitmap32; Fillmode: TPolyFillMode = pfWinding); reintroduce; overload;
     88    procedure PolygonFS(const Points: TArrayOfFloatPoint); overload; virtual;
     89    procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint); overload; virtual;
     90
     91    property Bitmap: TBitmap32 read FBitmap write SetBitmap;
     92    property FillMode: TPolyFillMode read FFillMode write SetFillMode;
     93    property Color: TColor32 read FColor write SetColor;
     94    property Filler: TCustomPolygonFiller read FFiller write SetFiller;
     95  end;
     96  TPolygonRenderer32Class = class of TPolygonRenderer32;
     97
     98  { TPolygonRenderer32VPR }
     99  { Polygon renderer based on VPR. Computes exact coverages for optimal anti-aliasing. }
     100  TFillProc = procedure(Coverage: PSingleArray; AlphaValues: PColor32Array; Count: Integer; Color: TColor32);
     101
     102  TPolygonRenderer32VPR = class(TPolygonRenderer32)
     103  private
     104    FFillProc: TFillProc;
     105    procedure UpdateFillProcs;
     106  protected
     107    procedure RenderSpan(const Span: TValueSpan; DstY: Integer); virtual;
     108    procedure FillSpan(const Span: TValueSpan; DstY: Integer); virtual;
     109    function GetRenderSpan: TRenderSpanEvent; virtual;
     110  public
     111    procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
     112      const ClipRect: TFloatRect); override;
     113  end;
     114
     115  { TPolygonRenderer32LCD }
     116  TPolygonRenderer32LCD = class(TPolygonRenderer32VPR)
     117  protected
     118    procedure RenderSpan(const Span: TValueSpan; DstY: Integer); override;
     119  public
     120    procedure PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint;
     121      const ClipRect: TFloatRect); override;
     122  end;
     123
     124  { TPolygonRenderer32LCD2 }
     125  TPolygonRenderer32LCD2 = class(TPolygonRenderer32LCD)
     126  public
     127    procedure RenderSpan(const Span: TValueSpan; DstY: Integer); override;
     128  end;
     129
     130  { TCustomPolygonFiller }
     131
     132  TFillLineEvent = procedure(Dst: PColor32; DstX, DstY, Length: Integer;
     133    AlphaValues: PColor32; CombineMode: TCombineMode) of object;
    84134
    85135  TCustomPolygonFiller = class
     
    87137    function GetFillLine: TFillLineEvent; virtual; abstract;
    88138  public
     139    procedure BeginRendering; virtual;
     140    procedure EndRendering; virtual;
     141
    89142    property FillLine: TFillLineEvent read GetFillLine;
    90143  end;
    91144
    92 const
    93   DefaultAAMode = am8times; // Use 54 levels of transparency for antialiasing.
    94 
    95 procedure PolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    96   Color: TColor32; Mode: TPolyFillMode = pfAlternate; Transformation: TTransformation = nil); overload;
    97 procedure PolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    98   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode = pfAlternate; Transformation: TTransformation = nil); overload;
    99 procedure PolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    100   Filler: TCustomPolygonFiller; Mode: TPolyFillMode = pfAlternate; Transformation: TTransformation = nil); overload;
    101 
    102 procedure PolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    103   Color: TColor32; Mode: TPolyFillMode = pfAlternate;
    104   const AAMode: TAntialiasMode = DefaultAAMode; Transformation: TTransformation = nil); overload;
    105 procedure PolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    106   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode = pfAlternate;
    107   const AAMode: TAntialiasMode = DefaultAAMode; Transformation: TTransformation = nil); overload;
    108 procedure PolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    109   Filler: TCustomPolygonFiller; Mode: TPolyFillMode = pfAlternate;
    110   const AAMode: TAntialiasMode = DefaultAAMode; Transformation: TTransformation = nil); overload;
    111 
    112 procedure PolyPolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    113   Color: TColor32; Mode: TPolyFillMode = pfAlternate; Transformation: TTransformation = nil); overload;
    114 procedure PolyPolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    115   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode = pfAlternate; Transformation: TTransformation = nil); overload;
    116 procedure PolyPolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    117   Filler: TCustomPolygonFiller; Mode: TPolyFillMode = pfAlternate; Transformation: TTransformation = nil); overload;
    118 
    119 procedure PolyPolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    120   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode = pfAlternate;
    121   const AAMode: TAntialiasMode = DefaultAAMode; Transformation: TTransformation = nil); overload;
    122 procedure PolyPolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    123   Color: TColor32; Mode: TPolyFillMode = pfAlternate;
    124   const AAMode: TAntialiasMode = DefaultAAMode; Transformation: TTransformation = nil); overload;
    125 procedure PolyPolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfArrayOfFixedPoint;
    126   Filler: TCustomPolygonFiller; Mode: TPolyFillMode = pfAlternate;
    127   const AAMode: TAntialiasMode = DefaultAAMode; Transformation: TTransformation = nil); overload;
    128 
    129 function PolygonBounds(const Points: TArrayOfFixedPoint; Transformation: TTransformation = nil): TFixedRect;
    130 function PolyPolygonBounds(const Points: TArrayOfArrayOfFixedPoint; Transformation: TTransformation = nil): TFixedRect;
    131 
    132 function PtInPolygon(const Pt: TFixedPoint; const Points: TArrayOfFixedPoint): Boolean;
    133 
    134 { TPolygon32 }
    135 { TODO : Bezier Curves, and QSpline curves for TrueType font rendering }
    136 { TODO : Check if QSpline is compatible with Type1 fonts }
    137 type
    138   TPolygon32 = class(TThreadPersistent)
     145  { TCallbackPolygonFiller }
     146  TCallbackPolygonFiller = class(TCustomPolygonFiller)
    139147  private
    140     FAntialiased: Boolean;
    141     FClosed: Boolean;
    142     FFillMode: TPolyFillMode;
    143     FNormals: TArrayOfArrayOfFixedPoint;
    144     FPoints: TArrayOfArrayOfFixedPoint;
    145     FAntialiasMode: TAntialiasMode;
     148    FFillLineEvent: TFillLineEvent;
    146149  protected
    147     procedure BuildNormals;
    148     procedure CopyPropertiesTo(Dst: TPolygon32); virtual;
    149     procedure AssignTo(Dst: TPersistent); override;
     150    function GetFillLine: TFillLineEvent; override;
    150151  public
    151     constructor Create; override;
    152     destructor Destroy; override;
    153     procedure Add(const P: TFixedPoint);
    154     procedure AddPoints(var First: TFixedPoint; Count: Integer);
    155     function  ContainsPoint(const P: TFixedPoint): Boolean;
    156     procedure Clear;
    157     function  Grow(const Delta: TFixed; EdgeSharpness: Single = 0): TPolygon32;
    158 
    159     procedure Draw(Bitmap: TCustomBitmap32; OutlineColor, FillColor: TColor32; Transformation: TTransformation = nil); overload;
    160     procedure Draw(Bitmap: TCustomBitmap32; OutlineColor: TColor32; FillCallback: TFillLineEvent; Transformation: TTransformation = nil); overload;
    161     procedure Draw(Bitmap: TCustomBitmap32; OutlineColor: TColor32; Filler: TCustomPolygonFiller; Transformation: TTransformation = nil); overload;
    162 
    163     procedure DrawEdge(Bitmap: TCustomBitmap32; Color: TColor32; Transformation: TTransformation = nil);
    164 
    165     procedure DrawFill(Bitmap: TCustomBitmap32; Color: TColor32; Transformation: TTransformation = nil); overload;
    166     procedure DrawFill(Bitmap: TCustomBitmap32; FillCallback: TFillLineEvent; Transformation: TTransformation = nil); overload;
    167     procedure DrawFill(Bitmap: TCustomBitmap32; Filler: TCustomPolygonFiller; Transformation: TTransformation = nil); overload;
    168 
    169     procedure NewLine;
    170     procedure Offset(const Dx, Dy: TFixed);
    171     function  Outline: TPolygon32;
    172     procedure Transform(Transformation: TTransformation);
    173     function GetBoundingRect: TFixedRect;
    174 
    175     property Antialiased: Boolean read FAntialiased write FAntialiased;
    176     property AntialiasMode: TAntialiasMode read FAntialiasMode write FAntialiasMode;
    177     property Closed: Boolean read FClosed write FClosed;
    178     property FillMode: TPolyFillMode read FFillMode write FFillMode;
    179 
    180     property Normals: TArrayOfArrayOfFixedPoint read FNormals write FNormals;
    181     property Points: TArrayOfArrayOfFixedPoint read FPoints write FPoints;
     152    property FillLineEvent: TFillLineEvent read FFillLineEvent write FFillLineEvent;
     153  end;
     154
     155  { TInvertPolygonFiller }
     156  TInvertPolygonFiller = class(TCustomPolygonFiller)
     157  protected
     158    function GetFillLine: TFillLineEvent; override;
     159    procedure FillLineBlend(Dst: PColor32; DstX, DstY, Length: Integer;
     160      AlphaValues: PColor32; CombineMode: TCombineMode);
     161  end;
     162
     163  { TClearPolygonFiller }
     164  TClearPolygonFiller = class(TCustomPolygonFiller)
     165  private
     166    FColor: TColor32;
     167  protected
     168    function GetFillLine: TFillLineEvent; override;
     169    procedure FillLineClear(Dst: PColor32; DstX, DstY,
     170      Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
     171  public
     172    constructor Create(Color: TColor32 = $00808080); reintroduce; virtual;
     173
     174    property Color: TColor32 read FColor write FColor;
    182175  end;
    183176
     
    190183  protected
    191184    function GetFillLine: TFillLineEvent; override;
    192     procedure FillLineOpaque(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
    193     procedure FillLineBlend(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
    194     procedure FillLineBlendMasterAlpha(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
    195     procedure FillLineCustomCombine(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
     185    procedure FillLineOpaque(Dst: PColor32; DstX, DstY,
     186      Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
     187    procedure FillLineBlend(Dst: PColor32; DstX, DstY,
     188      Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
     189    procedure FillLineBlendMasterAlpha(Dst: PColor32; DstX, DstY,
     190      Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
     191    procedure FillLineCustomCombine(Dst: PColor32; DstX, DstY,
     192      Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
    196193  public
    197194    property Pattern: TCustomBitmap32 read FPattern write FPattern;
     
    207204    procedure SetSampler(const Value: TCustomSampler);
    208205  protected
     206    procedure SamplerChanged; virtual;
    209207    function GetFillLine: TFillLineEvent; override;
    210     procedure SampleLineOpaque(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
    211 
     208    procedure SampleLineOpaque(Dst: PColor32; DstX, DstY, Length: Integer;
     209      AlphaValues: PColor32; CombineMode: TCombineMode);
     210  public
     211    constructor Create(Sampler: TCustomSampler = nil); reintroduce; virtual;
     212    procedure BeginRendering; override;
     213    procedure EndRendering; override;
    212214    property Sampler: TCustomSampler read FSampler write SetSampler;
    213215  end;
    214    
     216
     217procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     218  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     219  Transformation: TTransformation = nil); overload;
     220procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     221  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     222  Transformation: TTransformation = nil); overload;
     223procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     224  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
     225  Transformation: TTransformation = nil); overload;
     226procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     227  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
     228  Transformation: TTransformation = nil); overload;
     229procedure PolyPolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     230  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     231  Transformation: TTransformation = nil); overload;
     232procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     233  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     234  Transformation: TTransformation = nil); overload;
     235procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     236  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     237  Transformation: TTransformation = nil); overload;
     238procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     239  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     240  Transformation: TTransformation = nil); overload;
     241
     242procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     243  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     244  Transformation: TTransformation = nil); overload;
     245procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     246  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     247  Transformation: TTransformation = nil); overload;
     248procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     249  ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
     250  Transformation: TTransformation = nil); overload;
     251procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     252  ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
     253  Transformation: TTransformation = nil); overload;
     254procedure PolyPolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     255  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     256  Transformation: TTransformation = nil); overload;
     257procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     258  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     259  Transformation: TTransformation = nil); overload;
     260procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     261  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     262  Transformation: TTransformation = nil); overload;
     263procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     264  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     265  Transformation: TTransformation = nil); overload;
     266
     267
     268procedure PolyPolylineFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     269  Color: TColor32; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
     270  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     271  MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
     272procedure PolyPolylineFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     273  Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
     274  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     275  MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
     276
     277procedure PolylineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     278  Color: TColor32; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
     279  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     280  MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
     281procedure PolylineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     282  Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
     283  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     284  MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil); overload;
     285
     286//Filled only Dashes ...
     287procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     288  const Dashes: TArrayOfFloat; Color: TColor32;
     289  Closed: Boolean = False; Width: TFloat = 1.0); overload;
     290procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     291  const Dashes: TArrayOfFloat; FillColor, StrokeColor: TColor32;
     292  Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0); overload;
     293//Filled and stroked Dashes ...
     294procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     295  const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller;
     296  Closed: Boolean = False; Width: TFloat = 1.0); overload;
     297procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     298  const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller; StrokeColor: TColor32;
     299  Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0); overload;
     300
     301procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     302  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     303  Transformation: TTransformation = nil); overload;
     304procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     305  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     306  Transformation: TTransformation = nil); overload;
     307procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     308  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
     309  Transformation: TTransformation = nil); overload;
     310procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     311  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate;
     312  Transformation: TTransformation = nil); overload;
     313procedure PolyPolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     314  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     315  Transformation: TTransformation = nil); overload;
     316procedure PolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     317  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     318  Transformation: TTransformation = nil);
     319procedure PolyPolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     320  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     321  Transformation: TTransformation = nil); overload;
     322procedure PolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     323  Color: TColor32; FillMode: TPolyFillMode = pfAlternate;
     324  Transformation: TTransformation = nil);
     325
     326procedure PolyPolylineXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     327  Color: TColor32; Closed: Boolean = False; StrokeWidth: TFixed = $10000;
     328  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     329  MiterLimit: TFixed = $40000; Transformation: TTransformation = nil); overload;
     330procedure PolyPolylineXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     331  Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFixed = $10000;
     332  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     333  MiterLimit: TFixed = $40000; Transformation: TTransformation = nil); overload;
     334
     335procedure PolylineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     336  Color: TColor32; Closed: Boolean = False; StrokeWidth: TFixed = $10000;
     337  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     338  MiterLimit: TFixed = $40000; Transformation: TTransformation = nil); overload;
     339procedure PolylineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     340  Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFixed = $10000;
     341  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     342  MiterLimit: TFixed = $40000; Transformation: TTransformation = nil); overload;
     343
     344//Filled only Dashes ...
     345procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     346  const Dashes: TArrayOfFixed; Color: TColor32;
     347  Closed: Boolean = False; Width: TFixed = $10000); overload;
     348procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     349  const Dashes: TArrayOfFixed; FillColor, StrokeColor: TColor32;
     350  Closed: Boolean; Width: TFixed; StrokeWidth: TFixed = $20000); overload;
     351//Filled and stroked Dashes ...
     352procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     353  const Dashes: TArrayOfFixed; Filler: TCustomPolygonFiller;
     354  Closed: Boolean = False; Width: TFixed = $10000); overload;
     355procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     356  const Dashes: TArrayOfFixed; Filler: TCustomPolygonFiller; StrokeColor: TColor32;
     357  Closed: Boolean; Width: TFixed; StrokeWidth: TFixed = $20000); overload;
     358
     359// fill entire bitmap with a given polygon filler
     360procedure FillBitmap(Bitmap: TBitmap32; Filler: TCustomPolygonFiller);
     361
     362{ Registration routines }
     363procedure RegisterPolygonRenderer(PolygonRendererClass: TCustomPolygonRendererClass);
     364
     365var
     366  PolygonRendererList: TClassList;
     367  DefaultPolygonRendererClass: TPolygonRenderer32Class = TPolygonRenderer32VPR;
     368
    215369implementation
    216370
    217 uses Math;
     371uses
     372  Math, SysUtils, GR32_Math, GR32_LowLevel, GR32_Blend, GR32_Gamma,
     373  GR32_VectorUtils;
     374
     375resourcestring
     376  RCStrNoSamplerSpecified = 'No sampler specified!';
    218377
    219378type
    220   TCustomBitmap32Access = class(TCustomBitmap32);
    221   TShiftFunc = function(Value: Integer): Integer;  // needed for antialiasing to speed things up
    222 // These are for edge scan info. Note, that the most significant bit of the
    223 // edge in a scan line is used for winding (edge direction) info.
    224 
    225   TEdgePoint = Integer;
    226 
    227   PEdgePoints = ^TEdgePoints;
    228   TEdgePoints = array [0..MaxListSize-1] of TEdgePoint;
    229 
    230   PScanLine = ^TScanLine;
    231   TScanLine = record
    232     Count: Integer;
    233     EdgePoints: PEdgePoints;
    234     EdgePointsLength: Integer;
    235   end;
    236 
    237   TScanLines = array of TScanLine;
    238 
    239 const
    240   AA_LINES: Array[TAntialiasMode] of Integer = (32, 16, 8, 4, 2, 1);
    241   AA_SHIFT: Array[TAntialiasMode] of Integer = (5, 4, 3, 2, 1, 0);
    242   AA_MULTI: Array[TAntialiasMode] of Integer = (65, 273, 1167, 5460, 32662, 0);
    243 
    244 { POLYLINES }
    245 
    246 procedure PolylineTS(
    247   Bitmap: TCustomBitmap32;
    248   const Points: TArrayOfFixedPoint;
    249   Color: TColor32;
    250   Closed: Boolean;
     379  TBitmap32Access = class(TBitmap32);
     380
     381procedure RegisterPolygonRenderer(PolygonRendererClass: TCustomPolygonRendererClass);
     382begin
     383  if not Assigned(PolygonRendererList) then PolygonRendererList := TClassList.Create;
     384  PolygonRendererList.Add(PolygonRendererClass);
     385end;
     386
     387// routines for color filling:
     388
     389procedure MakeAlphaNonZeroUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
     390  Count: Integer; Color: TColor32);
     391var
     392  I: Integer;
     393  M, V: Cardinal;
     394  Last: TFloat;
     395  C: TColor32Entry absolute Color;
     396begin
     397  M := C.A * $101;
     398  Last := Infinity;
     399  for I := 0 to Count - 1 do
     400  begin
     401    if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
     402    begin
     403      Last := Coverage[I];
     404      V := Abs(Round(Last * $10000));
     405      if V > $10000 then V := $10000;
     406      V := V * M shr 24;
     407{$IFDEF USEGR32GAMMA}
     408      V := GAMMA_ENCODING_TABLE[V];
     409{$ENDIF}
     410      C.A := V;
     411    end;
     412    AlphaValues[I] := Color;
     413  end;
     414end;
     415
     416(*
     417procedure MakeAlphaNonZeroUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
     418  Count: Integer; Color: TColor32);
     419var
     420  I: Integer;
     421  M, V, C: Cardinal;
     422begin
     423  M := Color shr 24 * $101;
     424  C := Color and $00ffffff;
     425  for I := 0 to Count - 1 do
     426  begin
     427    V := Abs(Round(Coverage[I] * $10000));
     428    if V > $10000 then V := $10000;
     429{$IFDEF USEGR32GAMMA}
     430    V := GAMMA_ENCODING_TABLE[V * M shr 24];
     431    AlphaValues[I] := (V shl 24) or C;
     432{$ELSE}
     433    AlphaValues[I] := (V * M and $ff000000) or C;
     434{$ENDIF}
     435  end;
     436end;
     437*)
     438
     439procedure MakeAlphaEvenOddUP(Coverage: PSingleArray; AlphaValues: PColor32Array;
     440  Count: Integer; Color: TColor32);
     441var
     442  I: Integer;
     443  M, V: Cardinal;
     444  Last: TFloat;
     445  C: TColor32Entry absolute Color;
     446begin
     447  M := C.A * $101;
     448  Last := Infinity;
     449  for I := 0 to Count - 1 do
     450  begin
     451    if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
     452    begin
     453      Last := Coverage[I];
     454      V := Abs(Round(Coverage[I] * $10000));
     455      V := V and $01ffff;
     456      if V >= $10000 then
     457        V := V xor $1ffff;
     458      V := V * M shr 24;
     459{$IFDEF USEGR32GAMMA}
     460      V := GAMMA_ENCODING_TABLE[V];
     461{$ENDIF}
     462      C.A := V;
     463    end;
     464    AlphaValues[I] := Color;
     465  end;
     466end;
     467
     468procedure MakeAlphaNonZeroP(Value: Single; AlphaValues: PColor32Array;
     469  Count: Integer; Color: TColor32);
     470var
     471  M, V: Cardinal;
     472  C: TColor32Entry absolute Color;
     473begin
     474  M := C.A * $101;
     475  V := Abs(Round(Value * $10000));
     476  if V > $10000 then V := $10000;
     477  V := V * M shr 24;
     478{$IFDEF USEGR32GAMMA}
     479  V := GAMMA_ENCODING_TABLE[V];
     480{$ENDIF}
     481  C.A := V;
     482  FillLongWord(AlphaValues[0], Count, Color);
     483end;
     484
     485procedure MakeAlphaEvenOddP(Value: Single; AlphaValues: PColor32Array;
     486  Count: Integer; Color: TColor32);
     487var
     488  M, V: Cardinal;
     489  C: TColor32Entry absolute Color;
     490begin
     491  M := C.A * $101;
     492  V := Abs(Round(Value * $10000));
     493  V := V and $01ffff;
     494  if V > $10000 then V := V xor $1ffff;
     495  V := V * M shr 24;
     496{$IFDEF USEGR32GAMMA}
     497  V := GAMMA_ENCODING_TABLE[V];
     498{$ENDIF}
     499  C.A := V;
     500  FillLongWord(AlphaValues[0], Count, Color);
     501end;
     502
     503
     504// polygon filler routines (extract alpha only):
     505
     506procedure MakeAlphaNonZeroUPF(Coverage: PSingleArray; AlphaValues: PColor32Array;
     507  Count: Integer; Color: TColor32);
     508var
     509  I: Integer;
     510  V: Integer;
     511begin
     512  for I := 0 to Count - 1 do
     513  begin
     514    V := Clamp(Round(Abs(Coverage[I]) * 256));
     515{$IFDEF USEGR32GAMMA}
     516    V := GAMMA_ENCODING_TABLE[V];
     517{$ENDIF}
     518    AlphaValues[I] := V;
     519  end;
     520end;
     521
     522procedure MakeAlphaEvenOddUPF(Coverage: PSingleArray; AlphaValues: PColor32Array;
     523  Count: Integer; Color: TColor32);
     524var
     525  I: Integer;
     526  V: Integer;
     527begin
     528  for I := 0 to Count - 1 do
     529  begin
     530    V := Round(Abs(Coverage[I]) * 256);
     531    V := V and $000001ff;
     532    if V >= $100 then V := V xor $1ff;
     533{$IFDEF USEGR32GAMMA}
     534    V := GAMMA_ENCODING_TABLE[V];
     535{$ENDIF}
     536    AlphaValues[I] := V;
     537  end;
     538end;
     539
     540procedure MakeAlphaNonZeroPF(Value: Single; AlphaValues: PColor32Array;
     541  Count: Integer; Color: TColor32);
     542var
     543  V: Integer;
     544begin
     545  V := Clamp(Round(Abs(Value) * 256));
     546{$IFDEF USEGR32GAMMA}
     547    V := GAMMA_ENCODING_TABLE[V];
     548{$ENDIF}
     549  FillLongWord(AlphaValues[0], Count, V);
     550end;
     551
     552procedure MakeAlphaEvenOddPF(Value: Single; AlphaValues: PColor32Array;
     553  Count: Integer; Color: TColor32);
     554var
     555  V: Integer;
     556begin
     557  V := Round(Abs(Value) * 256);
     558  V := V and $000001ff;
     559  if V >= $100 then V := V xor $1ff;
     560{$IFDEF USEGR32GAMMA}
     561    V := GAMMA_ENCODING_TABLE[V];
     562{$ENDIF}
     563  FillLongWord(AlphaValues[0], Count, V);
     564end;
     565
     566procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     567  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     568var
     569  Renderer: TPolygonRenderer32VPR;
     570begin
     571  Renderer := TPolygonRenderer32VPR.Create;
     572  try
     573    Renderer.Bitmap := Bitmap;
     574    Renderer.Color := Color;
     575    Renderer.FillMode := FillMode;
     576    Renderer.PolyPolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     577  finally
     578    Renderer.Free;
     579  end;
     580end;
     581
     582procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     583  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     584var
     585  Renderer: TPolygonRenderer32VPR;
     586begin
     587  Renderer := TPolygonRenderer32VPR.Create;
     588  try
     589    Renderer.Bitmap := Bitmap;
     590    Renderer.Color := Color;
     591    Renderer.FillMode := FillMode;
     592    Renderer.PolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     593  finally
     594    Renderer.Free;
     595  end;
     596end;
     597
     598procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     599  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation);
     600var
     601  Renderer: TPolygonRenderer32VPR;
     602begin
     603  if not Assigned(Filler) then Exit;
     604  Renderer := TPolygonRenderer32VPR.Create;
     605  try
     606    Renderer.Bitmap := Bitmap;
     607    Renderer.Filler := Filler;
     608    Renderer.FillMode := FillMode;
     609    Renderer.PolyPolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     610  finally
     611    Renderer.Free;
     612  end;
     613end;
     614
     615procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     616  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation);
     617var
     618  Renderer: TPolygonRenderer32VPR;
     619begin
     620  if not Assigned(Filler) then Exit;
     621  Renderer := TPolygonRenderer32VPR.Create;
     622  try
     623    Renderer.Bitmap := Bitmap;
     624    Renderer.Filler := Filler;
     625    Renderer.FillMode := FillMode;
     626    Renderer.PolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     627  finally
     628    Renderer.Free;
     629  end;
     630end;
     631
     632procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     633  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     634var
     635  Renderer: TPolygonRenderer32LCD;
     636begin
     637  Renderer := TPolygonRenderer32LCD.Create;
     638  try
     639    Renderer.Bitmap := Bitmap;
     640    Renderer.FillMode := FillMode;
     641    Renderer.Color := Color;
     642    Renderer.PolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     643  finally
     644    Renderer.Free;
     645  end;
     646end;
     647
     648procedure PolyPolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     649  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     650var
     651  Renderer: TPolygonRenderer32LCD;
     652begin
     653  Renderer := TPolygonRenderer32LCD.Create;
     654  try
     655    Renderer.Bitmap := Bitmap;
     656    Renderer.FillMode := FillMode;
     657    Renderer.Color := Color;
     658    Renderer.PolyPolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     659  finally
     660    Renderer.Free;
     661  end;
     662end;
     663
     664procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     665  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     666var
     667  Renderer: TPolygonRenderer32LCD2;
     668begin
     669  Renderer := TPolygonRenderer32LCD2.Create;
     670  try
     671    Renderer.Bitmap := Bitmap;
     672    Renderer.FillMode := FillMode;
     673    Renderer.Color := Color;
     674    Renderer.PolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     675  finally
     676    Renderer.Free;
     677  end;
     678end;
     679
     680procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     681  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     682var
     683  Renderer: TPolygonRenderer32LCD2;
     684begin
     685  Renderer := TPolygonRenderer32LCD2.Create;
     686  try
     687    Renderer.Bitmap := Bitmap;
     688    Renderer.FillMode := FillMode;
     689    Renderer.Color := Color;
     690    Renderer.PolyPolygonFS(Points, FloatRect(Bitmap.ClipRect), Transformation);
     691  finally
     692    Renderer.Free;
     693  end;
     694end;
     695
     696procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     697  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode;
    251698  Transformation: TTransformation);
    252699var
    253   I, Count: Integer;
    254   DoAlpha: Boolean;
    255 begin
    256   Count := Length(Points);
    257 
    258   if (Count = 1) and Closed then
    259     if Assigned(Transformation) then
    260       with Transformation.Transform(Points[0]) do
    261         Bitmap.SetPixelTS(FixedRound(X), FixedRound(Y), Color)
     700  Renderer: TPolygonRenderer32VPR;
     701  IntersectedClipRect: TRect;
     702begin
     703  Renderer := TPolygonRenderer32VPR.Create;
     704  try
     705    Renderer.Bitmap := Bitmap;
     706    Renderer.Color := Color;
     707    Renderer.FillMode := FillMode;
     708    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     709    Renderer.PolyPolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     710  finally
     711    Renderer.Free;
     712  end;
     713end;
     714
     715procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     716  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode;
     717  Transformation: TTransformation);
     718var
     719  Renderer: TPolygonRenderer32VPR;
     720  IntersectedClipRect: TRect;
     721begin
     722  Renderer := TPolygonRenderer32VPR.Create;
     723  try
     724    Renderer.Bitmap := Bitmap;
     725    Renderer.Color := Color;
     726    Renderer.FillMode := FillMode;
     727    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     728    Renderer.PolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     729  finally
     730    Renderer.Free;
     731  end;
     732end;
     733
     734procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     735  ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode;
     736  Transformation: TTransformation);
     737var
     738  Renderer: TPolygonRenderer32VPR;
     739  IntersectedClipRect: TRect;
     740begin
     741  if not Assigned(Filler) then Exit;
     742  Renderer := TPolygonRenderer32VPR.Create;
     743  try
     744    Renderer.Bitmap := Bitmap;
     745    Renderer.Filler := Filler;
     746    Renderer.FillMode := FillMode;
     747    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     748    Renderer.PolyPolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     749  finally
     750    Renderer.Free;
     751  end;
     752end;
     753
     754procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     755  ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode;
     756  Transformation: TTransformation);
     757var
     758  Renderer: TPolygonRenderer32VPR;
     759  IntersectedClipRect: TRect;
     760begin
     761  if not Assigned(Filler) then Exit;
     762  Renderer := TPolygonRenderer32VPR.Create;
     763  try
     764    Renderer.Bitmap := Bitmap;
     765    Renderer.Filler := Filler;
     766    Renderer.FillMode := FillMode;
     767    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     768    Renderer.PolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     769  finally
     770    Renderer.Free;
     771  end;
     772end;
     773
     774procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     775  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode;
     776  Transformation: TTransformation);
     777var
     778  Renderer: TPolygonRenderer32LCD;
     779  IntersectedClipRect: TRect;
     780begin
     781  Renderer := TPolygonRenderer32LCD.Create;
     782  try
     783    Renderer.Bitmap := Bitmap;
     784    Renderer.FillMode := FillMode;
     785    Renderer.Color := Color;
     786    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     787    Renderer.PolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     788  finally
     789    Renderer.Free;
     790  end;
     791end;
     792
     793procedure PolyPolygonFS_LCD(Bitmap: TBitmap32;
     794  const Points: TArrayOfArrayOfFloatPoint; ClipRect: TRect; Color: TColor32;
     795  FillMode: TPolyFillMode; Transformation: TTransformation);
     796var
     797  Renderer: TPolygonRenderer32LCD;
     798  IntersectedClipRect: TRect;
     799begin
     800  Renderer := TPolygonRenderer32LCD.Create;
     801  try
     802    Renderer.Bitmap := Bitmap;
     803    Renderer.FillMode := FillMode;
     804    Renderer.Color := Color;
     805    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     806    Renderer.PolyPolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     807  finally
     808    Renderer.Free;
     809  end;
     810end;
     811
     812procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     813  ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode;
     814  Transformation: TTransformation);
     815var
     816  Renderer: TPolygonRenderer32LCD2;
     817  IntersectedClipRect: TRect;
     818begin
     819  Renderer := TPolygonRenderer32LCD2.Create;
     820  try
     821    Renderer.Bitmap := Bitmap;
     822    Renderer.FillMode := FillMode;
     823    Renderer.Color := Color;
     824    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     825    Renderer.PolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     826  finally
     827    Renderer.Free;
     828  end;
     829end;
     830
     831procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32;
     832  const Points: TArrayOfArrayOfFloatPoint; ClipRect: TRect; Color: TColor32;
     833  FillMode: TPolyFillMode; Transformation: TTransformation);
     834var
     835  Renderer: TPolygonRenderer32LCD2;
     836  IntersectedClipRect: TRect;
     837begin
     838  Renderer := TPolygonRenderer32LCD2.Create;
     839  try
     840    Renderer.Bitmap := Bitmap;
     841    Renderer.FillMode := FillMode;
     842    Renderer.Color := Color;
     843    GR32.IntersectRect(IntersectedClipRect, Bitmap.ClipRect, ClipRect);
     844    Renderer.PolyPolygonFS(Points, FloatRect(IntersectedClipRect), Transformation);
     845  finally
     846    Renderer.Free;
     847  end;
     848end;
     849
     850procedure PolyPolylineFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     851  Color: TColor32; Closed: Boolean; StrokeWidth: TFloat;
     852  JoinStyle: TJoinStyle; EndStyle: TEndStyle;
     853  MiterLimit: TFloat; Transformation: TTransformation);
     854var
     855  Dst: TArrayOfArrayOfFloatPoint;
     856begin
     857  Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, MiterLimit);
     858  PolyPolygonFS(Bitmap, Dst, Color, pfWinding, Transformation);
     859end;
     860
     861procedure PolyPolylineFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint;
     862  Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
     863  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     864  MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil);
     865var
     866  Dst: TArrayOfArrayOfFloatPoint;
     867begin
     868  Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, MiterLimit);
     869  PolyPolygonFS(Bitmap, Dst, Filler, pfWinding, Transformation);
     870end;
     871
     872procedure PolylineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     873  Color: TColor32; Closed: Boolean; StrokeWidth: TFloat;
     874  JoinStyle: TJoinStyle; EndStyle: TEndStyle;
     875  MiterLimit: TFloat; Transformation: TTransformation);
     876begin
     877  PolyPolylineFS(Bitmap, PolyPolygon(Points), Color, Closed, StrokeWidth,
     878    JoinStyle, EndStyle, MiterLimit, Transformation);
     879end;
     880
     881procedure PolylineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     882  Filler: TCustomPolygonFiller; Closed: Boolean = False; StrokeWidth: TFloat = 1.0;
     883  JoinStyle: TJoinStyle = jsMiter; EndStyle: TEndStyle = esButt;
     884  MiterLimit: TFloat = 4.0; Transformation: TTransformation = nil);
     885begin
     886  PolyPolylineFS(Bitmap, PolyPolygon(Points), Filler, Closed, StrokeWidth,
     887    JoinStyle, EndStyle, MiterLimit, Transformation);
     888end;
     889
     890procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     891  const Dashes: TArrayOfFloat; Color: TColor32;
     892  Closed: Boolean = False; Width: TFloat = 1.0);
     893var
     894  MultiPoly: TArrayOfArrayOfFloatPoint;
     895begin
     896  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     897  PolyPolylineFS(Bitmap, MultiPoly, Color, False, Width);
     898end;
     899
     900procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     901  const Dashes: TArrayOfFloat; FillColor, StrokeColor: TColor32;
     902  Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0);
     903var
     904  MultiPoly: TArrayOfArrayOfFloatPoint;
     905begin
     906  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     907  MultiPoly := BuildPolyPolyLine(MultiPoly, False, Width);
     908  PolyPolygonFS(Bitmap, MultiPoly, FillColor);
     909  PolyPolylineFS(Bitmap, MultiPoly, StrokeColor, True, StrokeWidth);
     910end;
     911
     912procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     913  const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller;
     914  Closed: Boolean = False; Width: TFloat = 1.0);
     915var
     916  MultiPoly: TArrayOfArrayOfFloatPoint;
     917begin
     918  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     919  PolyPolylineFS(Bitmap, MultiPoly, Filler, False, Width);
     920end;
     921
     922procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint;
     923  const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller; StrokeColor: TColor32;
     924  Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0);
     925var
     926  MultiPoly: TArrayOfArrayOfFloatPoint;
     927begin
     928  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     929  MultiPoly := BuildPolyPolyLine(MultiPoly, False, Width);
     930  PolyPolygonFS(Bitmap, MultiPoly, Filler);
     931  PolyPolylineFS(Bitmap, MultiPoly, StrokeColor, True, StrokeWidth);
     932end;
     933
     934
     935procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     936  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     937var
     938  Renderer: TPolygonRenderer32VPR;
     939begin
     940  Renderer := TPolygonRenderer32VPR.Create;
     941  try
     942    Renderer.Bitmap := Bitmap;
     943    Renderer.Color := Color;
     944    Renderer.FillMode := FillMode;
     945    Renderer.PolyPolygonFS(FixedPointToFloatPoint(Points),
     946      FloatRect(Bitmap.ClipRect), Transformation);
     947  finally
     948    Renderer.Free;
     949  end;
     950end;
     951
     952procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     953  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     954var
     955  Renderer: TPolygonRenderer32VPR;
     956begin
     957  Renderer := TPolygonRenderer32VPR.Create;
     958  try
     959    Renderer.Bitmap := Bitmap;
     960    Renderer.Color := Color;
     961    Renderer.FillMode := FillMode;
     962    Renderer.PolygonFS(FixedPointToFloatPoint(Points),
     963      FloatRect(Bitmap.ClipRect), Transformation);
     964  finally
     965    Renderer.Free;
     966  end;
     967end;
     968
     969procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     970  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation);
     971var
     972  Renderer: TPolygonRenderer32VPR;
     973begin
     974  Renderer := TPolygonRenderer32VPR.Create;
     975  try
     976    Renderer.Bitmap := Bitmap;
     977    Renderer.Filler := Filler;
     978    Renderer.FillMode := FillMode;
     979    Renderer.PolyPolygonFS(FixedPointToFloatPoint(Points),
     980      FloatRect(Bitmap.ClipRect), Transformation);
     981  finally
     982    Renderer.Free;
     983  end;
     984end;
     985
     986procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     987  Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation);
     988var
     989  Renderer: TPolygonRenderer32VPR;
     990begin
     991  Renderer := TPolygonRenderer32VPR.Create;
     992  try
     993    Renderer.Bitmap := Bitmap;
     994    Renderer.Filler := Filler;
     995    Renderer.FillMode := FillMode;
     996    Renderer.PolygonFS(FixedPointToFloatPoint(Points),
     997      FloatRect(Bitmap.ClipRect), Transformation);
     998  finally
     999    Renderer.Free;
     1000  end;
     1001end;
     1002
     1003procedure PolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1004  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     1005var
     1006  Renderer: TPolygonRenderer32LCD;
     1007begin
     1008  Renderer := TPolygonRenderer32LCD.Create;
     1009  try
     1010    Renderer.Bitmap := Bitmap;
     1011    Renderer.FillMode := FillMode;
     1012    Renderer.Color := Color;
     1013    Renderer.PolygonFS(FixedPointToFloatPoint(Points),
     1014      FloatRect(Bitmap.ClipRect), Transformation);
     1015  finally
     1016    Renderer.Free;
     1017  end;
     1018end;
     1019
     1020procedure PolyPolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     1021  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     1022var
     1023  Renderer: TPolygonRenderer32LCD;
     1024begin
     1025  Renderer := TPolygonRenderer32LCD.Create;
     1026  try
     1027    Renderer.Bitmap := Bitmap;
     1028    Renderer.FillMode := FillMode;
     1029    Renderer.Color := Color;
     1030    Renderer.PolyPolygonFS(FixedPointToFloatPoint(Points),
     1031      FloatRect(Bitmap.ClipRect), Transformation);
     1032  finally
     1033    Renderer.Free;
     1034  end;
     1035end;
     1036
     1037procedure PolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1038  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     1039var
     1040  Renderer: TPolygonRenderer32LCD2;
     1041begin
     1042  Renderer := TPolygonRenderer32LCD2.Create;
     1043  try
     1044    Renderer.Bitmap := Bitmap;
     1045    Renderer.FillMode := FillMode;
     1046    Renderer.Color := Color;
     1047    Renderer.PolygonFS(FixedPointToFloatPoint(Points),
     1048      FloatRect(Bitmap.ClipRect), Transformation);
     1049  finally
     1050    Renderer.Free;
     1051  end;
     1052end;
     1053
     1054procedure PolyPolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     1055  Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation);
     1056var
     1057  Renderer: TPolygonRenderer32LCD2;
     1058begin
     1059  Renderer := TPolygonRenderer32LCD2.Create;
     1060  try
     1061    Renderer.Bitmap := Bitmap;
     1062    Renderer.FillMode := FillMode;
     1063    Renderer.Color := Color;
     1064    Renderer.PolyPolygonFS(FixedPointToFloatPoint(Points),
     1065      FloatRect(Bitmap.ClipRect), Transformation);
     1066  finally
     1067    Renderer.Free;
     1068  end;
     1069end;
     1070
     1071procedure PolyPolylineXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     1072  Color: TColor32; Closed: Boolean; StrokeWidth: TFixed;
     1073  JoinStyle: TJoinStyle; EndStyle: TEndStyle;
     1074  MiterLimit: TFixed; Transformation: TTransformation);
     1075var
     1076  Dst: TArrayOfArrayOfFixedPoint;
     1077begin
     1078  Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle,
     1079    MiterLimit);
     1080  PolyPolygonXS(Bitmap, Dst, Color, pfWinding, Transformation);
     1081end;
     1082
     1083procedure PolyPolylineXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint;
     1084  Filler: TCustomPolygonFiller; Closed: Boolean = False;
     1085  StrokeWidth: TFixed = $10000; JoinStyle: TJoinStyle = jsMiter;
     1086  EndStyle: TEndStyle = esButt; MiterLimit: TFixed = $40000;
     1087  Transformation: TTransformation = nil);
     1088var
     1089  Dst: TArrayOfArrayOfFixedPoint;
     1090begin
     1091  Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle,
     1092    MiterLimit);
     1093  PolyPolygonXS(Bitmap, Dst, Filler, pfWinding, Transformation);
     1094end;
     1095
     1096procedure PolylineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1097  Color: TColor32; Closed: Boolean; StrokeWidth: TFixed;
     1098  JoinStyle: TJoinStyle; EndStyle: TEndStyle;
     1099  MiterLimit: TFixed; Transformation: TTransformation);
     1100begin
     1101  PolyPolylineXS(Bitmap, PolyPolygon(Points), Color,
     1102    Closed, StrokeWidth, JoinStyle, EndStyle,
     1103    MiterLimit, Transformation);
     1104end;
     1105
     1106procedure PolylineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1107  Filler: TCustomPolygonFiller; Closed: Boolean = False;
     1108  StrokeWidth: TFixed = $10000; JoinStyle: TJoinStyle = jsMiter;
     1109  EndStyle: TEndStyle = esButt; MiterLimit: TFixed = $40000;
     1110  Transformation: TTransformation = nil);
     1111begin
     1112  PolyPolylineXS(Bitmap, PolyPolygon(Points), Filler, Closed, StrokeWidth,
     1113    JoinStyle, EndStyle, MiterLimit, Transformation);
     1114end;
     1115
     1116procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1117  const Dashes: TArrayOfFixed; Color: TColor32;
     1118  Closed: Boolean = False; Width: TFixed = $10000);
     1119var
     1120  MultiPoly: TArrayOfArrayOfFixedPoint;
     1121begin
     1122  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     1123  PolyPolylineXS(Bitmap, MultiPoly, Color, False, Width);
     1124end;
     1125
     1126procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1127  const Dashes: TArrayOfFixed; FillColor, StrokeColor: TColor32;
     1128  Closed: Boolean; Width: TFixed; StrokeWidth: TFixed = $20000);
     1129var
     1130  MultiPoly: TArrayOfArrayOfFixedPoint;
     1131begin
     1132  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     1133  PolyPolylineXS(Bitmap, MultiPoly, FillColor, False, Width);
     1134  MultiPoly := BuildPolyPolyLine(MultiPoly, False, Width);
     1135  PolyPolylineXS(Bitmap, MultiPoly, StrokeColor, True, strokeWidth);
     1136end;
     1137
     1138procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1139  const Dashes: TArrayOfFixed; Filler: TCustomPolygonFiller;
     1140  Closed: Boolean = False; Width: TFixed = $10000);
     1141var
     1142  MultiPoly: TArrayOfArrayOfFixedPoint;
     1143begin
     1144  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     1145  PolyPolylineXS(Bitmap, MultiPoly, Filler, False, Width);
     1146end;
     1147
     1148procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint;
     1149  const Dashes: TArrayOfFixed; Filler: TCustomPolygonFiller; StrokeColor: TColor32;
     1150  Closed: Boolean; Width: TFixed; StrokeWidth: TFixed = $20000);
     1151var
     1152  MultiPoly: TArrayOfArrayOfFixedPoint;
     1153begin
     1154  MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed);
     1155  PolyPolylineXS(Bitmap, MultiPoly, Filler, False, Width);
     1156  MultiPoly := BuildPolyPolyLine(MultiPoly, False, Width);
     1157  PolyPolylineXS(Bitmap, MultiPoly, StrokeColor, True, StrokeWidth);
     1158end;
     1159
     1160procedure FillBitmap(Bitmap: TBitmap32; Filler: TCustomPolygonFiller);
     1161var
     1162  AlphaValues: PColor32;
     1163  Y: Integer;
     1164begin
     1165  {$IFDEF USESTACKALLOC}
     1166  AlphaValues := StackAlloc(Bitmap.Width * SizeOf(TColor32));
     1167  {$ELSE}
     1168  GetMem(AlphaValues, Bitmap.Width * SizeOf(TColor32));
     1169  {$ENDIF}
     1170  FillLongword(AlphaValues^, Bitmap.Width, $FF);
     1171  Filler.BeginRendering;
     1172  for Y := 0 to Bitmap.Height - 1 do
     1173    Filler.FillLine(PColor32(Bitmap.ScanLine[y]), 0, y, Bitmap.Width,
     1174      AlphaValues, Bitmap.CombineMode);
     1175  Filler.EndRendering;
     1176  {$IFDEF USESTACKALLOC}
     1177  StackFree(AlphaValues);
     1178  {$ELSE}
     1179  FreeMem(AlphaValues);
     1180  {$ENDIF}
     1181end;
     1182
     1183
     1184{ LCD sub-pixel rendering (see http://www.grc.com/cttech.htm) }
     1185
     1186type
     1187  PRGBTriple = ^TRGBTriple;
     1188  TRGBTriple = packed record
     1189    B, G, R: Byte;
     1190  end;
     1191
     1192  PRGBTripleArray = ^TRGBTripleArray;
     1193  TRGBTripleArray = array [0..0] of TRGBTriple;
     1194
     1195  TMakeAlphaProcLCD = procedure(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray;
     1196    Count: Integer; Color: TColor32);
     1197
     1198procedure MakeAlphaNonZeroLCD(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray;
     1199  Count: Integer; Color: TColor32);
     1200var
     1201  I: Integer;
     1202  M, V: Cardinal;
     1203  Last: TFloat;
     1204  C: TColor32Entry absolute Color;
     1205begin
     1206  M := C.A * 86;  // 86 = 258 / 3
     1207
     1208  Last := Infinity;
     1209  V := 0;
     1210  AlphaValues[0] := 0;
     1211  AlphaValues[1] := 0;
     1212  for I := 0 to Count - 1 do
     1213  begin
     1214    if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
     1215    begin
     1216      Last := Coverage[I];
     1217      V := Abs(Round(Last * $10000));
     1218      if V > $10000 then V := $10000;
     1219      V := V * M shr 24;
     1220    end;
     1221    Inc(AlphaValues[I], V);
     1222{$IFDEF USEGR32GAMMA}
     1223    AlphaValues[I] := GAMMA_ENCODING_TABLE[AlphaValues[I]];
     1224{$ENDIF}
     1225    Inc(AlphaValues[I + 1], V);
     1226    AlphaValues[I + 2] := V;
     1227  end;
     1228  AlphaValues[Count + 2] := 0;
     1229  AlphaValues[Count + 3] := 0;
     1230end;
     1231
     1232procedure MakeAlphaEvenOddLCD(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray;
     1233  Count: Integer; Color: TColor32);
     1234var
     1235  I: Integer;
     1236  M, V: Cardinal;
     1237  Last: TFloat;
     1238begin
     1239  M := Color shr 24 * 86;  // 86 = 258 / 3
     1240
     1241  Last := Infinity;
     1242  V := 0;
     1243  AlphaValues[0] := 0;
     1244  AlphaValues[1] := 0;
     1245  for I := 0 to Count - 1 do
     1246  begin
     1247    if PInteger(@Last)^ <> PInteger(@Coverage[I])^ then
     1248    begin
     1249      Last := Coverage[I];
     1250      V := Abs(Round(Coverage[I] * $10000));
     1251      V := V and $01ffff;
     1252      if V >= $10000 then V := V xor $1ffff;
     1253      V := V * M shr 24;
     1254    end;
     1255    Inc(AlphaValues[I], V);
     1256{$IFDEF USEGR32GAMMA}
     1257    AlphaValues[I] := GAMMA_ENCODING_TABLE[AlphaValues[I]];
     1258{$ENDIF}
     1259    Inc(AlphaValues[I + 1], V);
     1260    AlphaValues[I + 2] := V;
     1261  end;
     1262  AlphaValues[Count + 2] := 0;
     1263  AlphaValues[Count + 3] := 0;
     1264end;
     1265
     1266procedure MakeAlphaNonZeroLCD2(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray;
     1267  Count: Integer; Color: TColor32);
     1268var
     1269  I: Integer;
     1270begin
     1271  MakeAlphaNonZeroLCD(Coverage, AlphaValues, Count, Color);
     1272  AlphaValues[Count + 2] := (AlphaValues[Count] + AlphaValues[Count + 1]) div 3;
     1273  AlphaValues[Count + 3] := AlphaValues[Count + 1] div 3;
     1274  for I := Count + 1 downto 2 do
     1275  begin
     1276    AlphaValues[I] := (AlphaValues[I] + AlphaValues[I - 1] + AlphaValues[I - 2]) div 3;
     1277  end;
     1278  AlphaValues[1] := (AlphaValues[0] + AlphaValues[1]) div 3;
     1279  AlphaValues[0] := AlphaValues[0] div 3;
     1280end;
     1281
     1282procedure MakeAlphaEvenOddLCD2(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray;
     1283  Count: Integer; Color: TColor32);
     1284var
     1285  I: Integer;
     1286begin
     1287  MakeAlphaEvenOddLCD(Coverage, AlphaValues, Count, Color);
     1288  AlphaValues[Count + 2] := (AlphaValues[Count] + AlphaValues[Count + 1]) div 3;
     1289  AlphaValues[Count + 3] := AlphaValues[Count + 1] div 3;
     1290  for I := Count + 1 downto 2 do
     1291  begin
     1292    AlphaValues[I] := (AlphaValues[I] + AlphaValues[I - 1] + AlphaValues[I - 2]) div 3;
     1293  end;
     1294  AlphaValues[1] := (AlphaValues[0] + AlphaValues[1]) div 3;
     1295  AlphaValues[0] := AlphaValues[0] div 3;
     1296end;
     1297
     1298procedure CombineLineLCD(Weights: PRGBTripleArray; Dst: PColor32Array; Color: TColor32; Count: Integer);
     1299var
     1300  I: Integer;
     1301  {$IFDEF TEST_BLENDMEMRGB128SSE4}
     1302  Weights64: UInt64;
     1303  {$ENDIF}
     1304begin
     1305  I := 0;
     1306  while Count <> 0 do
     1307    {$IFDEF TEST_BLENDMEMRGB128SSE4}
     1308    if (Count shr 1) = 0 then
     1309    {$ENDIF}
     1310    begin
     1311      if PColor32(@Weights[I])^ = $FFFFFFFF then
     1312        Dst[I] := Color
     1313      else
     1314        BlendMemRGB(Color, Dst[I], PColor32(@Weights[I])^);
     1315      Dec(Count);
     1316      Inc(I);
     1317    end
     1318    {$IFDEF TEST_BLENDMEMRGB128SSE4}
    2621319    else
    263       with Points[0] do
    264         Bitmap.SetPixelTS(FixedRound(X), FixedRound(Y), Color);
    265 
    266   if Count < 2 then Exit;
    267   DoAlpha := Color and $FF000000 <> $FF000000;
    268   Bitmap.BeginUpdate;
    269   Bitmap.PenColor := Color;
    270 
    271   if Assigned(Transformation) then
    272   begin
    273     with Transformation.Transform(Points[0]) do Bitmap.MoveTo(FixedRound(X), FixedRound(Y));
    274     if DoAlpha then
    275       for I := 1 to Count - 1 do
    276         with Transformation.Transform(Points[I]) do
    277           Bitmap.LineToTS(FixedRound(X), FixedRound(Y))
    278     else
    279       for I := 1 to Count - 1 do
    280         with Transformation.Transform(Points[I]) do
    281           Bitmap.LineToS(FixedRound(X), FixedRound(Y));
    282 
    283     if Closed then with Transformation.Transform(Points[0]) do
    284       if DoAlpha then
    285         Bitmap.LineToTS(FixedRound(X), FixedRound(Y))
    286       else
    287         Bitmap.LineToS(FixedRound(X), FixedRound(Y));
    288   end
    289   else
    290   begin
    291     with Points[0] do Bitmap.MoveTo(FixedRound(X), FixedRound(Y));
    292     if DoAlpha then
    293       for I := 1 to Count - 1 do
    294         with Points[I] do
    295           Bitmap.LineToTS(FixedRound(X), FixedRound(Y))
    296     else
    297       for I := 1 to Count - 1 do
    298         with Points[I] do
    299           Bitmap.LineToS(FixedRound(X), FixedRound(Y));
    300 
    301     if Closed then with Points[0] do
    302       if DoAlpha then
    303         Bitmap.LineToTS(FixedRound(X), FixedRound(Y))
    304       else
    305         Bitmap.LineToS(FixedRound(X), FixedRound(Y));
    306   end;
    307 
    308   Bitmap.EndUpdate;
    309   Bitmap.Changed;
    310 end;
    311 
    312 procedure PolylineAS(
    313   Bitmap: TCustomBitmap32;
    314   const Points: TArrayOfFixedPoint;
    315   Color: TColor32;
    316   Closed: Boolean;
    317   Transformation: TTransformation);
    318 var
    319   I, Count: Integer;
    320 begin
    321   Count := Length(Points);
    322   if (Count = 1) and Closed then
    323     if Assigned(Transformation) then
    324       with Transformation.Transform(Points[0]) do
    325         Bitmap.SetPixelTS(FixedRound(X), FixedRound(Y), Color)
    326     else
    327       with Points[0] do
    328         Bitmap.SetPixelTS(FixedRound(X), FixedRound(Y), Color);
    329 
    330   if Count < 2 then Exit;
    331   Bitmap.BeginUpdate;
    332   Bitmap.PenColor := Color;
    333 
    334   if Assigned(Transformation) then
    335   begin
    336     with Transformation.Transform(Points[0]) do Bitmap.MoveTo(FixedRound(X), FixedRound(Y));
    337     for I := 1 to Count - 1 do
    338       with Transformation.Transform(Points[I]) do
    339         Bitmap.LineToAS(FixedRound(X), FixedRound(Y));
    340     if Closed then with Transformation.Transform(Points[0]) do Bitmap.LineToAS(FixedRound(X), FixedRound(Y));
    341   end
    342   else
    343   begin
    344     with Points[0] do Bitmap.MoveTo(FixedRound(X), FixedRound(Y));
    345     for I := 1 to Count - 1 do
    346       with Points[I] do
    347         Bitmap.LineToAS(FixedRound(X), FixedRound(Y));
    348     if Closed then with Points[0] do Bitmap.LineToAS(FixedRound(X), FixedRound(Y));
    349   end;
    350 
    351   Bitmap.EndUpdate;
    352   Bitmap.Changed;
    353 end;
    354 
    355 procedure PolylineXS(
    356   Bitmap: TCustomBitmap32;
    357   const Points: TArrayOfFixedPoint;
    358   Color: TColor32;
    359   Closed: Boolean;
    360   Transformation: TTransformation);
    361 var
    362   I, Count: Integer;
    363 begin
    364   Count := Length(Points);
    365   if (Count = 1) and Closed then
    366     if Assigned(Transformation) then
    367       with Transformation.Transform(Points[0]) do Bitmap.PixelXS[X, Y] := Color
    368     else
    369       with Points[0] do Bitmap.PixelXS[X, Y] := Color;
    370 
    371   if Count < 2 then Exit;
    372   Bitmap.BeginUpdate;
    373   Bitmap.PenColor := Color;
    374 
    375   if Assigned(Transformation) then
    376   begin
    377     with Transformation.Transform(Points[0]) do Bitmap.MoveToX(X, Y);
    378     for I := 1 to Count - 1 do with Transformation.Transform(Points[I]) do Bitmap.LineToXS(X, Y);
    379     if Closed then with Transformation.Transform(Points[0]) do Bitmap.LineToXS(X, Y);
    380   end
    381   else
    382   begin
    383     with Points[0] do Bitmap.MoveToX(X, Y);
    384     for I := 1 to Count - 1 do with Points[I] do Bitmap.LineToXS(X, Y);
    385     if Closed then with Points[0] do Bitmap.LineToXS(X, Y);
    386   end;
    387 
    388   Bitmap.EndUpdate;
    389   Bitmap.Changed;
    390 end;
    391 
    392 procedure PolylineXSP(
    393   Bitmap: TCustomBitmap32;
    394   const Points: TArrayOfFixedPoint;
    395   Closed: Boolean;
    396   Transformation: TTransformation);
    397 var
    398   I, Count: Integer;
    399 begin
    400   Count := Length(Points);
    401   if Count < 2 then Exit;
    402   Bitmap.BeginUpdate;
    403   if Assigned(Transformation) then
    404   begin
    405     with Transformation.Transform(Points[0]) do Bitmap.MoveToX(X, Y);
    406     for I := 1 to Count - 1 do with Transformation.Transform(Points[I]) do Bitmap.LineToXSP(X, Y);
    407     if Closed then with Transformation.Transform(Points[0]) do Bitmap.LineToXSP(X, Y);
    408   end
    409   else
    410   begin
    411     with Points[0] do Bitmap.MoveToX(X, Y);
    412     for I := 1 to Count - 1 do with Points[I] do Bitmap.LineToXSP(X, Y);
    413     if Closed then with Points[0] do Bitmap.LineToXSP(X, Y);
    414   end;
    415 
    416   Bitmap.EndUpdate;
    417   Bitmap.Changed;
    418 end;
    419 
    420 procedure PolyPolylineTS(
    421   Bitmap: TCustomBitmap32;
    422   const Points: TArrayOfArrayOfFixedPoint;
    423   Color: TColor32;
    424   Closed: Boolean;
    425   Transformation: TTransformation);
    426 var
    427   I: Integer;
    428 begin
    429   for I := 0 to High(Points) do PolylineTS(Bitmap, Points[I], Color, Closed, Transformation);
    430 end;
    431 
    432 procedure PolyPolylineAS(
    433   Bitmap: TCustomBitmap32;
    434   const Points: TArrayOfArrayOfFixedPoint;
    435   Color: TColor32;
    436   Closed: Boolean;
    437   Transformation: TTransformation);
    438 var
    439   I: Integer;
    440 begin
    441   for I := 0 to High(Points) do PolylineAS(Bitmap, Points[I], Color, Closed, Transformation);
    442 end;
    443 
    444 procedure PolyPolylineXS(
    445   Bitmap: TCustomBitmap32;
    446   const Points: TArrayOfArrayOfFixedPoint;
    447   Color: TColor32;
    448   Closed: Boolean;
    449   Transformation: TTransformation);
    450 var
    451   I: Integer;
    452 begin
    453   for I := 0 to High(Points) do PolylineXS(Bitmap, Points[I], Color, Closed, Transformation);
    454 end;
    455 
    456 procedure PolyPolylineXSP(
    457   Bitmap: TCustomBitmap32;
    458   const Points: TArrayOfArrayOfFixedPoint;
    459   Closed: Boolean;
    460   Transformation: TTransformation);
    461 var
    462   I: Integer;
    463 begin
    464   for I := 0 to High(Points) do PolylineXSP(Bitmap, Points[I], Closed, Transformation);
    465 end;
    466 
    467 
    468 { General routines for drawing polygons }
    469 
    470 procedure ScanLinesCreate(var ScanLines: TScanLines; Length: Integer);
    471 begin
    472   SetLength(ScanLines, Length);
    473 end;
    474 
    475 procedure ScanLinesDestroy(var ScanLines: TScanLines);
    476 var
    477   I: Integer;
    478 begin
    479   for I := 0 to High(ScanLines) do
    480     FreeMem(ScanLines[I].EdgePoints);
    481 
    482   SetLength(ScanLines, 0);
    483 end;
    484 
    485 
    486 { Routines for sorting edge points in scanlines }
    487 
    488 const
    489   SortThreshold = 10;
    490   ReallocationThreshold = 64;
    491 
    492 procedure InsertionSort(LPtr, RPtr: PInteger);
    493 var
    494   IPtr, JPtr: PInteger;
    495   Temp: PInteger;
    496   P, C, T: Integer;
    497 begin
    498   IPtr := LPtr;
    499   Inc(IPtr);
    500   repeat
    501     C := IPtr^;
    502     P := C and $7FFFFFFF;
    503     JPtr := IPtr;
    504 
    505 {$IFDEF HAS_NATIVEINT}
    506     if NativeUInt(JPtr) > NativeUInt(LPtr) then
    507 {$ELSE}
    508     if Cardinal(JPtr) > Cardinal(LPtr) then
    509 {$ENDIF}
    510     repeat
    511       Temp := JPtr;
    512       Dec(Temp);
    513       T := Temp^;
    514       if T and $7FFFFFFF > P then
     1320    begin
     1321      Weights64 := (UInt64(PColor32(@Weights[I + 1])^) shl 32) or
     1322        PColor32(@Weights[I])^;
     1323      if Weights64 = $FFFFFFFFFFFFFFFF then
    5151324      begin
    516         JPtr^ := T;
    517         JPtr := Temp;
     1325        Dst[I] := Color;
     1326        Dst[I + 1] := Color;
    5181327      end
    5191328      else
    520         Break;
    521 {$IFDEF HAS_NATIVEINT}
    522     until NativeUInt(JPtr) <= NativeUInt(LPtr);
    523 {$ELSE}
    524     until Cardinal(JPtr) <= Cardinal(LPtr);
    525 {$ENDIF}
    526 
    527     JPtr^ := C;
    528     Inc(IPtr);
    529 {$IFDEF HAS_NATIVEINT}
    530   until NativeUInt(IPtr) > NativeUInt(RPtr);
    531 {$ELSE}
    532   until Cardinal(IPtr) > Cardinal(RPtr);
    533 {$ENDIF}
    534 end;
    535 
    536 procedure QuickSort(LPtr, RPtr: PInteger);
    537 var
    538 {$IFDEF HAS_NATIVEINT}
    539   P: NativeUInt;
    540 {$ELSE}
    541   P: Cardinal;
    542 {$ENDIF}
    543   TempVal: Integer;
    544   IPtr, JPtr: PInteger;
    545   Temp: Integer;
    546 const
    547   OddMask = SizeOf(Integer) and not(SizeOf(Integer) - 1);
    548 begin
    549   {$IFDEF HAS_NATIVEINT}
    550   if NativeUInt(RPtr) - NativeUInt(LPtr) > SortThreshold shl 2 then
    551   {$ELSE}
    552   if Cardinal(RPtr) - Cardinal(LPtr) > SortThreshold shl 2 then
    553   {$ENDIF}
    554   repeat
    555     {$IFDEF HAS_NATIVEINT}
    556     P := NativeUInt(RPtr) - NativeUInt(LPtr);
    557     if (P and OddMask > 0) then Dec(P, SizeOf(Integer));
    558     TempVal := PInteger(NativeUInt(LPtr) + P shr 1)^ and $7FFFFFFF;
    559     {$ELSE}
    560     P := Cardinal(RPtr) - Cardinal(LPtr);
    561     if (P and OddMask > 0) then Dec(P, SizeOf(Integer));
    562     TempVal := PInteger(Cardinal(LPtr) + P shr 1)^ and $7FFFFFFF;
    563     {$ENDIF}
    564 
    565     IPtr := LPtr;
    566     JPtr := RPtr;
    567     repeat
    568       while (IPtr^ and $7FFFFFFF) < TempVal do Inc(IPtr);
    569       while (JPtr^ and $7FFFFFFF) > TempVal do Dec(JPtr);
    570       {$IFDEF HAS_NATIVEINT}
    571       if NativeUInt(IPtr) <= NativeUInt(JPtr) then
    572       {$ELSE}
    573       if Cardinal(IPtr) <= Cardinal(JPtr) then
    574       {$ENDIF}
    575       begin
    576         Temp := IPtr^;
    577         IPtr^ := JPtr^;
    578         JPtr^ := Temp;
    579 //        Swap(IPtr^, JPtr^);
    580         Inc(IPtr);
    581         Dec(JPtr);
    582       end;
    583     {$IFDEF HAS_NATIVEINT}
    584     until NativeUInt(IPtr) > NativeUInt(JPtr);
    585     if NativeUInt(LPtr) < NativeUInt(JPtr) then
    586     {$ELSE}
    587     until Integer(IPtr) > Integer(JPtr);
    588     if Cardinal(LPtr) < Cardinal(JPtr) then
    589     {$ENDIF}
    590       QuickSort(LPtr, JPtr);
    591     LPtr := IPtr;
    592   {$IFDEF HAS_NATIVEINT}
    593   until NativeUInt(IPtr) >= NativeUInt(RPtr)
    594   {$ELSE}
    595   until Cardinal(IPtr) >= Cardinal(RPtr)
    596   {$ENDIF}
    597   else
    598     InsertionSort(LPtr, RPtr);
    599 end;
    600 
    601 procedure SortLine(const ALine: TScanLine);
    602 var
    603   L, T: Integer;
    604 begin
    605   L := ALine.Count;
    606   Assert(not Odd(L));
    607   if L = 2 then
    608   begin
    609     if (ALine.EdgePoints[0] and $7FFFFFFF) > (ALine.EdgePoints[1] and $7FFFFFFF) then
    610     begin
    611       T := ALine.EdgePoints[0];
    612       ALine.EdgePoints[0] := ALine.EdgePoints[1];
    613       ALine.EdgePoints[1] := T;
    614     end;
    615   end
    616   else if L > SortThreshold then
    617     QuickSort(@ALine.EdgePoints[0], @ALine.EdgePoints[L - 1])
    618   else if L > 2 then
    619     InsertionSort(@ALine.EdgePoints[0], @ALine.EdgePoints[L - 1]);
    620 end;
    621 
    622 procedure SortLines(const ScanLines: TScanLines);
    623 var
    624   I: Integer;
    625 begin
    626   for I := 0 to High(ScanLines) do SortLine(ScanLines[I]);
    627 end;
    628 
    629 
    630 { Routines for rendering polygon edges to scanlines }
    631 
    632 procedure AddEdgePoint(X: Integer; const Y: Integer; const ClipRect: TFixedRect; const ScanLines: TScanLines; const Direction: Integer);
    633 var
    634   L: Integer;
    635   ScanLine: PScanLine;
    636 begin
    637   if (Y < ClipRect.Top) or (Y > ClipRect.Bottom) then Exit;
    638 
    639   if X < ClipRect.Left then
    640     X := ClipRect.Left
    641   else if X > ClipRect.Right then
    642     X := ClipRect.Right;
    643 
    644   // positive direction (+1) is down
    645   if Direction < 0 then
    646     X := Integer(Longword(X) or $80000000); // set the highest bit if the winding is up
    647 
    648   ScanLine := @ScanLines[Y - ClipRect.Top];
    649 
    650   L := ScanLine.Count;
    651   Inc(ScanLine.Count);
    652   if ScanLine.Count > ScanLine.EdgePointsLength then
    653   begin
    654     ScanLine.EdgePointsLength := L + ReallocationThreshold;
    655     ReallocMem(ScanLine.EdgePoints, ScanLine.EdgePointsLength * SizeOf(TEdgePoint));
    656   end;
    657   ScanLine.EdgePoints[L] := X; 
    658 end;
    659 
    660 function DrawEdge(const P1, P2: TFixedPoint; const ClipRect: TFixedRect; const ScanLines: TScanLines): Integer;
    661 var
    662   X, Y: Integer;
    663   I, K: Integer;
    664   Dx, Dy, Sx, Sy: Integer;
    665   Delta: Integer;
    666 begin
    667   // this function 'renders' a line into the edge point (ScanLines) buffer
    668   // and returns the line direction (1 - down, -1 - up, 0 - horizontal)
    669   Result := 0;
    670   if P2.Y = P1.Y then Exit;
    671   Dx := P2.X - P1.X;
    672   Dy := P2.Y - P1.Y;
    673 
    674   if Dy > 0 then Sy := 1
    675   else
    676   begin
    677     Sy := -1;
    678     Dy := -Dy;
    679   end;
    680 
    681   Result := Sy;
    682 
    683   if Dx > 0 then Sx := 1
    684   else
    685   begin
    686     Sx := -1;
    687     Dx := -Dx;
    688   end;
    689 
    690   Delta := (Dx mod Dy) shr 1;
    691   X := P1.X; Y := P1.Y;
    692 
    693   for I := 0 to Dy - 1 do
    694   begin
    695     AddEdgePoint(X, Y, ClipRect, ScanLines, Result);
    696     Inc(Y, Sy);
    697     Inc(Delta, Dx);
    698 
    699     // try it two times and if anything else left, use div and mod
    700     if Delta > Dy then
    701     begin
    702       Inc(X, Sx);
    703       Dec(Delta, Dy);
    704 
    705       if Delta > Dy then  // segment is tilted more than 45 degrees?
    706       begin
    707         Inc(X, Sx);
    708         Dec(Delta, Dy);
    709 
    710         if Delta > Dy then // are we still here?
    711         begin
    712           K := (Delta + Dy - 1) div Dy;
    713           Inc(X, Sx * K);
    714           Dec(Delta, Dy * K);
    715         end;
    716       end;
    717     end;
    718   end;
    719 end;
    720 
    721 
    722 procedure RoundShift1(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation); forward; {$IFDEF USEINLINING} inline; {$ENDIF}
    723 procedure RoundShift2(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation); forward; {$IFDEF USEINLINING} inline; {$ENDIF}
    724 procedure RoundShift4(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation); forward; {$IFDEF USEINLINING} inline; {$ENDIF}
    725 procedure RoundShift8(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation); forward; {$IFDEF USEINLINING} inline; {$ENDIF}
    726 procedure RoundShift16(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation); forward; {$IFDEF USEINLINING} inline; {$ENDIF}
    727 procedure RoundShift32(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation); forward; {$IFDEF USEINLINING} inline; {$ENDIF}
    728 
    729 type
    730   TTransformProc = procedure(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    731   TTransformationAccess = class(TTransformation);
    732 
    733 procedure Transform1(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    734 begin
    735   TTransformationAccess(T).TransformFixed(SrcPoint.X, SrcPoint.Y, DstPoint.X, DstPoint.Y);
    736   RoundShift1(DstPoint, DstPoint, nil);
    737 end;
    738 
    739 procedure RoundShift1(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    740 {$IFDEF USENATIVECODE}
    741 begin
    742   DstPoint.X := (SrcPoint.X + $7F) div 256;
    743   DstPoint.Y := (SrcPoint.Y + $7FFF) div 65536;
    744 {$ELSE}
    745 asm
    746 {$IFDEF TARGET_x64}
    747     MOV EAX, [SrcPoint]
    748     ADD EAX, $0000007F
    749     SAR EAX, 8 // sub-sampled
    750     MOV [DstPoint], EAX
    751     MOV EDX, [SrcPoint + $4]
    752     ADD EDX, $00007FFF
    753     SAR EDX, 16
    754     MOV [DstPoint + $4], EDX
    755 {$ENDIF}
    756 {$IFDEF TARGET_x86}
    757     MOV ECX, [SrcPoint.X]
    758     ADD ECX, $0000007F
    759     SAR ECX, 8 // sub-sampled
    760     MOV [DstPoint.X], ECX
    761     MOV EDX, [SrcPoint.Y]
    762     ADD EDX, $00007FFF
    763     SAR EDX, 16
    764     MOV [DstPoint.Y], EDX
    765 {$ENDIF}
    766 {$ENDIF}
    767 end;
    768 
    769 procedure Transform2(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    770 begin
    771   TTransformationAccess(T).TransformFixed(SrcPoint.X, SrcPoint.Y, DstPoint.X, DstPoint.Y);
    772   RoundShift2(DstPoint, DstPoint, nil);
    773 end;
    774 
    775 procedure RoundShift2(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    776 {$IFDEF USENATIVECODE}
    777 begin
    778   DstPoint.X := (SrcPoint.X + $3FFF) div 32768;
    779   DstPoint.Y := (SrcPoint.Y + $3FFF) div 32768;
    780 {$ELSE}
    781 asm
    782 {$IFDEF TARGET_x64}
    783     MOV EAX, [SrcPoint]
    784     ADD EAX, $00003FFF
    785     SAR EAX, 15
    786     MOV [DstPoint], EAX
    787     MOV EDX, [SrcPoint + $4]
    788     ADD EDX, $00003FFF
    789     SAR EDX, 15
    790     MOV [DstPoint + $4], EDX
    791 {$ENDIF}
    792 {$IFDEF TARGET_x86}
    793     MOV ECX, [SrcPoint.X]
    794     ADD ECX, $00003FFF
    795     SAR ECX, 15
    796     MOV [DstPoint.X], ECX
    797     MOV EDX, [SrcPoint.Y]
    798     ADD EDX, $00003FFF
    799     SAR EDX, 15
    800     MOV [DstPoint.Y], EDX
    801 {$ENDIF}
    802 {$ENDIF}
    803 end;
    804 
    805 procedure Transform4(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    806 begin
    807   TTransformationAccess(T).TransformFixed(SrcPoint.X, SrcPoint.Y, DstPoint.X, DstPoint.Y);
    808   RoundShift4(DstPoint, DstPoint, nil);
    809 end;
    810 
    811 procedure RoundShift4(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    812 {$IFDEF USENATIVECODE}
    813 begin
    814   DstPoint.X := (SrcPoint.X + $1FFF) div 16384;
    815   DstPoint.Y := (SrcPoint.Y + $1FFF) div 16384;
    816 {$ELSE}
    817 asm
    818 {$IFDEF TARGET_x64}
    819     MOV EAX, [SrcPoint]
    820     ADD EAX, $00001FFF
    821     SAR EAX, 14
    822     MOV [DstPoint], EAX
    823     MOV EDX, [SrcPoint + $4]
    824     ADD EDX, $00001FFF
    825     SAR EDX, 14
    826     MOV [DstPoint + $4], EDX
    827 {$ENDIF}
    828 {$IFDEF TARGET_x86}
    829     MOV ECX, [SrcPoint.X]
    830     ADD ECX, $00001FFF
    831     SAR ECX, 14
    832     MOV [DstPoint.X], ECX
    833     MOV EDX, [SrcPoint.Y]
    834     ADD EDX, $00001FFF
    835     SAR EDX, 14
    836     MOV [DstPoint.Y], EDX
    837 {$ENDIF}
    838 {$ENDIF}
    839 end;
    840 
    841 procedure Transform8(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    842 begin
    843   TTransformationAccess(T).TransformFixed(SrcPoint.X, SrcPoint.Y, DstPoint.X, DstPoint.Y);
    844   RoundShift8(DstPoint, DstPoint, nil);
    845 end;
    846 
    847 procedure RoundShift8(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    848 {$IFDEF USENATIVECODE}
    849 begin
    850   DstPoint.X := (SrcPoint.X + $FFF) div 8192;
    851   DstPoint.Y := (SrcPoint.Y + $FFF) div 8192;
    852 {$ELSE}
    853 asm
    854 {$IFDEF TARGET_x64}
    855     MOV EAX, [SrcPoint]
    856     ADD EAX, $00000FFF
    857     SAR EAX, 13
    858     MOV [DstPoint], EAX
    859     MOV EDX, [SrcPoint + $4]
    860     ADD EDX, $00000FFF
    861     SAR EDX, 13
    862     MOV [DstPoint + $4], EDX
    863 {$ENDIF}
    864 {$IFDEF TARGET_x86}
    865     MOV ECX, [SrcPoint.X]
    866     ADD ECX, $00000FFF
    867     SAR ECX, 13
    868     MOV [DstPoint.X], ECX
    869     MOV EDX, [SrcPoint.Y]
    870     ADD EDX, $00000FFF
    871     SAR EDX, 13
    872     MOV [DstPoint.Y], EDX
    873 {$ENDIF}
    874 {$ENDIF}
    875 end;
    876 
    877 procedure Transform16(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    878 begin
    879   TTransformationAccess(T).TransformFixed(SrcPoint.X, SrcPoint.Y, DstPoint.X, DstPoint.Y);
    880   RoundShift16(DstPoint, DstPoint, nil);
    881 end;
    882 
    883 procedure RoundShift16(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    884 {$IFDEF USENATIVECODE}
    885 begin
    886   DstPoint.X := (SrcPoint.X + $7FF) div 4096;
    887   DstPoint.Y := (SrcPoint.Y + $7FF) div 4096;
    888 {$ELSE}
    889 asm
    890 {$IFDEF TARGET_x64}
    891     MOV EAX, [SrcPoint]
    892     ADD EAX, $000007FF
    893     SAR EAX, 12
    894     MOV [DstPoint], EAX
    895     MOV EDX, [SrcPoint + $4]
    896     ADD EDX, $000007FF
    897     SAR EDX, 12
    898     MOV [DstPoint + $4], EDX
    899 {$ENDIF}
    900 {$IFDEF TARGET_x86}
    901     MOV ECX, [SrcPoint.X]
    902     ADD ECX, $000007FF
    903     SAR ECX, 12
    904     MOV [DstPoint.X], ECX
    905     MOV EDX, [SrcPoint.Y]
    906     ADD EDX, $000007FF
    907     SAR EDX, 12
    908     MOV [DstPoint.Y], EDX
    909 {$ENDIF}
    910 {$ENDIF}
    911 end;
    912 
    913 procedure Transform32(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    914 begin
    915   TTransformationAccess(T).TransformFixed(SrcPoint.X, SrcPoint.Y, DstPoint.X, DstPoint.Y);
    916   RoundShift32(DstPoint, DstPoint, nil);
    917 end;
    918 
    919 procedure RoundShift32(var DstPoint: TFixedPoint; const SrcPoint: TFixedPoint; const T: TTransformation);
    920 {$IFDEF USENATIVECODE}
    921 begin
    922   DstPoint.X := (SrcPoint.X + $3FF) div 2048;
    923   DstPoint.Y := (SrcPoint.Y + $3FF) div 2048;
    924 {$ELSE}
    925 asm
    926 {$IFDEF TARGET_x64}
    927     MOV EAX, [SrcPoint]
    928     ADD EAX, $000003FF
    929     SAR EAX, 11
    930     MOV [DstPoint], EAX
    931     MOV EDX, [SrcPoint + $4]
    932     ADD EDX, $000003FF
    933     SAR EDX, 11
    934     MOV [DstPoint + $4], EDX
    935 {$ENDIF}
    936 {$IFDEF TARGET_x86}
    937     MOV ECX, [SrcPoint.X]
    938     ADD ECX, $000003FF
    939     SAR ECX, 11
    940     MOV [DstPoint.X], ECX
    941     MOV EDX, [SrcPoint.Y]
    942     ADD EDX, $000003FF
    943     SAR EDX, 11
    944     MOV [DstPoint.Y], EDX
    945 {$ENDIF}
    946 {$ENDIF}
    947 end;
    948 
    949 const
    950   RoundShiftProcs: array[TAntialiasMode] of TTransformProc = (RoundShift32, RoundShift16, RoundShift8, RoundShift4, RoundShift2, RoundShift1);
    951   TransformProcs:  array[TAntialiasMode] of TTransformProc = (Transform32, Transform16, Transform8, Transform4, Transform2, Transform1);
    952 
    953 procedure AddPolygon(const Points: TArrayOfFixedPoint; const ClipRect: TFixedRect;
    954   var ScanLines: TScanLines; AAMode: TAntialiasMode; Transformation: TTransformation);
    955 var
    956   P1, P2: TFixedPoint;
    957   I: Integer;
    958   PPtr: PFixedPoint;
    959   Transform: TTransformProc;
    960   Direction, PrevDirection: Integer; // up = 1 or down = -1
    961 begin
    962   if Length(Points) < 3 then Exit;
    963 
    964   if Assigned(Transformation) then
    965     Transform := TransformProcs[AAMode]
    966   else
    967     Transform := RoundShiftProcs[AAMode];
    968 
    969   Transform(P1, Points[0], Transformation);
    970 
    971   // find the last Y different from Y1 and get direction
    972   PrevDirection := 0;
    973   I := High(Points);
    974   PPtr := @Points[I];
    975 
    976   while (I > 0) and (PrevDirection = 0) do
    977   begin
    978     Dec(I);
    979     Transform(P2, PPtr^, Transformation); { TODO : optimize minor inefficiency... }
    980     PrevDirection := P1.Y - P2.Y;
    981     Dec(PPtr);
    982   end;
    983 
    984   if PrevDirection > 0 then
    985     PrevDirection := 1
    986   else if PrevDirection < 0 then
    987     PrevDirection := -1
    988   else
    989     PrevDirection := 0;
    990 
    991   PPtr := @Points[1];
    992   for I := 1 to High(Points) do
    993   begin
    994     Transform(P2, PPtr^, Transformation);
    995 
    996     if P1.Y <> P2.Y then
    997     begin
    998       Direction := DrawEdge(P1, P2, ClipRect, ScanLines);
    999       if Direction <> PrevDirection then
    1000       begin
    1001         AddEdgePoint(P1.X, P1.Y, ClipRect, ScanLines, -Direction);
    1002         PrevDirection := Direction;
    1003       end;
    1004     end;
    1005 
    1006     P1 := P2;
    1007     Inc(PPtr);
    1008   end;
    1009 
    1010   Transform(P2, Points[0], Transformation);
    1011 
    1012   if P1.Y <> P2.Y then
    1013   begin
    1014     Direction := DrawEdge(P1, P2, ClipRect, ScanLines);
    1015     if Direction <> PrevDirection then AddEdgePoint(P1.X, P1.Y, ClipRect, ScanLines, -Direction);
    1016   end;
    1017 end;
    1018 
    1019 
    1020 { FillLines routines }
    1021 { These routines rasterize the sorted edge points in the scanlines to
    1022   the bitmap buffer }
    1023 
    1024 procedure ColorFillLines(Bitmap: TCustomBitmap32; BaseY: Integer;
    1025   const ScanLines: TScanLines; Color: TColor32; Mode: TPolyFillMode);
    1026 var
    1027   I, J, L: Integer;
    1028   Top, Left, Right, OldRight, LP, RP, Cx: Integer;
    1029   Winding, NextWinding: Integer;
    1030   HorzLine: procedure(X1, Y, X2: Integer; Value: TColor32) of Object;
    1031 begin
    1032   if Color and $FF000000 <> $FF000000 then
    1033     HorzLine := Bitmap.HorzLineT
    1034   else
    1035     HorzLine := Bitmap.HorzLine;
    1036 
    1037   Cx := Bitmap.ClipRect.Right - 1;
    1038   Top := BaseY - 1;
    1039 
    1040   if Mode = pfAlternate then
    1041     for J := 0 to High(ScanLines) do
    1042     begin
    1043       Inc(Top);
    1044       L := ScanLines[J].Count; // assuming length is even
    1045       if L = 0 then Continue;
    1046       I := 0;
    1047       OldRight := -1;
    1048 
    1049       while I < L do
    1050       begin
    1051         Left := ScanLines[J].EdgePoints[I] and $7FFFFFFF;
    1052         Inc(I);
    1053         Right := ScanLines[J].EdgePoints[I] and $7FFFFFFF - 1;
    1054         if Right > Left then
    1055         begin
    1056           if (Left and $FF) < $80 then Left := Left shr 8
    1057           else Left := Left shr 8 + 1;
    1058 
    1059           if (Right and $FF) < $80 then Right := Right shr 8
    1060           else Right := Right shr 8 + 1;
    1061 
    1062           if Right >= Cx then Right := Cx;
    1063 
    1064           if Left <= OldRight then Left := OldRight + 1;
    1065           OldRight := Right;
    1066           if Right >= Left then HorzLine(Left, Top, Right, Color);
    1067         end;
    1068         Inc(I);
    1069       end
     1329        BlendMemRGB128(Color, Dst[I], Weights64);
     1330      Dec(Count, 2);
     1331      Inc(I, 2);
    10701332    end
    1071   else // Mode = pfWinding
    1072     for J := 0 to High(ScanLines) do
    1073     begin
    1074       Inc(Top);
    1075       L := ScanLines[J].Count; // assuming length is even
    1076       if L = 0 then Continue;
    1077       I := 0;
    1078 
    1079       Winding := 0;
    1080       Left := ScanLines[J].EdgePoints[0];
    1081       if (Left and $80000000) <> 0 then Inc(Winding) else Dec(Winding);
    1082       Left := Left and $7FFFFFFF;
    1083       Inc(I);
    1084 
    1085       while I < L do
    1086       begin
    1087         Right := ScanLines[J].EdgePoints[I];
    1088         if (Right and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
    1089         Right := Right and $7FFFFFFF;
    1090         Inc(I);
    1091 
    1092         if Winding <> 0 then
    1093         begin
    1094           if (Left and $FF) < $80 then LP := Left shr 8
    1095           else LP := Left shr 8 + 1;
    1096           if (Right and $FF) < $80 then RP := Right shr 8
    1097           else RP := Right shr 8 + 1;
    1098 
    1099           if RP >= Cx then RP := Cx;
    1100 
    1101           if RP >= LP then HorzLine(LP, Top, RP, Color);
    1102         end;
    1103 
    1104         Inc(Winding, NextWinding);
    1105         Left := Right;
    1106       end;
    1107     end;
    1108 end;
    1109 
    1110 procedure ColorFillLines2(Bitmap: TCustomBitmap32; BaseY: Integer;
    1111   const ScanLines: TScanLines; Color: TColor32; Mode: TPolyFillMode;
    1112   const AAMode: TAntialiasMode = DefaultAAMode);
    1113 var
    1114   I, J, L, N: Integer;
    1115   MinY, MaxY, Y, Top, Bottom: Integer;
    1116   MinX, MaxX, X, Dx: Integer;
    1117   Left, Right: Integer;
    1118   Buffer: array of Integer;
    1119   ColorBuffer: array of TColor32;
    1120   BufferSize: Integer;
    1121   C, A: TColor32;
    1122   ScanLine: PIntegerArray;
    1123   Winding, NextWinding: Integer;
    1124   AAShift, AALines, AAMultiplier: Integer;
    1125   BlendLineEx: TBlendLineEx;
    1126 begin
    1127   A := Color shr 24;
    1128 
    1129   AAShift := AA_SHIFT[AAMode];
    1130   AALines := AA_LINES[AAMode] - 1; // we do the -1 here for optimization.
    1131   AAMultiplier := AA_MULTI[AAMode];
    1132 
    1133   BlendLineEx := BLEND_LINE_EX[Bitmap.CombineMode]^;
    1134 
    1135   // find the range of Y screen coordinates
    1136   MinY := BaseY shr AAShift;
    1137   MaxY := (BaseY + Length(ScanLines) + AALines) shr AAShift;
    1138 
    1139   Y := MinY;
    1140   while Y < MaxY do
    1141   begin
    1142     Top := Y shl AAShift - BaseY;
    1143     Bottom := Top + AALines;
    1144     if Top < 0 then Top := 0;
    1145     if Bottom >= Length(ScanLines) then Bottom := High(ScanLines);
    1146 
    1147     // find left and right edges of the screen scanline
    1148     MinX := $7F000000; MaxX := -$7F000000;
    1149     for J := Top to Bottom do
    1150     begin
    1151       L := ScanLines[J].Count - 1;
    1152       if L > 0 then
    1153       begin
    1154         Left := (ScanLines[J].EdgePoints[0] and $7FFFFFFF);
    1155         Right := (ScanLines[J].EdgePoints[L] and $7FFFFFFF + AALines);
    1156         if Left < MinX then MinX := Left;
    1157         if Right > MaxX then MaxX := Right;
    1158       end
    1159     end;
    1160 
    1161     if MaxX >= MinX then
    1162     begin
    1163       MinX := MinX shr AAShift;
    1164       MaxX := MaxX shr AAShift;
    1165       // allocate buffer for a single scanline
    1166       BufferSize := MaxX - MinX + 2;
    1167       if Length(Buffer) < BufferSize then
    1168       begin
    1169         SetLength(Buffer, BufferSize + 64);
    1170         SetLength(ColorBuffer, BufferSize + 64);
    1171       end;
    1172       FillLongword(Buffer[0], BufferSize, 0);
    1173 
    1174       // ...and fill it
    1175       if Mode = pfAlternate then
    1176         for J := Top to Bottom do
    1177         begin
    1178           I := 0;
    1179           L := ScanLines[J].Count;
    1180           ScanLine := @ScanLines[J].EdgePoints[0];
    1181           while I < L do
    1182           begin
    1183             // Left edge
    1184             X := ScanLine[I] and $7FFFFFFF;
    1185             Dx := X and AALines;
    1186             X := X shr AAShift - MinX;
    1187             Inc(Buffer[X], Dx xor AALines);
    1188             Inc(Buffer[X + 1], Dx);
    1189             Inc(I);
    1190 
    1191             // Right edge
    1192             X := ScanLine[I] and $7FFFFFFF;
    1193             Dx := X and AALines;
    1194             X := X shr AAShift - MinX;
    1195             Dec(Buffer[X], Dx xor AALines);
    1196             Dec(Buffer[X + 1], Dx);
    1197             Inc(I);
    1198           end
    1199         end
    1200       else // mode = pfWinding
    1201         for J := Top to Bottom do
    1202         begin
    1203           I := 0;
    1204           L := ScanLines[J].Count;
    1205           ScanLine := @ScanLines[J].EdgePoints[0];
    1206           Winding := 0;
    1207           while I < L do
    1208           begin
    1209             X := ScanLine[I];
    1210             Inc(I);
    1211             if (X and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
    1212             X := X and $7FFFFFFF;
    1213             if Winding = 0 then
    1214             begin
    1215               Dx := X and AALines;
    1216               X := X shr AAShift - MinX;
    1217               Inc(Buffer[X], Dx xor AALines);
    1218               Inc(Buffer[X + 1], Dx);
    1219             end;
    1220             Inc(Winding, NextWinding);
    1221             if Winding = 0 then
    1222             begin
    1223               Dx := X and AALines;
    1224               X := X shr AAShift - MinX;
    1225               Dec(Buffer[X], Dx xor AALines);
    1226               Dec(Buffer[X + 1], Dx);
    1227             end;
    1228           end;
    1229         end;
    1230 
    1231       // integrate the buffer
    1232       N := 0;
    1233       C := Color and $00FFFFFF;
    1234       for I := 0 to BufferSize - 1 do
    1235       begin
    1236         Inc(N, Buffer[I]);
    1237         ColorBuffer[I] := TColor32(N * AAMultiplier and $FF00) shl 16 or C;
    1238       end;
    1239 
    1240       // draw it to the screen
    1241       BlendLineEx(@ColorBuffer[0], Pointer(Bitmap.PixelPtr[MinX, Y]),
    1242         Min(BufferSize, Bitmap.Width - MinX), A);
    1243       EMMS;
    1244     end;
    1245 
    1246     Inc(Y);
    1247   end;
    1248 end;
    1249 
    1250 procedure CustomFillLines(Bitmap: TCustomBitmap32; BaseY: Integer;
    1251   const ScanLines: TScanLines; FillLineCallback: TFillLineEvent; Mode: TPolyFillMode);
    1252 var
    1253   I, J, L: Integer;
    1254   Top, Left, Right, OldRight, LP, RP, Cx: Integer;
    1255   Winding, NextWinding: Integer;
    1256 begin
    1257   Top := BaseY - 1;
    1258   Cx := Bitmap.ClipRect.Right - 1;
    1259 
    1260   if Mode = pfAlternate then
    1261     for J := 0 to High(ScanLines) do
    1262     begin
    1263       Inc(Top);
    1264       L := ScanLines[J].Count; // assuming length is even
    1265       if L = 0 then Continue;
    1266       I := 0;
    1267       OldRight := -1;
    1268 
    1269       while I < L do
    1270       begin
    1271         Left := ScanLines[J].EdgePoints[I] and $7FFFFFFF;
    1272         Inc(I);
    1273         Right := ScanLines[J].EdgePoints[I] and $7FFFFFFF - 1;
    1274         if Right > Left then
    1275         begin
    1276           if (Left and $FF) < $80 then Left := Left shr 8
    1277           else Left := Left shr 8 + 1;
    1278           if (Right and $FF) < $80 then Right := Right shr 8
    1279           else Right := Right shr 8 + 1;
    1280 
    1281           if Right >= Cx then Right := Cx;
    1282 
    1283           if Left <= OldRight then Left := OldRight + 1;
    1284           OldRight := Right;
    1285           if Right >= Left then
    1286             FillLineCallback(Bitmap.PixelPtr[Left, Top], Left, Top, Right - Left, nil);
    1287         end;
    1288         Inc(I);
    1289       end
    1290     end
    1291   else // Mode = pfWinding
    1292     for J := 0 to High(ScanLines) do
    1293     begin
    1294       Inc(Top);
    1295       L := ScanLines[J].Count; // assuming length is even
    1296       if L = 0 then Continue;
    1297       I := 0;
    1298 
    1299       Winding := 0;
    1300       Left := ScanLines[J].EdgePoints[0];
    1301       if (Left and $80000000) <> 0 then Inc(Winding) else Dec(Winding);
    1302       Left := Left and $7FFFFFFF;
    1303       Inc(I);
    1304       while I < L do
    1305       begin
    1306         Right := ScanLines[J].EdgePoints[I];
    1307         if (Right and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
    1308         Right := Right and $7FFFFFFF;
    1309         Inc(I);
    1310 
    1311         if Winding <> 0 then
    1312         begin
    1313           if (Left and $FF) < $80 then LP := Left shr 8
    1314           else LP := Left shr 8 + 1;
    1315           if (Right and $FF) < $80 then RP := Right shr 8
    1316           else RP := Right shr 8 + 1;
    1317 
    1318           if RP >= Cx then RP := Cx;
    1319 
    1320           if RP >= LP then
    1321             FillLineCallback(Bitmap.PixelPtr[LP, Top], LP, Top, RP - LP, nil);
    1322         end;
    1323 
    1324         Inc(Winding, NextWinding);
    1325         Left := Right;
    1326       end;
    1327     end;
     1333    {$ENDIF};
    13281334  EMMS;
    13291335end;
    13301336
    1331 procedure CustomFillLines2(Bitmap: TCustomBitmap32; BaseY: Integer;
    1332   const ScanLines: TScanLines; FillLineCallback: TFillLineEvent; Mode: TPolyFillMode;
    1333   const AAMode: TAntialiasMode = DefaultAAMode);
    1334 var
    1335   I, J, L, N: Integer;
    1336   MinY, MaxY, Y, Top, Bottom: Integer;
    1337   MinX, MaxX, X, Dx: Integer;
    1338   Left, Right: Integer;
    1339   Buffer: array of Integer;
    1340   AlphaBuffer: array of TColor32;
    1341   BufferSize: Integer;
    1342   ScanLine: PIntegerArray;
    1343   Winding, NextWinding: Integer;
    1344   AAShift, AALines, AAMultiplier: Integer;
    1345 begin
    1346   AAShift := AA_SHIFT[AAMode];
    1347   AALines := AA_LINES[AAMode] - 1; // we do the -1 here for optimization.
    1348   AAMultiplier := AA_MULTI[AAMode];
    1349 
    1350   // find the range of Y screen coordinates
    1351   MinY := BaseY shr AAShift;
    1352   MaxY := (BaseY + Length(ScanLines) + AALines) shr AAShift;
    1353 
    1354   Y := MinY;
    1355   while Y < MaxY do
    1356   begin
    1357     Top := Y shl AAShift - BaseY;
    1358     Bottom := Top + AALines;
    1359     if Top < 0 then Top := 0;
    1360     if Bottom >= Length(ScanLines) then Bottom := High(ScanLines);
    1361 
    1362     // find left and right edges of the screen scanline
    1363     MinX := $7F000000; MaxX := -$7F000000;
    1364     for J := Top to Bottom do
    1365     begin
    1366       L := ScanLines[J].Count - 1;
    1367       if L > 0 then
    1368       begin
    1369         Left := (ScanLines[J].EdgePoints[0] and $7FFFFFFF);
    1370         Right := (ScanLines[J].EdgePoints[L] and $7FFFFFFF + AALines);
    1371         if Left < MinX then MinX := Left;
    1372         if Right > MaxX then MaxX := Right;
    1373       end
    1374     end;
    1375 
    1376     if MaxX >= MinX then
    1377     begin
    1378       MinX := MinX shr AAShift;
    1379       MaxX := MaxX shr AAShift;
    1380       // allocate buffer for a single scanline
    1381       BufferSize := MaxX - MinX + 2;
    1382       if Length(Buffer) < BufferSize then
    1383       begin
    1384         SetLength(Buffer, BufferSize + 64);
    1385         SetLength(AlphaBuffer, BufferSize + 64);
    1386       end;
    1387       FillLongword(Buffer[0], BufferSize, 0);
    1388 
    1389       // ...and fill it
    1390       if Mode = pfAlternate then
    1391         for J := Top to Bottom do
    1392         begin
    1393           I := 0;
    1394           L := ScanLines[J].Count;
    1395           ScanLine := @ScanLines[J].EdgePoints[0];
    1396           while I < L do
    1397           begin
    1398             // Left edge
    1399             X := ScanLine[I] and $7FFFFFFF;
    1400             Dx := X and AALines;
    1401             X := X shr AAShift - MinX;
    1402             Inc(Buffer[X], Dx xor AALines);
    1403             Inc(Buffer[X + 1], Dx);
    1404             Inc(I);
    1405 
    1406             // Right edge
    1407             X := ScanLine[I] and $7FFFFFFF;
    1408             Dx := X and AALines;
    1409             X := X shr AAShift - MinX;
    1410             Dec(Buffer[X], Dx xor AALines);
    1411             Dec(Buffer[X + 1], Dx);
    1412             Inc(I);
    1413           end
    1414         end
    1415       else // mode = pfWinding
    1416         for J := Top to Bottom do
    1417         begin
    1418           I := 0;
    1419           L := ScanLines[J].Count;
    1420           ScanLine := @ScanLines[J].EdgePoints[0];
    1421           Winding := 0;
    1422           while I < L do
    1423           begin
    1424             X := ScanLine[I];
    1425             Inc(I);
    1426             if (X and $80000000) <> 0 then NextWinding := 1 else NextWinding := -1;
    1427             X := X and $7FFFFFFF;
    1428             if Winding = 0 then
    1429             begin
    1430               Dx := X and AALines;
    1431               X := X shr AAShift - MinX;
    1432               Inc(Buffer[X], Dx xor AALines);
    1433               Inc(Buffer[X + 1], Dx);
    1434             end;
    1435             Inc(Winding, NextWinding);
    1436             if Winding = 0 then
    1437             begin
    1438               Dx := X and AALines;
    1439               X := X shr AAShift - MinX;
    1440               Dec(Buffer[X], Dx xor AALines);
    1441               Dec(Buffer[X + 1], Dx);
    1442             end;
    1443           end;
    1444         end;
    1445 
    1446       // integrate the buffer
    1447       N := 0;
    1448       for I := 0 to BufferSize - 1 do
    1449       begin
    1450         Inc(N, Buffer[I]);
    1451         AlphaBuffer[I] := (N * AAMultiplier) shr 8;
    1452       end;
    1453 
    1454       // draw it to the screen
    1455       FillLineCallback(Pointer(Bitmap.PixelPtr[MinX, Y]), MinX, Y, BufferSize, @AlphaBuffer[0]);
    1456       EMMS;
    1457     end;
    1458 
    1459     Inc(Y);
    1460   end;
    1461 end;
    1462 
    1463 
    1464 { Helper routines for drawing Polygons and PolyPolygons }
    1465 
    1466 procedure RenderPolyPolygon(Bitmap: TCustomBitmap32;
    1467   const Points: TArrayOfArrayOfFixedPoint; Color: TColor32;
    1468   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode;
    1469   const AAMode: TAntialiasMode; Transformation: TTransformation);
    1470 var
    1471   ChangedRect, DstRect: TFixedRect;
    1472   P: TFixedPoint;
    1473   AAShift: Integer;
    1474   I: Integer;
    1475   ScanLines: TScanLines;
    1476 begin
    1477   if not Bitmap.MeasuringMode then
    1478   begin
    1479     ChangedRect := PolyPolygonBounds(Points, Transformation);
    1480 
    1481     with DstRect do
    1482     if AAMode <> amNone then
    1483     begin
    1484       AAShift := AA_SHIFT[AAMode];
    1485       Left := Bitmap.ClipRect.Left shl AAShift;
    1486       Right := Bitmap.ClipRect.Right shl AAShift - 1;
    1487       Top := Bitmap.ClipRect.Top shl AAShift;
    1488       Bottom := Bitmap.ClipRect.Bottom shl AAShift - 1;
    1489 
    1490       P.X := ChangedRect.Top;
    1491       P.Y := ChangedRect.Bottom;
    1492       RoundShiftProcs[AAMode](P, P, nil);
    1493       Top := Constrain(P.X, Top, Bottom);
    1494       Bottom := Constrain(P.Y, Top, Bottom);
    1495     end
    1496     else
    1497     begin
    1498       Left := Bitmap.ClipRect.Left shl 8;
    1499       Right := Bitmap.ClipRect.Right shl 8 - 1;
    1500       Top := Constrain(SAR_16(ChangedRect.Top + $00007FFF),
    1501         Bitmap.ClipRect.Top, Bitmap.ClipRect.Bottom - 1);
    1502       Bottom := Constrain(SAR_16(ChangedRect.Bottom + $00007FFF),
    1503         Bitmap.ClipRect.Top, Bitmap.ClipRect.Bottom - 1);
    1504     end;
    1505 
    1506     if DstRect.Top >= DstRect.Bottom then Exit;
    1507 
    1508     ScanLinesCreate(ScanLines, DstRect.Bottom - DstRect.Top + 1);
    1509     for I := 0 to High(Points) do
    1510       AddPolygon(Points[I], DstRect, ScanLines, AAMode, Transformation);
    1511 
    1512     SortLines(ScanLines);
    1513     Bitmap.BeginUpdate;
    1514     try
    1515       if AAMode <> amNone then
    1516         if Assigned(FillLineCallback) then
    1517           CustomFillLines2(Bitmap, DstRect.Top, ScanLines, FillLineCallback, Mode, AAMode)
    1518         else
    1519           ColorFillLines2(Bitmap, DstRect.Top, ScanLines, Color, Mode, AAMode)
    1520       else
    1521         if Assigned(FillLineCallback) then
    1522           CustomFillLines(Bitmap, DstRect.Top, ScanLines, FillLineCallback, Mode)
    1523         else
    1524           ColorFillLines(Bitmap, DstRect.Top, ScanLines, Color, Mode);
    1525     finally
    1526       Bitmap.EndUpdate;
    1527       ScanLinesDestroy(ScanLines);
    1528     end;
    1529     Bitmap.Changed(MakeRect(ChangedRect, rrOutside));
    1530   end
    1531   else
    1532     Bitmap.Changed(MakeRect(PolyPolygonBounds(Points, Transformation), rrOutside));
    1533 end;
    1534 
    1535 procedure RenderPolygon(Bitmap: TCustomBitmap32;
    1536   const Points: TArrayOfFixedPoint; Color: TColor32;
    1537   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode;
    1538   const AAMode: TAntialiasMode; Transformation: TTransformation);
    1539 var
    1540   H: TArrayOfArrayOfFixedPoint;
    1541 begin
    1542   SetLength(H, 1);
    1543   H[0] := Points;
    1544   RenderPolyPolygon(Bitmap, H, Color, FillLineCallback, Mode, AAMode, Transformation);
    1545   H[0] := nil;
    1546 end;
    1547 
    1548 
    1549 { Polygons }
    1550 
    1551 procedure PolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    1552   Color: TColor32; Mode: TPolyFillMode; Transformation: TTransformation);
    1553 begin
    1554   RenderPolygon(Bitmap, Points, Color, nil, Mode, amNone, Transformation);
    1555 end;
    1556 
    1557 procedure PolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    1558   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode;
    1559   Transformation: TTransformation);
    1560 begin
    1561   RenderPolygon(Bitmap, Points, 0, FillLineCallback, Mode, amNone, Transformation);
    1562 end;
    1563 
    1564 procedure PolygonTS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    1565   Filler: TCustomPolygonFiller; Mode: TPolyFillMode;
    1566   Transformation: TTransformation);
    1567 begin
    1568   RenderPolygon(Bitmap, Points, 0, Filler.FillLine, Mode, amNone, Transformation);
    1569 end;
    1570 
    1571 procedure PolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    1572   Color: TColor32; Mode: TPolyFillMode;
    1573   const AAMode: TAntialiasMode; Transformation: TTransformation);
    1574 begin
    1575   RenderPolygon(Bitmap, Points, Color, nil, Mode, AAMode, Transformation);
    1576 end;
    1577 
    1578 procedure PolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    1579   FillLineCallback: TFillLineEvent; Mode: TPolyFillMode;
    1580   const AAMode: TAntialiasMode; Transformation: TTransformation);
    1581 begin
    1582   RenderPolygon(Bitmap, Points, 0, FillLineCallback, Mode, AAMode, Transformation);
    1583 end;
    1584 
    1585 procedure PolygonXS(Bitmap: TCustomBitmap32; const Points: TArrayOfFixedPoint;
    1586   Filler: TCustomPolygonFiller; Mode: TPolyFillMode;
    1587   const AAMode: TAntialiasMode; Transformation: TTransformation);
    1588 begin
    1589   RenderPolygon(Bitmap, Points, 0, Filler.FillLine, Mode, AAMode, Transformation);
    1590 end;
    1591 
    1592 
    1593 { PolyPolygons }
    1594 
    1595 procedure PolyPolygonTS(Bitmap: TCustomBitmap32;
    1596   const Points: TArrayOfArrayOfFixedPoint; Color: TColor32; Mode: TPolyFillMode;
    1597   Transformation: TTransformation);
    1598 begin
    1599   RenderPolyPolygon(Bitmap, Points, Color, nil, Mode, amNone, Transformation);
    1600 end;
    1601 
    1602 procedure PolyPolygonTS(Bitmap: TCustomBitmap32;
    1603   const Points: TArrayOfArrayOfFixedPoint; FillLineCallback: TFillLineEvent;
    1604   Mode: TPolyFillMode; Transformation: TTransformation);
    1605 begin
    1606   RenderPolyPolygon(Bitmap, Points, 0, FillLineCallback, Mode, amNone, Transformation);
    1607 end;
    1608 
    1609 procedure PolyPolygonTS(Bitmap: TCustomBitmap32;
    1610   const Points: TArrayOfArrayOfFixedPoint; Filler: TCustomPolygonFiller;
    1611   Mode: TPolyFillMode; Transformation: TTransformation);
    1612 begin
    1613   RenderPolyPolygon(Bitmap, Points, 0, Filler.FillLine, Mode, amNone, Transformation);
    1614 end;
    1615 
    1616 procedure PolyPolygonXS(Bitmap: TCustomBitmap32;
    1617   const Points: TArrayOfArrayOfFixedPoint; Color: TColor32; Mode: TPolyFillMode;
    1618   const AAMode: TAntialiasMode; Transformation: TTransformation);
    1619 begin
    1620   RenderPolyPolygon(Bitmap, Points, Color, nil, Mode, AAMode, Transformation);
    1621 end;
    1622 
    1623 procedure PolyPolygonXS(Bitmap: TCustomBitmap32;
    1624   const Points: TArrayOfArrayOfFixedPoint; FillLineCallback: TFillLineEvent;
    1625   Mode: TPolyFillMode; const AAMode: TAntialiasMode;
    1626   Transformation: TTransformation);
    1627 begin
    1628   RenderPolyPolygon(Bitmap, Points, 0, FillLineCallback, Mode, AAMode, Transformation);
    1629 end;
    1630 
    1631 procedure PolyPolygonXS(Bitmap: TCustomBitmap32;
    1632   const Points: TArrayOfArrayOfFixedPoint; Filler: TCustomPolygonFiller;
    1633   Mode: TPolyFillMode; const AAMode: TAntialiasMode;
    1634   Transformation: TTransformation);
    1635 begin
    1636   RenderPolyPolygon(Bitmap, Points, 0, Filler.FillLine, Mode, AAMode, Transformation);
    1637 end;
    1638 
    1639 
    1640 { Helper routines }
    1641 
    1642 function PolygonBounds(const Points: TArrayOfFixedPoint;
    1643   Transformation: TTransformation): TFixedRect;
    1644 var
    1645   I: Integer;
    1646 begin
    1647   with Result do
    1648   begin
    1649     Left := $7FFFFFFF;
    1650     Right := -$7FFFFFFF;
    1651     Top := $7FFFFFFF;
    1652     Bottom := -$7FFFFFFF;
    1653 
    1654     if Assigned(Transformation) then
    1655     begin
    1656       for I := 0 to High(Points) do
    1657       with Transformation.Transform(Points[I]) do
    1658       begin
    1659         if X < Left   then Left := X;
    1660         if X > Right  then Right := X;
    1661         if Y < Top    then Top := Y;
    1662         if Y > Bottom then Bottom := Y;
    1663       end
    1664     end
    1665     else
    1666       for I := 0 to High(Points) do
    1667       with Points[I] do
    1668       begin
    1669         if X < Left   then Left := X;
    1670         if X > Right  then Right := X;
    1671         if Y < Top    then Top := Y;
    1672         if Y > Bottom then Bottom := Y;
    1673       end;
    1674   end;
    1675 end;
    1676 
    1677 function PolyPolygonBounds(const Points: TArrayOfArrayOfFixedPoint;
    1678   Transformation: TTransformation): TFixedRect;
    1679 var
    1680   I, J: Integer;
    1681 begin
    1682   with Result do
    1683   begin
    1684     Left := $7FFFFFFF;
    1685     Right := -$7FFFFFFF;
    1686     Top := $7FFFFFFF;
    1687     Bottom := -$7FFFFFFF;
    1688 
    1689     if Assigned(Transformation) then
    1690       for I := 0 to High(Points) do
    1691         for J := 0 to High(Points[I]) do
    1692         with Transformation.Transform(Points[I, J]) do
    1693         begin
    1694           if X < Left   then Left := X;
    1695           if X > Right  then Right := X;
    1696           if Y < Top    then Top := Y;
    1697           if Y > Bottom then Bottom := Y;
    1698         end
    1699     else
    1700       for I := 0 to High(Points) do
    1701         for J := 0 to High(Points[I]) do
    1702         with Points[I, J] do
    1703         begin
    1704           if X < Left   then Left := X;
    1705           if X > Right  then Right := X;
    1706           if Y < Top    then Top := Y;
    1707           if Y > Bottom then Bottom := Y;
    1708         end;
    1709   end;
    1710 end;
    1711 
    1712 function PtInPolygon(const Pt: TFixedPoint; const Points: TArrayOfFixedPoint): Boolean;
    1713 var
    1714   I: Integer;
    1715   iPt, jPt: PFixedPoint;
    1716 begin
    1717   Result := False;
    1718   iPt := @Points[0];
    1719   jPt := @Points[High(Points)];
    1720   for I := 0 to High(Points) do
    1721   begin
    1722     Result := Result xor (((Pt.Y >= iPt.Y) xor (Pt.Y >= jPt.Y)) and
    1723       (Pt.X - iPt.X < MulDiv(jPt.X - iPt.X, Pt.Y - iPt.Y, jPt.Y - iPt.Y)));
    1724     jPt := iPt;
    1725     Inc(iPt);
    1726   end;
    1727 end;
    1728 
    1729 { TPolygon32 }
    1730 
    1731 procedure TPolygon32.Add(const P: TFixedPoint);
    1732 var
    1733   H, L: Integer;
    1734 begin
    1735   H := High(Points);
    1736   L := Length(Points[H]);
    1737   SetLength(Points[H], L + 1);
    1738   Points[H][L] := P;
    1739   Normals := nil;
    1740 end;
    1741 
    1742 procedure TPolygon32.AddPoints(var First: TFixedPoint; Count: Integer);
    1743 var
    1744   H, L, I: Integer;
    1745 begin
    1746   H := High(Points);
    1747   L := Length(Points[H]);
    1748   SetLength(Points[H], L + Count);
    1749   for I := 0 to Count - 1 do
    1750     Points[H, L + I] := PFixedPointArray(@First)[I];
    1751   Normals := nil;
    1752 end;
    1753 
    1754 procedure TPolygon32.CopyPropertiesTo(Dst: TPolygon32);
    1755 begin
    1756   Dst.Antialiased := Antialiased;
    1757   Dst.AntialiasMode := AntialiasMode;
    1758   Dst.Closed := Closed;
    1759   Dst.FillMode := FillMode;
    1760 end;
    1761 
    1762 procedure TPolygon32.AssignTo(Dst: TPersistent);
    1763 var
    1764   DstPolygon: TPolygon32;
    1765   Index: Integer;
    1766 begin
    1767   if Dst is TPolygon32 then
    1768   begin
    1769     DstPolygon := TPolygon32(Dst);
    1770     CopyPropertiesTo(DstPolygon);
    1771     SetLength(DstPolygon.FNormals, Length(Normals));
    1772     for Index := 0 to Length(Normals) - 1 do
    1773     begin
    1774       DstPolygon.Normals[Index] := Copy(Normals[Index]);
    1775     end;
    1776 
    1777     SetLength(DstPolygon.FPoints, Length(Points));
    1778     for Index := 0 to Length(Points) - 1 do
    1779     begin
    1780       DstPolygon.Points[Index] := Copy(Points[Index]);
    1781     end;
    1782   end
    1783   else
    1784     inherited;
    1785 end;
    1786 
    1787 function TPolygon32.GetBoundingRect: TFixedRect;
    1788 begin
    1789   Result := PolyPolygonBounds(Points);
    1790 end;
    1791 
    1792 procedure TPolygon32.BuildNormals;
    1793 var
    1794   I, J, Count, NextI: Integer;
    1795   dx, dy, f: Single;
    1796 begin
    1797   if Length(Normals) <> 0 then Exit;
    1798   SetLength(FNormals, Length(Points));
    1799 
    1800   for J := 0 to High(Points) do
    1801   begin
    1802     Count := Length(Points[J]);
    1803     SetLength(Normals[J], Count);
    1804 
    1805     if Count = 0 then Continue;
    1806     if Count = 1 then
    1807     begin
    1808       FillChar(Normals[J][0], SizeOf(TFixedPoint), 0);
    1809       Continue;
    1810     end;
    1811 
    1812     I := 0;
    1813     NextI := 1;
    1814     dx := 0;
    1815     dy := 0;
    1816 
    1817     while I < Count do
    1818     begin
    1819       if Closed and (NextI >= Count) then NextI := 0;
    1820       if NextI < Count then
    1821       begin
    1822         dx := (Points[J][NextI].X - Points[J][I].X) / $10000;
    1823         dy := (Points[J][NextI].Y - Points[J][I].Y) / $10000;
    1824       end;
    1825       if (dx <> 0) or (dy <> 0) then
    1826       begin
    1827         f := 1 / GR32_Math.Hypot(dx, dy);
    1828         dx := dx * f;
    1829         dy := dy * f;
    1830       end;
    1831       with Normals[J][I] do
    1832       begin
    1833         X := Fixed(dy);
    1834         Y := Fixed(-dx);
    1835       end;
    1836       Inc(I);
    1837       Inc(NextI);
    1838     end;
    1839   end;
    1840 end;
    1841 
    1842 procedure TPolygon32.Clear;
    1843 begin
    1844   Points := nil;
    1845   Normals := nil;
    1846   NewLine;
    1847 end;
    1848 
    1849 function TPolygon32.ContainsPoint(const P: TFixedPoint): Boolean;
    1850 var
    1851   I: Integer;
    1852 begin
    1853   Result := False;
    1854   for I := 0 to High(FPoints) do
    1855     if PtInPolygon(P, FPoints[I]) then
    1856     begin
    1857       Result := True;
    1858       Exit;
    1859     end;
    1860 end;
    1861 
    1862 constructor TPolygon32.Create;
    1863 begin
    1864   inherited;
    1865   FClosed := True;
    1866   FAntialiasMode := DefaultAAMode;
    1867   NewLine; // initiate a new contour
    1868 end;
    1869 
    1870 destructor TPolygon32.Destroy;
    1871 begin
    1872   Clear;
    1873   inherited;
    1874 end;
    1875 
    1876 procedure TPolygon32.Draw(Bitmap: TCustomBitmap32; OutlineColor, FillColor: TColor32; Transformation: TTransformation);
    1877 begin
    1878   Bitmap.BeginUpdate;
    1879 
    1880   if Antialiased then
    1881   begin
    1882     if (FillColor and $FF000000) <> 0 then
    1883       PolyPolygonXS(Bitmap, Points, FillColor, FillMode, AntialiasMode, Transformation);
    1884     if (OutlineColor and $FF000000) <> 0 then
    1885       PolyPolylineXS(Bitmap, Points, OutlineColor, Closed, Transformation);
    1886   end
    1887   else
    1888   begin
    1889     if (FillColor and $FF000000) <> 0 then
    1890       PolyPolygonTS(Bitmap, Points, FillColor, FillMode, Transformation);
    1891     if (OutlineColor and $FF000000) <> 0 then
    1892       PolyPolylineTS(Bitmap, Points, OutlineColor, Closed, Transformation);
    1893   end;
    1894 
    1895   Bitmap.EndUpdate;
    1896   Bitmap.Changed;
    1897 end;
    1898 
    1899 procedure TPolygon32.Draw(Bitmap: TCustomBitmap32; OutlineColor: TColor32;
    1900   FillCallback: TFillLineEvent; Transformation: TTransformation);
    1901 begin
    1902   Bitmap.BeginUpdate;
    1903 
    1904   if Antialiased then
    1905   begin
    1906 {$IFDEF FPC}
    1907     RenderPolyPolygon(Bitmap, Points, 0, FillCallback, FillMode, AntialiasMode, Transformation);
    1908 {$ELSE}
    1909     PolyPolygonXS(Bitmap, Points, FillCallback, FillMode, AntialiasMode, Transformation);
    1910 {$ENDIF}
    1911     if (OutlineColor and $FF000000) <> 0 then
    1912       PolyPolylineXS(Bitmap, Points, OutlineColor, Closed, Transformation);
    1913   end
    1914   else
    1915   begin
    1916 {$IFDEF FPC}
    1917     RenderPolyPolygon(Bitmap, Points, 0, FillCallback, FillMode, amNone, Transformation);
    1918 {$ELSE}
    1919     PolyPolygonTS(Bitmap, Points, FillCallback, FillMode, Transformation);
    1920 {$ENDIF}
    1921     if (OutlineColor and $FF000000) <> 0 then
    1922       PolyPolylineTS(Bitmap, Points, OutlineColor, Closed, Transformation);
    1923   end;
    1924 
    1925   Bitmap.EndUpdate;
    1926   Bitmap.Changed;
    1927 end;
    1928 
    1929 procedure TPolygon32.Draw(Bitmap: TCustomBitmap32; OutlineColor: TColor32;
    1930   Filler: TCustomPolygonFiller; Transformation: TTransformation);
    1931 begin
    1932 {$IFDEF FPC}
    1933   Bitmap.BeginUpdate;
    1934 
    1935   if Antialiased then
    1936   begin
    1937     RenderPolyPolygon(Bitmap, Points, 0, Filler.FillLine, FillMode, AntialiasMode, Transformation);
    1938     if (OutlineColor and $FF000000) <> 0 then
    1939       PolyPolylineXS(Bitmap, Points, OutlineColor, Closed, Transformation);
    1940   end
    1941   else
    1942   begin
    1943     RenderPolyPolygon(Bitmap, Points, 0, Filler.FillLine, FillMode, amNone, Transformation);
    1944     if (OutlineColor and $FF000000) <> 0 then
    1945       PolyPolylineTS(Bitmap, Points, OutlineColor, Closed, Transformation);
    1946   end;
    1947 
    1948   Bitmap.EndUpdate;
    1949   Bitmap.Changed;
    1950 
    1951 {$ELSE}
    1952   Draw(Bitmap, OutlineColor, Filler.FillLine, Transformation);
    1953 {$ENDIF}
    1954 end;
    1955 
    1956 procedure TPolygon32.DrawEdge(Bitmap: TCustomBitmap32; Color: TColor32; Transformation: TTransformation);
    1957 begin
    1958   Bitmap.BeginUpdate;
    1959 
    1960   if Antialiased then
    1961     PolyPolylineXS(Bitmap, Points, Color, Closed, Transformation)
    1962   else
    1963     PolyPolylineTS(Bitmap, Points, Color, Closed, Transformation);
    1964 
    1965   Bitmap.EndUpdate;
    1966   Bitmap.Changed;
    1967 end;
    1968 
    1969 procedure TPolygon32.DrawFill(Bitmap: TCustomBitmap32; Color: TColor32; Transformation: TTransformation);
    1970 begin
    1971   Bitmap.BeginUpdate;
    1972 
    1973   if Antialiased then
    1974     PolyPolygonXS(Bitmap, Points, Color, FillMode, AntialiasMode, Transformation)
    1975   else
    1976     PolyPolygonTS(Bitmap, Points, Color, FillMode, Transformation);
    1977 
    1978   Bitmap.EndUpdate;
    1979   Bitmap.Changed;
    1980 end;
    1981 
    1982 procedure TPolygon32.DrawFill(Bitmap: TCustomBitmap32; FillCallback: TFillLineEvent;
    1983   Transformation: TTransformation);
    1984 begin
    1985   Bitmap.BeginUpdate;
    1986 
    1987 {$IFDEF FPC}
    1988   if Antialiased then
    1989     RenderPolyPolygon(Bitmap, Points, 0, FillCallback, FillMode, AntialiasMode, Transformation)
    1990   else
    1991     RenderPolyPolygon(Bitmap, Points, 0, FillCallback, FillMode, amNone, Transformation);
    1992 {$ELSE}
    1993   if Antialiased then
    1994     PolyPolygonXS(Bitmap, Points, FillCallback, FillMode, AntialiasMode, Transformation)
    1995   else
    1996     PolyPolygonTS(Bitmap, Points, FillCallback, FillMode, Transformation);
    1997 {$ENDIF}
    1998 
    1999   Bitmap.EndUpdate;
    2000   Bitmap.Changed;
    2001 end;
    2002 
    2003 procedure TPolygon32.DrawFill(Bitmap: TCustomBitmap32; Filler: TCustomPolygonFiller;
    2004   Transformation: TTransformation);
    2005 begin
    2006 {$IFDEF FPC}
    2007   Bitmap.BeginUpdate;
    2008   if Antialiased then
    2009     RenderPolyPolygon(Bitmap, Points, 0, Filler.FillLine, FillMode, AntialiasMode, Transformation)
    2010   else
    2011     RenderPolyPolygon(Bitmap, Points, 0, Filler.FillLine, FillMode, amNone, Transformation);
    2012 
    2013   Bitmap.EndUpdate;
    2014   Bitmap.Changed;
    2015 {$ELSE}
    2016   DrawFill(Bitmap, Filler.FillLine, Transformation);
    2017 {$ENDIF}
    2018 end;
    2019 
    2020 function TPolygon32.Grow(const Delta: TFixed; EdgeSharpness: Single = 0): TPolygon32;
    2021 var
    2022   J, I, PrevI: Integer;
    2023   PX, PY, AX, AY, BX, BY, CX, CY, R, D, E: Integer;
    2024 
    2025   procedure AddPoint(LongDeltaX, LongDeltaY: Integer);
    2026   var
    2027     N, L: Integer;
    2028   begin
    2029     with Result do
    2030     begin
    2031       N := High(Points);
    2032       L := Length(Points[N]);
    2033       SetLength(Points[N], L + 1);
    2034     end;
    2035     with Result.Points[N][L] do
    2036     begin
    2037       X := PX + LongDeltaX;
    2038       Y := PY + LongDeltaY;
    2039     end;
    2040   end;
    2041 
    2042 begin
    2043   BuildNormals;
    2044 
    2045   if EdgeSharpness > 0.99 then
    2046     EdgeSharpness := 0.99
    2047   else if EdgeSharpness < 0 then
    2048     EdgeSharpness := 0;
    2049 
    2050   D := Delta;
    2051   E := Round(D * (1 - EdgeSharpness));
    2052 
    2053   Result := TPolygon32.Create;
    2054   CopyPropertiesTo(Result);
    2055 
    2056   if Delta = 0 then
    2057   begin
    2058     // simply copy the data
    2059     SetLength(Result.FPoints, Length(Points));
    2060     for J := 0 to High(Points) do
    2061       Result.Points[J] := Copy(Points[J], 0, Length(Points[J]));
    2062     Exit;
    2063   end;
    2064 
    2065   Result.Points := nil;
    2066 
    2067   for J := 0 to High(Points) do
    2068   begin
    2069     if Length(Points[J]) < 2 then Continue;
    2070 
    2071     Result.NewLine;
    2072 
    2073     for I := 0 to High(Points[J]) do
    2074     begin
    2075       with Points[J][I] do
    2076       begin
    2077         PX := X;
    2078         PY := Y;
    2079       end;
    2080 
    2081       with Normals[J][I] do
    2082       begin
    2083         BX := MulDiv(X, D, $10000);
    2084         BY := MulDiv(Y, D, $10000);
    2085       end;
    2086 
    2087       if (I > 0) or Closed then
    2088       begin
    2089         PrevI := I - 1;
    2090         if PrevI < 0 then PrevI := High(Points[J]);
    2091         with Normals[J][PrevI] do
    2092         begin
    2093           AX := MulDiv(X, D, $10000);
    2094           AY := MulDiv(Y, D, $10000);
    2095         end;
    2096 
    2097         if (I = High(Points[J])) and (not Closed) then AddPoint(AX, AY)
    2098         else
    2099         begin
    2100           CX := AX + BX;
    2101           CY := AY + BY;
    2102           R := MulDiv(AX, CX, D) + MulDiv(AY, CY, D);
    2103           if R > E then AddPoint(MulDiv(CX, D, R), MulDiv(CY, D, R))
    2104           else
    2105           begin
    2106             AddPoint(AX, AY);
    2107             AddPoint(BX, BY);
    2108           end;
    2109         end;
    2110       end
    2111       else AddPoint(BX, BY);
    2112     end;
    2113   end;
    2114 end;
    2115 
    2116 procedure TPolygon32.NewLine;
    2117 begin
    2118   SetLength(FPoints, Length(Points) + 1);
    2119   Normals := nil;
    2120 end;
    2121 
    2122 procedure TPolygon32.Offset(const Dx, Dy: TFixed);
    2123 var
    2124   J, I: Integer;
    2125 begin
    2126   for J := 0 to High(Points) do
    2127     for I := 0 to High(Points[J]) do
    2128       with Points[J][I] do
    2129       begin
    2130         Inc(X, Dx);
    2131         Inc(Y, Dy);
    2132       end;
    2133 end;
    2134 
    2135 function TPolygon32.Outline: TPolygon32;
    2136 var
    2137   J, I, L, H: Integer;
    2138 begin
    2139   BuildNormals;
    2140 
    2141   Result := TPolygon32.Create;
    2142   CopyPropertiesTo(Result);
    2143 
    2144   Result.Points := nil;
    2145 
    2146   for J := 0 to High(Points) do
    2147   begin
    2148     if Length(Points[J]) < 2 then Continue;
    2149 
    2150     if Closed then
    2151     begin
    2152       Result.NewLine;
    2153       for I := 0 to High(Points[J]) do Result.Add(Points[J][I]);
    2154       Result.NewLine;
    2155       for I := High(Points[J]) downto 0 do Result.Add(Points[J][I]);
    2156     end
    2157     else // not closed
    2158     begin
    2159       // unrolled...
    2160       SetLength(Result.FPoints, Length(Result.FPoints) + 1);
    2161       Result.FNormals:= nil;
    2162 
    2163       L:= Length(Points[J]);
    2164       H:= High(Result.FPoints);
    2165       SetLength(Result.FPoints[H], L * 2);
    2166       for I := 0 to High(Points[J]) do
    2167         Result.FPoints[H][I]:= (Points[J][I]);
    2168       for I := High(Points[J]) downto 0 do
    2169         Result.FPoints[H][2 * L - (I + 1)]:= (Points[J][I]);
    2170     end;
    2171   end;
    2172 end;
    2173 
    2174 procedure TPolygon32.Transform(Transformation: TTransformation);
    2175 begin
    2176   Points := TransformPoints(Points, Transformation);
    2177 end;
     1337{ TCustomPolygonFiller }
     1338
     1339procedure TCustomPolygonFiller.BeginRendering;
     1340begin
     1341  // implemented by descendants
     1342end;
     1343
     1344procedure TCustomPolygonFiller.EndRendering;
     1345begin
     1346  // implemented by descendants
     1347end;
     1348
     1349{ TCallbackPolygonFiller }
     1350
     1351function TCallbackPolygonFiller.GetFillLine: TFillLineEvent;
     1352begin
     1353  Result := FFillLineEvent;
     1354end;
     1355
     1356
     1357{ TInvertPolygonFiller }
     1358
     1359procedure TInvertPolygonFiller.FillLineBlend(Dst: PColor32; DstX, DstY,
     1360  Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
     1361var
     1362  X: Integer;
     1363  BlendMemEx: TBlendMemEx;
     1364begin
     1365  BlendMemEx := BLEND_MEM_EX[CombineMode]^;
     1366  for X := DstX to DstX + Length - 1 do
     1367  begin
     1368    BlendMemEx(InvertColor(Dst^), Dst^, AlphaValues^);
     1369    EMMS;
     1370    Inc(Dst);
     1371    Inc(AlphaValues);
     1372  end;
     1373end;
     1374
     1375function TInvertPolygonFiller.GetFillLine: TFillLineEvent;
     1376begin
     1377  Result := FillLineBlend;
     1378end;
     1379
     1380
     1381{ TClearPolygonFiller }
     1382
     1383constructor TClearPolygonFiller.Create(Color: TColor32 = $00808080);
     1384begin
     1385  inherited Create;
     1386  FColor := Color;
     1387end;
     1388
     1389procedure TClearPolygonFiller.FillLineClear(Dst: PColor32; DstX, DstY,
     1390  Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
     1391begin
     1392  FillLongword(Dst^, Length, FColor);
     1393end;
     1394
     1395function TClearPolygonFiller.GetFillLine: TFillLineEvent;
     1396begin
     1397  Result := FillLineClear;
     1398end;
     1399
    21781400
    21791401{ TBitmapPolygonFiller }
    21801402
    21811403procedure TBitmapPolygonFiller.FillLineOpaque(Dst: PColor32; DstX, DstY,
    2182   Length: Integer; AlphaValues: PColor32);
     1404  Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
    21831405var
    21841406  PatternX, PatternY, X: Integer;
     
    22231445end;
    22241446
    2225 procedure TBitmapPolygonFiller.FillLineBlend(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32);
     1447procedure TBitmapPolygonFiller.FillLineBlend(Dst: PColor32; DstX, DstY,
     1448  Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
    22261449var
    22271450  PatternX, PatternY, X: Integer;
     
    22681491end;
    22691492
    2270 procedure TBitmapPolygonFiller.FillLineBlendMasterAlpha(Dst: PColor32; DstX, DstY,
    2271   Length: Integer; AlphaValues: PColor32);
     1493procedure TBitmapPolygonFiller.FillLineBlendMasterAlpha(Dst: PColor32;
     1494  DstX, DstY, Length: Integer; AlphaValues: PColor32;
     1495  CombineMode: TCombineMode);
    22721496var
    22731497  PatternX, PatternY, X: Integer;
     
    23091533end;
    23101534
    2311 procedure TBitmapPolygonFiller.FillLineCustomCombine(Dst: PColor32; DstX, DstY,
    2312   Length: Integer; AlphaValues: PColor32);
     1535procedure TBitmapPolygonFiller.FillLineCustomCombine(Dst: PColor32;
     1536  DstX, DstY, Length: Integer; AlphaValues: PColor32;
     1537  CombineMode: TCombineMode);
    23131538var
    23141539  PatternX, PatternY, X: Integer;
     
    23721597{ TSamplerFiller }
    23731598
     1599constructor TSamplerFiller.Create(Sampler: TCustomSampler = nil);
     1600begin
     1601  inherited Create;
     1602  FSampler := Sampler;
     1603  SamplerChanged;
     1604end;
     1605
     1606procedure TSamplerFiller.EndRendering;
     1607begin
     1608  if Assigned(FSampler) then
     1609    FSampler.FinalizeSampling
     1610  else
     1611    raise Exception.Create(RCStrNoSamplerSpecified);
     1612end;
     1613
    23741614procedure TSamplerFiller.SampleLineOpaque(Dst: PColor32; DstX, DstY,
    2375   Length: Integer; AlphaValues: PColor32);
     1615  Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode);
    23761616var
    23771617  X: Integer;
    23781618  BlendMemEx: TBlendMemEx;
    23791619begin
    2380   BlendMemEx := BLEND_MEM_EX[cmBlend]^;
     1620  BlendMemEx := BLEND_MEM_EX[CombineMode]^;
    23811621  for X := DstX to DstX + Length - 1 do
    23821622  begin
     
    23881628end;
    23891629
     1630procedure TSamplerFiller.SamplerChanged;
     1631begin
     1632  if Assigned(FSampler) then
     1633    FGetSample := FSampler.GetSampleInt;
     1634end;
     1635
     1636procedure TSamplerFiller.BeginRendering;
     1637begin
     1638  if Assigned(FSampler) then
     1639    FSampler.PrepareSampling
     1640  else
     1641    raise Exception.Create(RCStrNoSamplerSpecified);
     1642end;
     1643
    23901644function TSamplerFiller.GetFillLine: TFillLineEvent;
    23911645begin
     
    23951649procedure TSamplerFiller.SetSampler(const Value: TCustomSampler);
    23961650begin
    2397   FSampler := Value;
    2398   FGetSample := FSampler.GetSampleInt;
    2399 end;
     1651  if FSampler <> Value then
     1652  begin
     1653    FSampler := Value;
     1654    SamplerChanged;
     1655  end;
     1656end;
     1657
     1658
     1659{ TCustomPolygonRenderer }
     1660
     1661procedure TCustomPolygonRenderer.PolygonFS(
     1662  const Points: TArrayOfFloatPoint; const ClipRect: TFloatRect;
     1663  Transformation: TTransformation);
     1664begin
     1665  PolyPolygonFS(PolyPolygon(Points), ClipRect, Transformation);
     1666end;
     1667
     1668procedure TCustomPolygonRenderer.PolygonFS(
     1669  const Points: TArrayOfFloatPoint; const ClipRect: TFloatRect);
     1670begin
     1671  PolyPolygonFS(PolyPolygon(Points), ClipRect);
     1672end;
     1673
     1674procedure TCustomPolygonRenderer.PolyPolygonFS(
     1675  const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
     1676begin
     1677  // implemented by descendants
     1678end;
     1679
     1680procedure TCustomPolygonRenderer.PolyPolygonFS(
     1681  const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect;
     1682  Transformation: TTransformation);
     1683var
     1684  APoints: TArrayOfArrayOfFloatPoint;
     1685begin
     1686  if Assigned(Transformation) then
     1687    APoints := TransformPolyPolygon(Points, Transformation)
     1688  else
     1689    APoints := Points;
     1690  PolyPolygonFS(APoints, ClipRect);
     1691end;
     1692
     1693{ TPolygonRenderer32 }
     1694
     1695constructor TPolygonRenderer32.Create(Bitmap: TBitmap32;
     1696  Fillmode: TPolyFillMode);
     1697begin
     1698  inherited Create;
     1699  FBitmap := Bitmap;
     1700  FFillMode := Fillmode;
     1701end;
     1702
     1703procedure TPolygonRenderer32.PolygonFS(const Points: TArrayOfFloatPoint);
     1704begin
     1705  PolyPolygonFS(PolyPolygon(Points), FloatRect(FBitmap.ClipRect));
     1706end;
     1707
     1708procedure TPolygonRenderer32.PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint);
     1709begin
     1710  PolyPolygonFS(Points, FloatRect(FBitmap.ClipRect));
     1711end;
     1712
     1713procedure TPolygonRenderer32.SetBitmap(const Value: TBitmap32);
     1714begin
     1715  if FBitmap <> Value then
     1716  begin
     1717    FBitmap := Value;
     1718    Changed;
     1719  end;
     1720end;
     1721
     1722procedure TPolygonRenderer32.SetColor(const Value: TColor32);
     1723begin
     1724  if FColor <> Value then
     1725  begin
     1726    FColor := Value;
     1727    Changed;
     1728  end;
     1729end;
     1730
     1731procedure TPolygonRenderer32.SetFiller(const Value: TCustomPolygonFiller);
     1732begin
     1733  if FFiller <> Value then
     1734  begin
     1735    FFiller := Value;
     1736    Changed;
     1737  end;
     1738end;
     1739
     1740procedure TPolygonRenderer32.SetFillMode(const Value: TPolyFillMode);
     1741begin
     1742  if FFillMode <> Value then
     1743  begin
     1744    FFillMode := Value;
     1745    Changed;
     1746  end;
     1747end;
     1748
     1749{ TPolygonRenderer32VPR }
     1750
     1751{$IFDEF USESTACKALLOC}
     1752{$W+}
     1753{$ENDIF}
     1754procedure TPolygonRenderer32VPR.FillSpan(const Span: TValueSpan; DstY: Integer);
     1755var
     1756  AlphaValues: PColor32Array;
     1757  Count: Integer;
     1758begin
     1759  Count := Span.X2 - Span.X1 + 1;
     1760  {$IFDEF USESTACKALLOC}
     1761  AlphaValues := StackAlloc(Count * SizeOf(TColor32));
     1762  {$ELSE}
     1763  GetMem(AlphaValues, Count * SizeOf(TColor32));
     1764  {$ENDIF}
     1765  FFillProc(Span.Values, AlphaValues, Count, FColor);
     1766  FFiller.FillLine(@Bitmap.ScanLine[DstY][Span.X1], Span.X1, DstY, Count,
     1767    PColor32(AlphaValues), Bitmap.CombineMode);
     1768  EMMS;
     1769  {$IFDEF USESTACKALLOC}
     1770  StackFree(AlphaValues);
     1771  {$ELSE}
     1772  FreeMem(AlphaValues);
     1773  {$ENDIF}
     1774end;
     1775{$IFDEF USESTACKALLOC}
     1776{$W-}
     1777{$ENDIF}
     1778
     1779function TPolygonRenderer32VPR.GetRenderSpan: TRenderSpanEvent;
     1780begin
     1781  if Assigned(FFiller) then
     1782    Result := FillSpan
     1783  else
     1784    Result := RenderSpan;
     1785end;
     1786
     1787procedure TPolygonRenderer32VPR.PolyPolygonFS(
     1788  const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
     1789{$IFDEF CHANGENOTIFICATIONS}
     1790var
     1791  I: Integer;
     1792{$ENDIF}
     1793begin
     1794  UpdateFillProcs;
     1795  if Assigned(FFiller) then
     1796  begin
     1797    FFiller.BeginRendering;
     1798    RenderPolyPolygon(Points, ClipRect, GetRenderSpan());
     1799    FFiller.EndRendering;
     1800  end
     1801  else
     1802    RenderPolyPolygon(Points, ClipRect, GetRenderSpan());
     1803
     1804{$IFDEF CHANGENOTIFICATIONS}
     1805  if TBitmap32Access(Bitmap).UpdateCount = 0 then
     1806    for I := 0 to High(Points) do
     1807      if Length(Points[I]) > 0 then
     1808        Bitmap.Changed(MakeRect(PolygonBounds(Points[I])));
     1809{$ENDIF}
     1810end;
     1811
     1812{$W+}
     1813procedure TPolygonRenderer32VPR.RenderSpan(const Span: TValueSpan;
     1814  DstY: Integer);
     1815var
     1816  AlphaValues: PColor32Array;
     1817  Count: Integer;
     1818begin
     1819  Count := Span.X2 - Span.X1 + 1;
     1820  {$IFDEF USESTACKALLOC}
     1821  AlphaValues := StackAlloc(Count * SizeOf(TColor32));
     1822  {$ELSE}
     1823  GetMem(AlphaValues, Count * SizeOf(TColor32));
     1824  {$ENDIF}
     1825  FFillProc(Span.Values, AlphaValues, Count, FColor);
     1826  if Bitmap.CombineMode = cmMerge then
     1827    MergeLine(@AlphaValues[0], @Bitmap.ScanLine[DstY][Span.X1], Count)
     1828  else
     1829    BlendLine(@AlphaValues[0], @Bitmap.ScanLine[DstY][Span.X1], Count);
     1830  EMMS;
     1831  {$IFDEF USESTACKALLOC}
     1832  StackFree(AlphaValues);
     1833  {$ELSE}
     1834  FreeMem(AlphaValues);
     1835  {$ENDIF}
     1836end;
     1837{$W-}
     1838
     1839procedure TPolygonRenderer32VPR.UpdateFillProcs;
     1840const
     1841  FillProcs: array [Boolean, TPolyFillMode] of TFillProc = (
     1842    (MakeAlphaEvenOddUP, MakeAlphaNonZeroUP),
     1843    (MakeAlphaEvenOddUPF, MakeAlphaNonZeroUPF)
     1844  );
     1845begin
     1846  FFillProc := FillProcs[Assigned(FFiller), FillMode];
     1847end;
     1848
     1849{ TPolygonRenderer32LCD }
     1850
     1851procedure TPolygonRenderer32LCD.PolyPolygonFS(
     1852  const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect);
     1853var
     1854  R: TFloatRect;
     1855  APoints: TArrayOfArrayOfFloatPoint;
     1856{$IFDEF CHANGENOTIFICATIONS}
     1857  I: Integer;
     1858{$ENDIF}
     1859begin
     1860  APoints := ScalePolyPolygon(Points, 3, 1);
     1861  R.Top := ClipRect.Top;
     1862  R.Bottom := ClipRect.Bottom;
     1863  R.Left := ClipRect.Left * 3;
     1864  R.Right := ClipRect.Right * 3;
     1865  RenderPolyPolygon(APoints, R, RenderSpan);
     1866{$IFDEF CHANGENOTIFICATIONS}
     1867  if TBitmap32Access(Bitmap).UpdateCount = 0 then
     1868    for I := 0 to High(Points) do
     1869      if length(Points[I]) > 0 then
     1870        Bitmap.Changed(MakeRect(PolygonBounds(Points[I])));
     1871{$ENDIF}
     1872end;
     1873
     1874{$W+}
     1875procedure TPolygonRenderer32LCD.RenderSpan(const Span: TValueSpan;
     1876  DstY: Integer);
     1877const
     1878  PADDING = 5;
     1879var
     1880  AlphaValues: SysUtils.PByteArray;
     1881  Count: Integer;
     1882  X1, Offset: Integer;
     1883const
     1884  MakeAlpha: array [TPolyFillMode] of TMakeAlphaProcLCD = (MakeAlphaEvenOddLCD, MakeAlphaNonZeroLCD);
     1885begin
     1886  Count := Span.X2 - Span.X1 + 1;
     1887  X1 := DivMod(Span.X1, 3, Offset);
     1888
     1889  // Left Padding + Right Padding + Filter Width = 2 + 2 + 2 = 6
     1890  {$IFDEF USESTACKALLOC}
     1891  AlphaValues := StackAlloc((Count + 6 + PADDING) * SizeOf(Byte));
     1892  {$ELSE}
     1893  GetMem(AlphaValues, (Count + 6 + PADDING) * SizeOf(Byte));
     1894  {$ENDIF}
     1895  AlphaValues[0] := 0;
     1896  AlphaValues[1] := 0;
     1897  if (X1 > 0) then
     1898  begin
     1899    Dec(X1);
     1900    Inc(Offset, 3);
     1901    AlphaValues[2] := 0;
     1902    AlphaValues[3] := 0;
     1903    AlphaValues[4] := 0;
     1904  end;
     1905
     1906  MakeAlpha[FFillMode](Span.Values, PByteArray(@AlphaValues[PADDING]), Count, FColor);
     1907  CombineLineLCD(@AlphaValues[PADDING - Offset], PColor32Array(@Bitmap.ScanLine[DstY][X1]), FColor, (Count + Offset + 2) div 3);
     1908
     1909  {$IFDEF USESTACKALLOC}
     1910  StackFree(AlphaValues);
     1911  {$ELSE}
     1912  FreeMem(AlphaValues);
     1913  {$ENDIF}
     1914end;
     1915{$W-}
     1916
     1917
     1918{ TPolygonRenderer32LCD2 }
     1919
     1920{$W+}
     1921procedure TPolygonRenderer32LCD2.RenderSpan(const Span: TValueSpan;
     1922  DstY: Integer);
     1923const
     1924  PADDING = 5;
     1925var
     1926  AlphaValues: SysUtils.PByteArray;
     1927  Count: Integer;
     1928  X1, Offset: Integer;
     1929const
     1930  MakeAlpha: array [TPolyFillMode] of TMakeAlphaProcLCD = (MakeAlphaEvenOddLCD2, MakeAlphaNonZeroLCD2);
     1931begin
     1932  Count := Span.X2 - Span.X1 + 1;
     1933  X1 := DivMod(Span.X1, 3, Offset);
     1934
     1935  // Left Padding + Right Padding + Filter Width = 2 + 2 + 2 = 6
     1936  {$IFDEF USESTACKALLOC}
     1937  AlphaValues := StackAlloc((Count + 6 + PADDING) * SizeOf(Byte));
     1938  {$ELSE}
     1939  GetMem(AlphaValues, (Count + 6 + PADDING) * SizeOf(Byte));
     1940  {$ENDIF}
     1941  AlphaValues[0] := 0;
     1942  AlphaValues[1] := 0;
     1943  if (X1 > 0) then
     1944  begin
     1945    Dec(X1);
     1946    Inc(Offset, 3);
     1947    AlphaValues[2] := 0;
     1948    AlphaValues[3] := 0;
     1949    AlphaValues[4] := 0;
     1950  end;
     1951
     1952  Dec(Offset, 1);
     1953  MakeAlpha[FFillMode](Span.Values, PByteArray(@AlphaValues[PADDING]), Count, FColor);
     1954  Inc(Count);
     1955  CombineLineLCD(@AlphaValues[PADDING - Offset], PColor32Array(@Bitmap.ScanLine[DstY][X1]), FColor, (Count + Offset + 2) div 3);
     1956
     1957  {$IFDEF USESTACKALLOC}
     1958  StackFree(AlphaValues);
     1959  {$ELSE}
     1960  FreeMem(AlphaValues);
     1961  {$ENDIF}
     1962end;
     1963{$W-}
     1964
     1965initialization
     1966  RegisterPolygonRenderer(TPolygonRenderer32VPR);
     1967  RegisterPolygonRenderer(TPolygonRenderer32LCD);
     1968  RegisterPolygonRenderer(TPolygonRenderer32LCD2);
     1969
     1970finalization
     1971  PolygonRendererList.Free;
    24001972
    24011973end.
Note: See TracChangeset for help on using the changeset viewer.