Changeset 522 for GraphicTest/Packages/Graphics32/GR32_Polygons.pas
- Timestamp:
- Apr 17, 2019, 10:42:18 AM (5 years ago)
- Location:
- GraphicTest/Packages/Graphics32
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/Packages/Graphics32
-
Property svn:ignore
set to
lib
-
Property svn:ignore
set to
-
GraphicTest/Packages/Graphics32/GR32_Polygons.pas
r450 r522 21 21 * license. 22 22 * 23 * The Original Code is Graphics3223 * The Original Code is Vectorial Polygon Rasterizer for Graphics32 24 24 * 25 25 * The Initial Developer of the Original Code is 26 * Alex A. Denisov26 * Mattias Andersson <mattias@centaurix.com> 27 27 * 28 * Portions created by the Initial Developer are Copyright (C) 200 0-200928 * Portions created by the Initial Developer are Copyright (C) 2008-2012 29 29 * the Initial Developer. All Rights Reserved. 30 30 * 31 31 * Contributor(s): 32 * Andre Beckedorf <Andre@metaException.de>33 * Mattias Andersson <mattias@centaurix.com>34 * Peter Larson <peter@larson.net>35 32 * 36 33 * ***** END LICENSE BLOCK ***** *) … … 40 37 {$I GR32.inc} 41 38 42 {$IFDEF PUREPASCAL}43 {$DEFINE USENATIVECODE}44 {$ENDIF}45 {$IFDEF USEINLINING}46 {$DEFINE USENATIVECODE}47 {$ENDIF}48 49 39 uses 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; 78 41 79 42 type 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; 84 134 85 135 TCustomPolygonFiller = class … … 87 137 function GetFillLine: TFillLineEvent; virtual; abstract; 88 138 public 139 procedure BeginRendering; virtual; 140 procedure EndRendering; virtual; 141 89 142 property FillLine: TFillLineEvent read GetFillLine; 90 143 end; 91 144 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) 139 147 private 140 FAntialiased: Boolean; 141 FClosed: Boolean; 142 FFillMode: TPolyFillMode; 143 FNormals: TArrayOfArrayOfFixedPoint; 144 FPoints: TArrayOfArrayOfFixedPoint; 145 FAntialiasMode: TAntialiasMode; 148 FFillLineEvent: TFillLineEvent; 146 149 protected 147 procedure BuildNormals; 148 procedure CopyPropertiesTo(Dst: TPolygon32); virtual; 149 procedure AssignTo(Dst: TPersistent); override; 150 function GetFillLine: TFillLineEvent; override; 150 151 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; 182 175 end; 183 176 … … 190 183 protected 191 184 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); 196 193 public 197 194 property Pattern: TCustomBitmap32 read FPattern write FPattern; … … 207 204 procedure SetSampler(const Value: TCustomSampler); 208 205 protected 206 procedure SamplerChanged; virtual; 209 207 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; 212 214 property Sampler: TCustomSampler read FSampler write SetSampler; 213 215 end; 214 216 217 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 218 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 219 Transformation: TTransformation = nil); overload; 220 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 221 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 222 Transformation: TTransformation = nil); overload; 223 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 224 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate; 225 Transformation: TTransformation = nil); overload; 226 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 227 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate; 228 Transformation: TTransformation = nil); overload; 229 procedure PolyPolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 230 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 231 Transformation: TTransformation = nil); overload; 232 procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 233 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 234 Transformation: TTransformation = nil); overload; 235 procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 236 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 237 Transformation: TTransformation = nil); overload; 238 procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 239 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 240 Transformation: TTransformation = nil); overload; 241 242 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 243 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 244 Transformation: TTransformation = nil); overload; 245 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 246 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 247 Transformation: TTransformation = nil); overload; 248 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 249 ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate; 250 Transformation: TTransformation = nil); overload; 251 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 252 ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate; 253 Transformation: TTransformation = nil); overload; 254 procedure PolyPolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 255 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 256 Transformation: TTransformation = nil); overload; 257 procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 258 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 259 Transformation: TTransformation = nil); overload; 260 procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 261 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 262 Transformation: TTransformation = nil); overload; 263 procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 264 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 265 Transformation: TTransformation = nil); overload; 266 267 268 procedure 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; 272 procedure 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 277 procedure 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; 281 procedure 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 ... 287 procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 288 const Dashes: TArrayOfFloat; Color: TColor32; 289 Closed: Boolean = False; Width: TFloat = 1.0); overload; 290 procedure 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 ... 294 procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 295 const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller; 296 Closed: Boolean = False; Width: TFloat = 1.0); overload; 297 procedure 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 301 procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 302 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 303 Transformation: TTransformation = nil); overload; 304 procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 305 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 306 Transformation: TTransformation = nil); overload; 307 procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 308 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate; 309 Transformation: TTransformation = nil); overload; 310 procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 311 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode = pfAlternate; 312 Transformation: TTransformation = nil); overload; 313 procedure PolyPolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 314 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 315 Transformation: TTransformation = nil); overload; 316 procedure PolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 317 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 318 Transformation: TTransformation = nil); 319 procedure PolyPolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 320 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 321 Transformation: TTransformation = nil); overload; 322 procedure PolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 323 Color: TColor32; FillMode: TPolyFillMode = pfAlternate; 324 Transformation: TTransformation = nil); 325 326 procedure 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; 330 procedure 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 335 procedure 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; 339 procedure 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 ... 345 procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 346 const Dashes: TArrayOfFixed; Color: TColor32; 347 Closed: Boolean = False; Width: TFixed = $10000); overload; 348 procedure 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 ... 352 procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 353 const Dashes: TArrayOfFixed; Filler: TCustomPolygonFiller; 354 Closed: Boolean = False; Width: TFixed = $10000); overload; 355 procedure 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 360 procedure FillBitmap(Bitmap: TBitmap32; Filler: TCustomPolygonFiller); 361 362 { Registration routines } 363 procedure RegisterPolygonRenderer(PolygonRendererClass: TCustomPolygonRendererClass); 364 365 var 366 PolygonRendererList: TClassList; 367 DefaultPolygonRendererClass: TPolygonRenderer32Class = TPolygonRenderer32VPR; 368 215 369 implementation 216 370 217 uses Math; 371 uses 372 Math, SysUtils, GR32_Math, GR32_LowLevel, GR32_Blend, GR32_Gamma, 373 GR32_VectorUtils; 374 375 resourcestring 376 RCStrNoSamplerSpecified = 'No sampler specified!'; 218 377 219 378 type 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 381 procedure RegisterPolygonRenderer(PolygonRendererClass: TCustomPolygonRendererClass); 382 begin 383 if not Assigned(PolygonRendererList) then PolygonRendererList := TClassList.Create; 384 PolygonRendererList.Add(PolygonRendererClass); 385 end; 386 387 // routines for color filling: 388 389 procedure MakeAlphaNonZeroUP(Coverage: PSingleArray; AlphaValues: PColor32Array; 390 Count: Integer; Color: TColor32); 391 var 392 I: Integer; 393 M, V: Cardinal; 394 Last: TFloat; 395 C: TColor32Entry absolute Color; 396 begin 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; 414 end; 415 416 (* 417 procedure MakeAlphaNonZeroUP(Coverage: PSingleArray; AlphaValues: PColor32Array; 418 Count: Integer; Color: TColor32); 419 var 420 I: Integer; 421 M, V, C: Cardinal; 422 begin 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; 436 end; 437 *) 438 439 procedure MakeAlphaEvenOddUP(Coverage: PSingleArray; AlphaValues: PColor32Array; 440 Count: Integer; Color: TColor32); 441 var 442 I: Integer; 443 M, V: Cardinal; 444 Last: TFloat; 445 C: TColor32Entry absolute Color; 446 begin 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; 466 end; 467 468 procedure MakeAlphaNonZeroP(Value: Single; AlphaValues: PColor32Array; 469 Count: Integer; Color: TColor32); 470 var 471 M, V: Cardinal; 472 C: TColor32Entry absolute Color; 473 begin 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); 483 end; 484 485 procedure MakeAlphaEvenOddP(Value: Single; AlphaValues: PColor32Array; 486 Count: Integer; Color: TColor32); 487 var 488 M, V: Cardinal; 489 C: TColor32Entry absolute Color; 490 begin 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); 501 end; 502 503 504 // polygon filler routines (extract alpha only): 505 506 procedure MakeAlphaNonZeroUPF(Coverage: PSingleArray; AlphaValues: PColor32Array; 507 Count: Integer; Color: TColor32); 508 var 509 I: Integer; 510 V: Integer; 511 begin 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; 520 end; 521 522 procedure MakeAlphaEvenOddUPF(Coverage: PSingleArray; AlphaValues: PColor32Array; 523 Count: Integer; Color: TColor32); 524 var 525 I: Integer; 526 V: Integer; 527 begin 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; 538 end; 539 540 procedure MakeAlphaNonZeroPF(Value: Single; AlphaValues: PColor32Array; 541 Count: Integer; Color: TColor32); 542 var 543 V: Integer; 544 begin 545 V := Clamp(Round(Abs(Value) * 256)); 546 {$IFDEF USEGR32GAMMA} 547 V := GAMMA_ENCODING_TABLE[V]; 548 {$ENDIF} 549 FillLongWord(AlphaValues[0], Count, V); 550 end; 551 552 procedure MakeAlphaEvenOddPF(Value: Single; AlphaValues: PColor32Array; 553 Count: Integer; Color: TColor32); 554 var 555 V: Integer; 556 begin 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); 564 end; 565 566 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 567 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 568 var 569 Renderer: TPolygonRenderer32VPR; 570 begin 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; 580 end; 581 582 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 583 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 584 var 585 Renderer: TPolygonRenderer32VPR; 586 begin 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; 596 end; 597 598 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 599 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation); 600 var 601 Renderer: TPolygonRenderer32VPR; 602 begin 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; 613 end; 614 615 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 616 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation); 617 var 618 Renderer: TPolygonRenderer32VPR; 619 begin 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; 630 end; 631 632 procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 633 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 634 var 635 Renderer: TPolygonRenderer32LCD; 636 begin 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; 646 end; 647 648 procedure PolyPolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 649 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 650 var 651 Renderer: TPolygonRenderer32LCD; 652 begin 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; 662 end; 663 664 procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 665 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 666 var 667 Renderer: TPolygonRenderer32LCD2; 668 begin 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; 678 end; 679 680 procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 681 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 682 var 683 Renderer: TPolygonRenderer32LCD2; 684 begin 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; 694 end; 695 696 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 697 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode; 251 698 Transformation: TTransformation); 252 699 var 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; 702 begin 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; 713 end; 714 715 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 716 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode; 717 Transformation: TTransformation); 718 var 719 Renderer: TPolygonRenderer32VPR; 720 IntersectedClipRect: TRect; 721 begin 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; 732 end; 733 734 procedure PolyPolygonFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 735 ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; 736 Transformation: TTransformation); 737 var 738 Renderer: TPolygonRenderer32VPR; 739 IntersectedClipRect: TRect; 740 begin 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; 752 end; 753 754 procedure PolygonFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 755 ClipRect: TRect; Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; 756 Transformation: TTransformation); 757 var 758 Renderer: TPolygonRenderer32VPR; 759 IntersectedClipRect: TRect; 760 begin 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; 772 end; 773 774 procedure PolygonFS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 775 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode; 776 Transformation: TTransformation); 777 var 778 Renderer: TPolygonRenderer32LCD; 779 IntersectedClipRect: TRect; 780 begin 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; 791 end; 792 793 procedure PolyPolygonFS_LCD(Bitmap: TBitmap32; 794 const Points: TArrayOfArrayOfFloatPoint; ClipRect: TRect; Color: TColor32; 795 FillMode: TPolyFillMode; Transformation: TTransformation); 796 var 797 Renderer: TPolygonRenderer32LCD; 798 IntersectedClipRect: TRect; 799 begin 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; 810 end; 811 812 procedure PolygonFS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 813 ClipRect: TRect; Color: TColor32; FillMode: TPolyFillMode; 814 Transformation: TTransformation); 815 var 816 Renderer: TPolygonRenderer32LCD2; 817 IntersectedClipRect: TRect; 818 begin 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; 829 end; 830 831 procedure PolyPolygonFS_LCD2(Bitmap: TBitmap32; 832 const Points: TArrayOfArrayOfFloatPoint; ClipRect: TRect; Color: TColor32; 833 FillMode: TPolyFillMode; Transformation: TTransformation); 834 var 835 Renderer: TPolygonRenderer32LCD2; 836 IntersectedClipRect: TRect; 837 begin 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; 848 end; 849 850 procedure PolyPolylineFS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFloatPoint; 851 Color: TColor32; Closed: Boolean; StrokeWidth: TFloat; 852 JoinStyle: TJoinStyle; EndStyle: TEndStyle; 853 MiterLimit: TFloat; Transformation: TTransformation); 854 var 855 Dst: TArrayOfArrayOfFloatPoint; 856 begin 857 Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, MiterLimit); 858 PolyPolygonFS(Bitmap, Dst, Color, pfWinding, Transformation); 859 end; 860 861 procedure 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); 865 var 866 Dst: TArrayOfArrayOfFloatPoint; 867 begin 868 Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, MiterLimit); 869 PolyPolygonFS(Bitmap, Dst, Filler, pfWinding, Transformation); 870 end; 871 872 procedure PolylineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 873 Color: TColor32; Closed: Boolean; StrokeWidth: TFloat; 874 JoinStyle: TJoinStyle; EndStyle: TEndStyle; 875 MiterLimit: TFloat; Transformation: TTransformation); 876 begin 877 PolyPolylineFS(Bitmap, PolyPolygon(Points), Color, Closed, StrokeWidth, 878 JoinStyle, EndStyle, MiterLimit, Transformation); 879 end; 880 881 procedure 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); 885 begin 886 PolyPolylineFS(Bitmap, PolyPolygon(Points), Filler, Closed, StrokeWidth, 887 JoinStyle, EndStyle, MiterLimit, Transformation); 888 end; 889 890 procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 891 const Dashes: TArrayOfFloat; Color: TColor32; 892 Closed: Boolean = False; Width: TFloat = 1.0); 893 var 894 MultiPoly: TArrayOfArrayOfFloatPoint; 895 begin 896 MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed); 897 PolyPolylineFS(Bitmap, MultiPoly, Color, False, Width); 898 end; 899 900 procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 901 const Dashes: TArrayOfFloat; FillColor, StrokeColor: TColor32; 902 Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0); 903 var 904 MultiPoly: TArrayOfArrayOfFloatPoint; 905 begin 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); 910 end; 911 912 procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 913 const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller; 914 Closed: Boolean = False; Width: TFloat = 1.0); 915 var 916 MultiPoly: TArrayOfArrayOfFloatPoint; 917 begin 918 MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed); 919 PolyPolylineFS(Bitmap, MultiPoly, Filler, False, Width); 920 end; 921 922 procedure DashLineFS(Bitmap: TBitmap32; const Points: TArrayOfFloatPoint; 923 const Dashes: TArrayOfFloat; Filler: TCustomPolygonFiller; StrokeColor: TColor32; 924 Closed: Boolean; Width: TFloat; StrokeWidth: TFloat = 2.0); 925 var 926 MultiPoly: TArrayOfArrayOfFloatPoint; 927 begin 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); 932 end; 933 934 935 procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 936 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 937 var 938 Renderer: TPolygonRenderer32VPR; 939 begin 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; 950 end; 951 952 procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 953 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 954 var 955 Renderer: TPolygonRenderer32VPR; 956 begin 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; 967 end; 968 969 procedure PolyPolygonXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 970 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation); 971 var 972 Renderer: TPolygonRenderer32VPR; 973 begin 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; 984 end; 985 986 procedure PolygonXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 987 Filler: TCustomPolygonFiller; FillMode: TPolyFillMode; Transformation: TTransformation); 988 var 989 Renderer: TPolygonRenderer32VPR; 990 begin 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; 1001 end; 1002 1003 procedure PolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 1004 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 1005 var 1006 Renderer: TPolygonRenderer32LCD; 1007 begin 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; 1018 end; 1019 1020 procedure PolyPolygonXS_LCD(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 1021 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 1022 var 1023 Renderer: TPolygonRenderer32LCD; 1024 begin 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; 1035 end; 1036 1037 procedure PolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 1038 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 1039 var 1040 Renderer: TPolygonRenderer32LCD2; 1041 begin 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; 1052 end; 1053 1054 procedure PolyPolygonXS_LCD2(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 1055 Color: TColor32; FillMode: TPolyFillMode; Transformation: TTransformation); 1056 var 1057 Renderer: TPolygonRenderer32LCD2; 1058 begin 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; 1069 end; 1070 1071 procedure PolyPolylineXS(Bitmap: TBitmap32; const Points: TArrayOfArrayOfFixedPoint; 1072 Color: TColor32; Closed: Boolean; StrokeWidth: TFixed; 1073 JoinStyle: TJoinStyle; EndStyle: TEndStyle; 1074 MiterLimit: TFixed; Transformation: TTransformation); 1075 var 1076 Dst: TArrayOfArrayOfFixedPoint; 1077 begin 1078 Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, 1079 MiterLimit); 1080 PolyPolygonXS(Bitmap, Dst, Color, pfWinding, Transformation); 1081 end; 1082 1083 procedure 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); 1088 var 1089 Dst: TArrayOfArrayOfFixedPoint; 1090 begin 1091 Dst := BuildPolyPolyLine(Points, Closed, StrokeWidth, JoinStyle, EndStyle, 1092 MiterLimit); 1093 PolyPolygonXS(Bitmap, Dst, Filler, pfWinding, Transformation); 1094 end; 1095 1096 procedure PolylineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 1097 Color: TColor32; Closed: Boolean; StrokeWidth: TFixed; 1098 JoinStyle: TJoinStyle; EndStyle: TEndStyle; 1099 MiterLimit: TFixed; Transformation: TTransformation); 1100 begin 1101 PolyPolylineXS(Bitmap, PolyPolygon(Points), Color, 1102 Closed, StrokeWidth, JoinStyle, EndStyle, 1103 MiterLimit, Transformation); 1104 end; 1105 1106 procedure 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); 1111 begin 1112 PolyPolylineXS(Bitmap, PolyPolygon(Points), Filler, Closed, StrokeWidth, 1113 JoinStyle, EndStyle, MiterLimit, Transformation); 1114 end; 1115 1116 procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 1117 const Dashes: TArrayOfFixed; Color: TColor32; 1118 Closed: Boolean = False; Width: TFixed = $10000); 1119 var 1120 MultiPoly: TArrayOfArrayOfFixedPoint; 1121 begin 1122 MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed); 1123 PolyPolylineXS(Bitmap, MultiPoly, Color, False, Width); 1124 end; 1125 1126 procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 1127 const Dashes: TArrayOfFixed; FillColor, StrokeColor: TColor32; 1128 Closed: Boolean; Width: TFixed; StrokeWidth: TFixed = $20000); 1129 var 1130 MultiPoly: TArrayOfArrayOfFixedPoint; 1131 begin 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); 1136 end; 1137 1138 procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 1139 const Dashes: TArrayOfFixed; Filler: TCustomPolygonFiller; 1140 Closed: Boolean = False; Width: TFixed = $10000); 1141 var 1142 MultiPoly: TArrayOfArrayOfFixedPoint; 1143 begin 1144 MultiPoly := GR32_VectorUtils.BuildDashedLine(Points, Dashes, 0, Closed); 1145 PolyPolylineXS(Bitmap, MultiPoly, Filler, False, Width); 1146 end; 1147 1148 procedure DashLineXS(Bitmap: TBitmap32; const Points: TArrayOfFixedPoint; 1149 const Dashes: TArrayOfFixed; Filler: TCustomPolygonFiller; StrokeColor: TColor32; 1150 Closed: Boolean; Width: TFixed; StrokeWidth: TFixed = $20000); 1151 var 1152 MultiPoly: TArrayOfArrayOfFixedPoint; 1153 begin 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); 1158 end; 1159 1160 procedure FillBitmap(Bitmap: TBitmap32; Filler: TCustomPolygonFiller); 1161 var 1162 AlphaValues: PColor32; 1163 Y: Integer; 1164 begin 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} 1181 end; 1182 1183 1184 { LCD sub-pixel rendering (see http://www.grc.com/cttech.htm) } 1185 1186 type 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 1198 procedure MakeAlphaNonZeroLCD(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray; 1199 Count: Integer; Color: TColor32); 1200 var 1201 I: Integer; 1202 M, V: Cardinal; 1203 Last: TFloat; 1204 C: TColor32Entry absolute Color; 1205 begin 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; 1230 end; 1231 1232 procedure MakeAlphaEvenOddLCD(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray; 1233 Count: Integer; Color: TColor32); 1234 var 1235 I: Integer; 1236 M, V: Cardinal; 1237 Last: TFloat; 1238 begin 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; 1264 end; 1265 1266 procedure MakeAlphaNonZeroLCD2(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray; 1267 Count: Integer; Color: TColor32); 1268 var 1269 I: Integer; 1270 begin 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; 1280 end; 1281 1282 procedure MakeAlphaEvenOddLCD2(Coverage: PSingleArray; AlphaValues: SysUtils.PByteArray; 1283 Count: Integer; Color: TColor32); 1284 var 1285 I: Integer; 1286 begin 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; 1296 end; 1297 1298 procedure CombineLineLCD(Weights: PRGBTripleArray; Dst: PColor32Array; Color: TColor32; Count: Integer); 1299 var 1300 I: Integer; 1301 {$IFDEF TEST_BLENDMEMRGB128SSE4} 1302 Weights64: UInt64; 1303 {$ENDIF} 1304 begin 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} 262 1319 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 515 1324 begin 516 JPtr^ := T;517 JPtr := Temp;1325 Dst[I] := Color; 1326 Dst[I + 1] := Color; 518 1327 end 519 1328 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); 1070 1332 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}; 1328 1334 EMMS; 1329 1335 end; 1330 1336 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 1339 procedure TCustomPolygonFiller.BeginRendering; 1340 begin 1341 // implemented by descendants 1342 end; 1343 1344 procedure TCustomPolygonFiller.EndRendering; 1345 begin 1346 // implemented by descendants 1347 end; 1348 1349 { TCallbackPolygonFiller } 1350 1351 function TCallbackPolygonFiller.GetFillLine: TFillLineEvent; 1352 begin 1353 Result := FFillLineEvent; 1354 end; 1355 1356 1357 { TInvertPolygonFiller } 1358 1359 procedure TInvertPolygonFiller.FillLineBlend(Dst: PColor32; DstX, DstY, 1360 Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode); 1361 var 1362 X: Integer; 1363 BlendMemEx: TBlendMemEx; 1364 begin 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; 1373 end; 1374 1375 function TInvertPolygonFiller.GetFillLine: TFillLineEvent; 1376 begin 1377 Result := FillLineBlend; 1378 end; 1379 1380 1381 { TClearPolygonFiller } 1382 1383 constructor TClearPolygonFiller.Create(Color: TColor32 = $00808080); 1384 begin 1385 inherited Create; 1386 FColor := Color; 1387 end; 1388 1389 procedure TClearPolygonFiller.FillLineClear(Dst: PColor32; DstX, DstY, 1390 Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode); 1391 begin 1392 FillLongword(Dst^, Length, FColor); 1393 end; 1394 1395 function TClearPolygonFiller.GetFillLine: TFillLineEvent; 1396 begin 1397 Result := FillLineClear; 1398 end; 1399 2178 1400 2179 1401 { TBitmapPolygonFiller } 2180 1402 2181 1403 procedure TBitmapPolygonFiller.FillLineOpaque(Dst: PColor32; DstX, DstY, 2182 Length: Integer; AlphaValues: PColor32 );1404 Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode); 2183 1405 var 2184 1406 PatternX, PatternY, X: Integer; … … 2223 1445 end; 2224 1446 2225 procedure TBitmapPolygonFiller.FillLineBlend(Dst: PColor32; DstX, DstY, Length: Integer; AlphaValues: PColor32); 1447 procedure TBitmapPolygonFiller.FillLineBlend(Dst: PColor32; DstX, DstY, 1448 Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode); 2226 1449 var 2227 1450 PatternX, PatternY, X: Integer; … … 2268 1491 end; 2269 1492 2270 procedure TBitmapPolygonFiller.FillLineBlendMasterAlpha(Dst: PColor32; DstX, DstY, 2271 Length: Integer; AlphaValues: PColor32); 1493 procedure TBitmapPolygonFiller.FillLineBlendMasterAlpha(Dst: PColor32; 1494 DstX, DstY, Length: Integer; AlphaValues: PColor32; 1495 CombineMode: TCombineMode); 2272 1496 var 2273 1497 PatternX, PatternY, X: Integer; … … 2309 1533 end; 2310 1534 2311 procedure TBitmapPolygonFiller.FillLineCustomCombine(Dst: PColor32; DstX, DstY, 2312 Length: Integer; AlphaValues: PColor32); 1535 procedure TBitmapPolygonFiller.FillLineCustomCombine(Dst: PColor32; 1536 DstX, DstY, Length: Integer; AlphaValues: PColor32; 1537 CombineMode: TCombineMode); 2313 1538 var 2314 1539 PatternX, PatternY, X: Integer; … … 2372 1597 { TSamplerFiller } 2373 1598 1599 constructor TSamplerFiller.Create(Sampler: TCustomSampler = nil); 1600 begin 1601 inherited Create; 1602 FSampler := Sampler; 1603 SamplerChanged; 1604 end; 1605 1606 procedure TSamplerFiller.EndRendering; 1607 begin 1608 if Assigned(FSampler) then 1609 FSampler.FinalizeSampling 1610 else 1611 raise Exception.Create(RCStrNoSamplerSpecified); 1612 end; 1613 2374 1614 procedure TSamplerFiller.SampleLineOpaque(Dst: PColor32; DstX, DstY, 2375 Length: Integer; AlphaValues: PColor32 );1615 Length: Integer; AlphaValues: PColor32; CombineMode: TCombineMode); 2376 1616 var 2377 1617 X: Integer; 2378 1618 BlendMemEx: TBlendMemEx; 2379 1619 begin 2380 BlendMemEx := BLEND_MEM_EX[ cmBlend]^;1620 BlendMemEx := BLEND_MEM_EX[CombineMode]^; 2381 1621 for X := DstX to DstX + Length - 1 do 2382 1622 begin … … 2388 1628 end; 2389 1629 1630 procedure TSamplerFiller.SamplerChanged; 1631 begin 1632 if Assigned(FSampler) then 1633 FGetSample := FSampler.GetSampleInt; 1634 end; 1635 1636 procedure TSamplerFiller.BeginRendering; 1637 begin 1638 if Assigned(FSampler) then 1639 FSampler.PrepareSampling 1640 else 1641 raise Exception.Create(RCStrNoSamplerSpecified); 1642 end; 1643 2390 1644 function TSamplerFiller.GetFillLine: TFillLineEvent; 2391 1645 begin … … 2395 1649 procedure TSamplerFiller.SetSampler(const Value: TCustomSampler); 2396 1650 begin 2397 FSampler := Value; 2398 FGetSample := FSampler.GetSampleInt; 2399 end; 1651 if FSampler <> Value then 1652 begin 1653 FSampler := Value; 1654 SamplerChanged; 1655 end; 1656 end; 1657 1658 1659 { TCustomPolygonRenderer } 1660 1661 procedure TCustomPolygonRenderer.PolygonFS( 1662 const Points: TArrayOfFloatPoint; const ClipRect: TFloatRect; 1663 Transformation: TTransformation); 1664 begin 1665 PolyPolygonFS(PolyPolygon(Points), ClipRect, Transformation); 1666 end; 1667 1668 procedure TCustomPolygonRenderer.PolygonFS( 1669 const Points: TArrayOfFloatPoint; const ClipRect: TFloatRect); 1670 begin 1671 PolyPolygonFS(PolyPolygon(Points), ClipRect); 1672 end; 1673 1674 procedure TCustomPolygonRenderer.PolyPolygonFS( 1675 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect); 1676 begin 1677 // implemented by descendants 1678 end; 1679 1680 procedure TCustomPolygonRenderer.PolyPolygonFS( 1681 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect; 1682 Transformation: TTransformation); 1683 var 1684 APoints: TArrayOfArrayOfFloatPoint; 1685 begin 1686 if Assigned(Transformation) then 1687 APoints := TransformPolyPolygon(Points, Transformation) 1688 else 1689 APoints := Points; 1690 PolyPolygonFS(APoints, ClipRect); 1691 end; 1692 1693 { TPolygonRenderer32 } 1694 1695 constructor TPolygonRenderer32.Create(Bitmap: TBitmap32; 1696 Fillmode: TPolyFillMode); 1697 begin 1698 inherited Create; 1699 FBitmap := Bitmap; 1700 FFillMode := Fillmode; 1701 end; 1702 1703 procedure TPolygonRenderer32.PolygonFS(const Points: TArrayOfFloatPoint); 1704 begin 1705 PolyPolygonFS(PolyPolygon(Points), FloatRect(FBitmap.ClipRect)); 1706 end; 1707 1708 procedure TPolygonRenderer32.PolyPolygonFS(const Points: TArrayOfArrayOfFloatPoint); 1709 begin 1710 PolyPolygonFS(Points, FloatRect(FBitmap.ClipRect)); 1711 end; 1712 1713 procedure TPolygonRenderer32.SetBitmap(const Value: TBitmap32); 1714 begin 1715 if FBitmap <> Value then 1716 begin 1717 FBitmap := Value; 1718 Changed; 1719 end; 1720 end; 1721 1722 procedure TPolygonRenderer32.SetColor(const Value: TColor32); 1723 begin 1724 if FColor <> Value then 1725 begin 1726 FColor := Value; 1727 Changed; 1728 end; 1729 end; 1730 1731 procedure TPolygonRenderer32.SetFiller(const Value: TCustomPolygonFiller); 1732 begin 1733 if FFiller <> Value then 1734 begin 1735 FFiller := Value; 1736 Changed; 1737 end; 1738 end; 1739 1740 procedure TPolygonRenderer32.SetFillMode(const Value: TPolyFillMode); 1741 begin 1742 if FFillMode <> Value then 1743 begin 1744 FFillMode := Value; 1745 Changed; 1746 end; 1747 end; 1748 1749 { TPolygonRenderer32VPR } 1750 1751 {$IFDEF USESTACKALLOC} 1752 {$W+} 1753 {$ENDIF} 1754 procedure TPolygonRenderer32VPR.FillSpan(const Span: TValueSpan; DstY: Integer); 1755 var 1756 AlphaValues: PColor32Array; 1757 Count: Integer; 1758 begin 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} 1774 end; 1775 {$IFDEF USESTACKALLOC} 1776 {$W-} 1777 {$ENDIF} 1778 1779 function TPolygonRenderer32VPR.GetRenderSpan: TRenderSpanEvent; 1780 begin 1781 if Assigned(FFiller) then 1782 Result := FillSpan 1783 else 1784 Result := RenderSpan; 1785 end; 1786 1787 procedure TPolygonRenderer32VPR.PolyPolygonFS( 1788 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect); 1789 {$IFDEF CHANGENOTIFICATIONS} 1790 var 1791 I: Integer; 1792 {$ENDIF} 1793 begin 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} 1810 end; 1811 1812 {$W+} 1813 procedure TPolygonRenderer32VPR.RenderSpan(const Span: TValueSpan; 1814 DstY: Integer); 1815 var 1816 AlphaValues: PColor32Array; 1817 Count: Integer; 1818 begin 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} 1836 end; 1837 {$W-} 1838 1839 procedure TPolygonRenderer32VPR.UpdateFillProcs; 1840 const 1841 FillProcs: array [Boolean, TPolyFillMode] of TFillProc = ( 1842 (MakeAlphaEvenOddUP, MakeAlphaNonZeroUP), 1843 (MakeAlphaEvenOddUPF, MakeAlphaNonZeroUPF) 1844 ); 1845 begin 1846 FFillProc := FillProcs[Assigned(FFiller), FillMode]; 1847 end; 1848 1849 { TPolygonRenderer32LCD } 1850 1851 procedure TPolygonRenderer32LCD.PolyPolygonFS( 1852 const Points: TArrayOfArrayOfFloatPoint; const ClipRect: TFloatRect); 1853 var 1854 R: TFloatRect; 1855 APoints: TArrayOfArrayOfFloatPoint; 1856 {$IFDEF CHANGENOTIFICATIONS} 1857 I: Integer; 1858 {$ENDIF} 1859 begin 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} 1872 end; 1873 1874 {$W+} 1875 procedure TPolygonRenderer32LCD.RenderSpan(const Span: TValueSpan; 1876 DstY: Integer); 1877 const 1878 PADDING = 5; 1879 var 1880 AlphaValues: SysUtils.PByteArray; 1881 Count: Integer; 1882 X1, Offset: Integer; 1883 const 1884 MakeAlpha: array [TPolyFillMode] of TMakeAlphaProcLCD = (MakeAlphaEvenOddLCD, MakeAlphaNonZeroLCD); 1885 begin 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} 1914 end; 1915 {$W-} 1916 1917 1918 { TPolygonRenderer32LCD2 } 1919 1920 {$W+} 1921 procedure TPolygonRenderer32LCD2.RenderSpan(const Span: TValueSpan; 1922 DstY: Integer); 1923 const 1924 PADDING = 5; 1925 var 1926 AlphaValues: SysUtils.PByteArray; 1927 Count: Integer; 1928 X1, Offset: Integer; 1929 const 1930 MakeAlpha: array [TPolyFillMode] of TMakeAlphaProcLCD = (MakeAlphaEvenOddLCD2, MakeAlphaNonZeroLCD2); 1931 begin 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} 1962 end; 1963 {$W-} 1964 1965 initialization 1966 RegisterPolygonRenderer(TPolygonRenderer32VPR); 1967 RegisterPolygonRenderer(TPolygonRenderer32LCD); 1968 RegisterPolygonRenderer(TPolygonRenderer32LCD2); 1969 1970 finalization 1971 PolygonRendererList.Free; 2400 1972 2401 1973 end.
Note:
See TracChangeset
for help on using the changeset viewer.